• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.security.keystore2;
18 
19 import android.security.keymaster.KeymasterArguments;
20 import android.security.keymaster.KeymasterDefs;
21 import android.security.keystore.KeyProperties;
22 
23 import java.security.ProviderException;
24 
25 /**
26  * @hide
27  */
28 public abstract class KeymasterUtils {
29 
KeymasterUtils()30     private KeymasterUtils() {}
31 
32     /** @hide */
getDigestOutputSizeBits(int keymasterDigest)33     static int getDigestOutputSizeBits(int keymasterDigest) {
34         switch (keymasterDigest) {
35             case KeymasterDefs.KM_DIGEST_NONE:
36                 return -1;
37             case KeymasterDefs.KM_DIGEST_MD5:
38                 return 128;
39             case KeymasterDefs.KM_DIGEST_SHA1:
40                 return 160;
41             case KeymasterDefs.KM_DIGEST_SHA_2_224:
42                 return 224;
43             case KeymasterDefs.KM_DIGEST_SHA_2_256:
44                 return 256;
45             case KeymasterDefs.KM_DIGEST_SHA_2_384:
46                 return 384;
47             case KeymasterDefs.KM_DIGEST_SHA_2_512:
48                 return 512;
49             default:
50                 throw new IllegalArgumentException("Unknown digest: " + keymasterDigest);
51         }
52     }
53 
54     /** @hide */
isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto( int keymasterBlockMode)55     static boolean isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(
56             int keymasterBlockMode) {
57         switch (keymasterBlockMode) {
58             case KeymasterDefs.KM_MODE_ECB:
59                 return false;
60             case KeymasterDefs.KM_MODE_CBC:
61             case KeymasterDefs.KM_MODE_CTR:
62             case KeymasterDefs.KM_MODE_GCM:
63                 return true;
64             default:
65                 throw new IllegalArgumentException("Unsupported block mode: " + keymasterBlockMode);
66         }
67     }
68 
69     /** @hide */
isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto( int keymasterPadding)70     static boolean isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(
71             int keymasterPadding) {
72         switch (keymasterPadding) {
73             case KeymasterDefs.KM_PAD_NONE:
74                 return false;
75             case KeymasterDefs.KM_PAD_RSA_OAEP:
76             case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
77                 return true;
78             default:
79                 throw new IllegalArgumentException(
80                         "Unsupported asymmetric encryption padding scheme: " + keymasterPadding);
81         }
82     }
83 
84     /**
85      * Adds {@code KM_TAG_MIN_MAC_LENGTH} tag, if necessary, to the keymaster arguments for
86      * generating or importing a key. This tag may only be needed for symmetric keys (e.g., HMAC,
87      * AES-GCM).
88      */
addMinMacLengthAuthorizationIfNecessary(KeymasterArguments args, int keymasterAlgorithm, int[] keymasterBlockModes, int[] keymasterDigests)89     public static void addMinMacLengthAuthorizationIfNecessary(KeymasterArguments args,
90             int keymasterAlgorithm,
91             int[] keymasterBlockModes,
92             int[] keymasterDigests) {
93         switch (keymasterAlgorithm) {
94             case KeymasterDefs.KM_ALGORITHM_AES:
95                 if (com.android.internal.util.ArrayUtils.contains(
96                         keymasterBlockModes, KeymasterDefs.KM_MODE_GCM)) {
97                     // AES GCM key needs the minimum length of AEAD tag specified.
98                     args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH,
99                             AndroidKeyStoreAuthenticatedAESCipherSpi.GCM
100                                     .MIN_SUPPORTED_TAG_LENGTH_BITS);
101                 }
102                 break;
103             case KeymasterDefs.KM_ALGORITHM_HMAC:
104                 // HMAC key needs the minimum length of MAC set to the output size of the associated
105                 // digest. This is because we do not offer a way to generate shorter MACs and
106                 // don't offer a way to verify MACs (other than by generating them).
107                 if (keymasterDigests.length != 1) {
108                     throw new ProviderException(
109                             "Unsupported number of authorized digests for HMAC key: "
110                                     + keymasterDigests.length
111                                     + ". Exactly one digest must be authorized");
112                 }
113                 int keymasterDigest = keymasterDigests[0];
114                 int digestOutputSizeBits = getDigestOutputSizeBits(keymasterDigest);
115                 if (digestOutputSizeBits == -1) {
116                     throw new ProviderException(
117                             "HMAC key authorized for unsupported digest: "
118                                     + KeyProperties.Digest.fromKeymaster(keymasterDigest));
119                 }
120                 args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH, digestOutputSizeBits);
121                 break;
122         }
123     }
124 }
125