• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.keystore;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.StringDef;
23 import android.security.keymaster.KeymasterDefs;
24 
25 import libcore.util.EmptyArray;
26 
27 import java.lang.annotation.Retention;
28 import java.lang.annotation.RetentionPolicy;
29 import java.util.Collection;
30 import java.util.Locale;
31 
32 /**
33  * Properties of <a href="{@docRoot}training/articles/keystore.html">Android Keystore</a> keys.
34  */
35 public abstract class KeyProperties {
KeyProperties()36     private KeyProperties() {}
37 
38     /**
39      * @hide
40      */
41     @Retention(RetentionPolicy.SOURCE)
42     @IntDef(flag = true, prefix = { "PURPOSE_" }, value = {
43             PURPOSE_ENCRYPT,
44             PURPOSE_DECRYPT,
45             PURPOSE_SIGN,
46             PURPOSE_VERIFY,
47             PURPOSE_WRAP_KEY,
48     })
49     public @interface PurposeEnum {}
50 
51     /**
52      * Purpose of key: encryption.
53      */
54     public static final int PURPOSE_ENCRYPT = 1 << 0;
55 
56     /**
57      * Purpose of key: decryption.
58      */
59     public static final int PURPOSE_DECRYPT = 1 << 1;
60 
61     /**
62      * Purpose of key: signing or generating a Message Authentication Code (MAC).
63      */
64     public static final int PURPOSE_SIGN = 1 << 2;
65 
66     /**
67      * Purpose of key: signature or Message Authentication Code (MAC) verification.
68      */
69     public static final int PURPOSE_VERIFY = 1 << 3;
70 
71     /**
72      * Purpose of key: wrapping and unwrapping wrapped keys for secure import.
73      */
74     public static final int PURPOSE_WRAP_KEY = 1 << 5;
75 
76     /**
77      * @hide
78      */
79     public static abstract class Purpose {
Purpose()80         private Purpose() {}
81 
toKeymaster(@urposeEnum int purpose)82         public static int toKeymaster(@PurposeEnum int purpose) {
83             switch (purpose) {
84                 case PURPOSE_ENCRYPT:
85                     return KeymasterDefs.KM_PURPOSE_ENCRYPT;
86                 case PURPOSE_DECRYPT:
87                     return KeymasterDefs.KM_PURPOSE_DECRYPT;
88                 case PURPOSE_SIGN:
89                     return KeymasterDefs.KM_PURPOSE_SIGN;
90                 case PURPOSE_VERIFY:
91                     return KeymasterDefs.KM_PURPOSE_VERIFY;
92                 case PURPOSE_WRAP_KEY:
93                     return KeymasterDefs.KM_PURPOSE_WRAP;
94                 default:
95                     throw new IllegalArgumentException("Unknown purpose: " + purpose);
96             }
97         }
98 
fromKeymaster(int purpose)99         public static @PurposeEnum int fromKeymaster(int purpose) {
100             switch (purpose) {
101                 case KeymasterDefs.KM_PURPOSE_ENCRYPT:
102                     return PURPOSE_ENCRYPT;
103                 case KeymasterDefs.KM_PURPOSE_DECRYPT:
104                     return PURPOSE_DECRYPT;
105                 case KeymasterDefs.KM_PURPOSE_SIGN:
106                     return PURPOSE_SIGN;
107                 case KeymasterDefs.KM_PURPOSE_VERIFY:
108                     return PURPOSE_VERIFY;
109                 case KeymasterDefs.KM_PURPOSE_WRAP:
110                     return PURPOSE_WRAP_KEY;
111                 default:
112                     throw new IllegalArgumentException("Unknown purpose: " + purpose);
113             }
114         }
115 
116         @NonNull
allToKeymaster(@urposeEnum int purposes)117         public static int[] allToKeymaster(@PurposeEnum int purposes) {
118             int[] result = getSetFlags(purposes);
119             for (int i = 0; i < result.length; i++) {
120                 result[i] = toKeymaster(result[i]);
121             }
122             return result;
123         }
124 
allFromKeymaster(@onNull Collection<Integer> purposes)125         public static @PurposeEnum int allFromKeymaster(@NonNull Collection<Integer> purposes) {
126             @PurposeEnum int result = 0;
127             for (int keymasterPurpose : purposes) {
128                 result |= fromKeymaster(keymasterPurpose);
129             }
130             return result;
131         }
132     }
133 
134     /**
135      * @hide
136      */
137     @Retention(RetentionPolicy.SOURCE)
138     @StringDef(prefix = { "KEY_" }, value = {
139         KEY_ALGORITHM_RSA,
140         KEY_ALGORITHM_EC,
141         KEY_ALGORITHM_AES,
142         KEY_ALGORITHM_HMAC_SHA1,
143         KEY_ALGORITHM_HMAC_SHA224,
144         KEY_ALGORITHM_HMAC_SHA256,
145         KEY_ALGORITHM_HMAC_SHA384,
146         KEY_ALGORITHM_HMAC_SHA512,
147         })
148     public @interface KeyAlgorithmEnum {}
149 
150     /** Rivest Shamir Adleman (RSA) key. */
151     public static final String KEY_ALGORITHM_RSA = "RSA";
152 
153     /** Elliptic Curve (EC) Cryptography key. */
154     public static final String KEY_ALGORITHM_EC = "EC";
155 
156     /** Advanced Encryption Standard (AES) key. */
157     public static final String KEY_ALGORITHM_AES = "AES";
158 
159     /**
160      * Triple Data Encryption Algorithm (3DES) key.
161      *
162      * @deprecated Included for interoperability with legacy systems. Prefer {@link
163      * KeyProperties#KEY_ALGORITHM_AES} for new development.
164      */
165     @Deprecated
166     public static final String KEY_ALGORITHM_3DES = "DESede";
167 
168     /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-1 as the hash. */
169     public static final String KEY_ALGORITHM_HMAC_SHA1 = "HmacSHA1";
170 
171     /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-224 as the hash. */
172     public static final String KEY_ALGORITHM_HMAC_SHA224 = "HmacSHA224";
173 
174     /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-256 as the hash. */
175     public static final String KEY_ALGORITHM_HMAC_SHA256 = "HmacSHA256";
176 
177     /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-384 as the hash. */
178     public static final String KEY_ALGORITHM_HMAC_SHA384 = "HmacSHA384";
179 
180     /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-512 as the hash. */
181     public static final String KEY_ALGORITHM_HMAC_SHA512 = "HmacSHA512";
182 
183     /**
184      * @hide
185      */
186     public static abstract class KeyAlgorithm {
KeyAlgorithm()187         private KeyAlgorithm() {}
188 
toKeymasterAsymmetricKeyAlgorithm( @onNull @eyAlgorithmEnum String algorithm)189         public static int toKeymasterAsymmetricKeyAlgorithm(
190                 @NonNull @KeyAlgorithmEnum String algorithm) {
191             if (KEY_ALGORITHM_EC.equalsIgnoreCase(algorithm)) {
192                 return KeymasterDefs.KM_ALGORITHM_EC;
193             } else if (KEY_ALGORITHM_RSA.equalsIgnoreCase(algorithm)) {
194                 return KeymasterDefs.KM_ALGORITHM_RSA;
195             } else {
196                 throw new IllegalArgumentException("Unsupported key algorithm: " + algorithm);
197             }
198         }
199 
200         @NonNull
fromKeymasterAsymmetricKeyAlgorithm( int keymasterAlgorithm)201         public static @KeyAlgorithmEnum String fromKeymasterAsymmetricKeyAlgorithm(
202                 int keymasterAlgorithm) {
203             switch (keymasterAlgorithm) {
204                 case KeymasterDefs.KM_ALGORITHM_EC:
205                     return KEY_ALGORITHM_EC;
206                 case KeymasterDefs.KM_ALGORITHM_RSA:
207                     return KEY_ALGORITHM_RSA;
208                 default:
209                     throw new IllegalArgumentException(
210                             "Unsupported key algorithm: " + keymasterAlgorithm);
211             }
212         }
213 
toKeymasterSecretKeyAlgorithm( @onNull @eyAlgorithmEnum String algorithm)214         public static int toKeymasterSecretKeyAlgorithm(
215                 @NonNull @KeyAlgorithmEnum String algorithm) {
216             if (KEY_ALGORITHM_AES.equalsIgnoreCase(algorithm)) {
217                 return KeymasterDefs.KM_ALGORITHM_AES;
218             } else if (KEY_ALGORITHM_3DES.equalsIgnoreCase(algorithm)) {
219                 return KeymasterDefs.KM_ALGORITHM_3DES;
220             } else if (algorithm.toUpperCase(Locale.US).startsWith("HMAC")) {
221                 return KeymasterDefs.KM_ALGORITHM_HMAC;
222             } else {
223                 throw new IllegalArgumentException(
224                         "Unsupported secret key algorithm: " + algorithm);
225             }
226         }
227 
228         @NonNull
fromKeymasterSecretKeyAlgorithm( int keymasterAlgorithm, int keymasterDigest)229         public static @KeyAlgorithmEnum String fromKeymasterSecretKeyAlgorithm(
230                 int keymasterAlgorithm, int keymasterDigest) {
231             switch (keymasterAlgorithm) {
232                 case KeymasterDefs.KM_ALGORITHM_AES:
233                     return KEY_ALGORITHM_AES;
234                 case KeymasterDefs.KM_ALGORITHM_3DES:
235                     return KEY_ALGORITHM_3DES;
236                 case KeymasterDefs.KM_ALGORITHM_HMAC:
237                     switch (keymasterDigest) {
238                         case KeymasterDefs.KM_DIGEST_SHA1:
239                             return KEY_ALGORITHM_HMAC_SHA1;
240                         case KeymasterDefs.KM_DIGEST_SHA_2_224:
241                             return KEY_ALGORITHM_HMAC_SHA224;
242                         case KeymasterDefs.KM_DIGEST_SHA_2_256:
243                             return KEY_ALGORITHM_HMAC_SHA256;
244                         case KeymasterDefs.KM_DIGEST_SHA_2_384:
245                             return KEY_ALGORITHM_HMAC_SHA384;
246                         case KeymasterDefs.KM_DIGEST_SHA_2_512:
247                             return KEY_ALGORITHM_HMAC_SHA512;
248                         default:
249                             throw new IllegalArgumentException("Unsupported HMAC digest: "
250                                     + Digest.fromKeymaster(keymasterDigest));
251                     }
252                 default:
253                     throw new IllegalArgumentException(
254                             "Unsupported key algorithm: " + keymasterAlgorithm);
255             }
256         }
257 
258         /**
259          * @hide
260          *
261          * @return keymaster digest or {@code -1} if the algorithm does not involve a digest.
262          */
toKeymasterDigest(@onNull @eyAlgorithmEnum String algorithm)263         public static int toKeymasterDigest(@NonNull @KeyAlgorithmEnum String algorithm) {
264             String algorithmUpper = algorithm.toUpperCase(Locale.US);
265             if (algorithmUpper.startsWith("HMAC")) {
266                 String digestUpper = algorithmUpper.substring("HMAC".length());
267                 switch (digestUpper) {
268                     case "SHA1":
269                         return KeymasterDefs.KM_DIGEST_SHA1;
270                     case "SHA224":
271                         return KeymasterDefs.KM_DIGEST_SHA_2_224;
272                     case "SHA256":
273                         return KeymasterDefs.KM_DIGEST_SHA_2_256;
274                     case "SHA384":
275                         return KeymasterDefs.KM_DIGEST_SHA_2_384;
276                     case "SHA512":
277                         return KeymasterDefs.KM_DIGEST_SHA_2_512;
278                     default:
279                         throw new IllegalArgumentException(
280                                 "Unsupported HMAC digest: " + digestUpper);
281                 }
282             } else {
283                 return -1;
284             }
285         }
286     }
287 
288     /**
289      * @hide
290      */
291     @Retention(RetentionPolicy.SOURCE)
292     @StringDef(prefix = { "BLOCK_MODE_" }, value = {
293         BLOCK_MODE_ECB,
294         BLOCK_MODE_CBC,
295         BLOCK_MODE_CTR,
296         BLOCK_MODE_GCM,
297         })
298     public @interface BlockModeEnum {}
299 
300     /** Electronic Codebook (ECB) block mode. */
301     public static final String BLOCK_MODE_ECB = "ECB";
302 
303     /** Cipher Block Chaining (CBC) block mode. */
304     public static final String BLOCK_MODE_CBC = "CBC";
305 
306     /** Counter (CTR) block mode. */
307     public static final String BLOCK_MODE_CTR = "CTR";
308 
309     /** Galois/Counter Mode (GCM) block mode. */
310     public static final String BLOCK_MODE_GCM = "GCM";
311 
312     /**
313      * @hide
314      */
315     public static abstract class BlockMode {
BlockMode()316         private BlockMode() {}
317 
toKeymaster(@onNull @lockModeEnum String blockMode)318         public static int toKeymaster(@NonNull @BlockModeEnum String blockMode) {
319             if (BLOCK_MODE_ECB.equalsIgnoreCase(blockMode)) {
320                 return KeymasterDefs.KM_MODE_ECB;
321             } else if (BLOCK_MODE_CBC.equalsIgnoreCase(blockMode)) {
322                 return KeymasterDefs.KM_MODE_CBC;
323             } else if (BLOCK_MODE_CTR.equalsIgnoreCase(blockMode)) {
324                 return KeymasterDefs.KM_MODE_CTR;
325             } else if (BLOCK_MODE_GCM.equalsIgnoreCase(blockMode)) {
326                 return KeymasterDefs.KM_MODE_GCM;
327             } else {
328                 throw new IllegalArgumentException("Unsupported block mode: " + blockMode);
329             }
330         }
331 
332         @NonNull
fromKeymaster(int blockMode)333         public static @BlockModeEnum String fromKeymaster(int blockMode) {
334             switch (blockMode) {
335                 case KeymasterDefs.KM_MODE_ECB:
336                     return BLOCK_MODE_ECB;
337                 case KeymasterDefs.KM_MODE_CBC:
338                     return BLOCK_MODE_CBC;
339                 case KeymasterDefs.KM_MODE_CTR:
340                     return BLOCK_MODE_CTR;
341                 case KeymasterDefs.KM_MODE_GCM:
342                     return BLOCK_MODE_GCM;
343                 default:
344                     throw new IllegalArgumentException("Unsupported block mode: " + blockMode);
345             }
346         }
347 
348         @NonNull
allFromKeymaster( @onNull Collection<Integer> blockModes)349         public static @BlockModeEnum String[] allFromKeymaster(
350                 @NonNull Collection<Integer> blockModes) {
351             if ((blockModes == null) || (blockModes.isEmpty())) {
352                 return EmptyArray.STRING;
353             }
354             @BlockModeEnum String[] result = new String[blockModes.size()];
355             int offset = 0;
356             for (int blockMode : blockModes) {
357                 result[offset] = fromKeymaster(blockMode);
358                 offset++;
359             }
360             return result;
361         }
362 
allToKeymaster(@ullable @lockModeEnum String[] blockModes)363         public static int[] allToKeymaster(@Nullable @BlockModeEnum String[] blockModes) {
364             if ((blockModes == null) || (blockModes.length == 0)) {
365                 return EmptyArray.INT;
366             }
367             int[] result = new int[blockModes.length];
368             for (int i = 0; i < blockModes.length; i++) {
369                 result[i] = toKeymaster(blockModes[i]);
370             }
371             return result;
372         }
373     }
374 
375     /**
376      * @hide
377      */
378     @Retention(RetentionPolicy.SOURCE)
379     @StringDef(prefix = { "ENCRYPTION_PADDING_" }, value = {
380         ENCRYPTION_PADDING_NONE,
381         ENCRYPTION_PADDING_PKCS7,
382         ENCRYPTION_PADDING_RSA_PKCS1,
383         ENCRYPTION_PADDING_RSA_OAEP,
384         })
385     public @interface EncryptionPaddingEnum {}
386 
387     /**
388      * No encryption padding.
389      */
390     public static final String ENCRYPTION_PADDING_NONE = "NoPadding";
391 
392     /**
393      * PKCS#7 encryption padding scheme.
394      */
395     public static final String ENCRYPTION_PADDING_PKCS7 = "PKCS7Padding";
396 
397     /**
398      * RSA PKCS#1 v1.5 padding scheme for encryption.
399      */
400     public static final String ENCRYPTION_PADDING_RSA_PKCS1 = "PKCS1Padding";
401 
402     /**
403      * RSA Optimal Asymmetric Encryption Padding (OAEP) scheme.
404      */
405     public static final String ENCRYPTION_PADDING_RSA_OAEP = "OAEPPadding";
406 
407     /**
408      * @hide
409      */
410     public static abstract class EncryptionPadding {
EncryptionPadding()411         private EncryptionPadding() {}
412 
toKeymaster(@onNull @ncryptionPaddingEnum String padding)413         public static int toKeymaster(@NonNull @EncryptionPaddingEnum String padding) {
414             if (ENCRYPTION_PADDING_NONE.equalsIgnoreCase(padding)) {
415                 return KeymasterDefs.KM_PAD_NONE;
416             } else if (ENCRYPTION_PADDING_PKCS7.equalsIgnoreCase(padding)) {
417                 return KeymasterDefs.KM_PAD_PKCS7;
418             } else if (ENCRYPTION_PADDING_RSA_PKCS1.equalsIgnoreCase(padding)) {
419                 return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT;
420             } else if (ENCRYPTION_PADDING_RSA_OAEP.equalsIgnoreCase(padding)) {
421                 return KeymasterDefs.KM_PAD_RSA_OAEP;
422             } else {
423                 throw new IllegalArgumentException(
424                         "Unsupported encryption padding scheme: " + padding);
425             }
426         }
427 
428         @NonNull
fromKeymaster(int padding)429         public static @EncryptionPaddingEnum String fromKeymaster(int padding) {
430             switch (padding) {
431                 case KeymasterDefs.KM_PAD_NONE:
432                     return ENCRYPTION_PADDING_NONE;
433                 case KeymasterDefs.KM_PAD_PKCS7:
434                     return ENCRYPTION_PADDING_PKCS7;
435                 case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
436                     return ENCRYPTION_PADDING_RSA_PKCS1;
437                 case KeymasterDefs.KM_PAD_RSA_OAEP:
438                     return ENCRYPTION_PADDING_RSA_OAEP;
439                 default:
440                     throw new IllegalArgumentException(
441                             "Unsupported encryption padding: " + padding);
442             }
443         }
444 
445         @NonNull
allToKeymaster(@ullable @ncryptionPaddingEnum String[] paddings)446         public static int[] allToKeymaster(@Nullable @EncryptionPaddingEnum String[] paddings) {
447             if ((paddings == null) || (paddings.length == 0)) {
448                 return EmptyArray.INT;
449             }
450             int[] result = new int[paddings.length];
451             for (int i = 0; i < paddings.length; i++) {
452                 result[i] = toKeymaster(paddings[i]);
453             }
454             return result;
455         }
456     }
457 
458     /**
459      * @hide
460      */
461     @Retention(RetentionPolicy.SOURCE)
462     @StringDef(prefix = { "SIGNATURE_PADDING_" }, value = {
463         SIGNATURE_PADDING_RSA_PKCS1,
464         SIGNATURE_PADDING_RSA_PSS,
465         })
466     public @interface SignaturePaddingEnum {}
467 
468     /**
469      * RSA PKCS#1 v1.5 padding for signatures.
470      */
471     public static final String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1";
472 
473     /**
474      * RSA PKCS#1 v2.1 Probabilistic Signature Scheme (PSS) padding.
475      */
476     public static final String SIGNATURE_PADDING_RSA_PSS = "PSS";
477 
478     static abstract class SignaturePadding {
SignaturePadding()479         private SignaturePadding() {}
480 
toKeymaster(@onNull @ignaturePaddingEnum String padding)481         static int toKeymaster(@NonNull @SignaturePaddingEnum String padding) {
482             switch (padding.toUpperCase(Locale.US)) {
483                 case SIGNATURE_PADDING_RSA_PKCS1:
484                     return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN;
485                 case SIGNATURE_PADDING_RSA_PSS:
486                     return KeymasterDefs.KM_PAD_RSA_PSS;
487                 default:
488                     throw new IllegalArgumentException(
489                             "Unsupported signature padding scheme: " + padding);
490             }
491         }
492 
493         @NonNull
fromKeymaster(int padding)494         static @SignaturePaddingEnum String fromKeymaster(int padding) {
495             switch (padding) {
496                 case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN:
497                     return SIGNATURE_PADDING_RSA_PKCS1;
498                 case KeymasterDefs.KM_PAD_RSA_PSS:
499                     return SIGNATURE_PADDING_RSA_PSS;
500                 default:
501                     throw new IllegalArgumentException("Unsupported signature padding: " + padding);
502             }
503         }
504 
505         @NonNull
allToKeymaster(@ullable @ignaturePaddingEnum String[] paddings)506         static int[] allToKeymaster(@Nullable @SignaturePaddingEnum String[] paddings) {
507             if ((paddings == null) || (paddings.length == 0)) {
508                 return EmptyArray.INT;
509             }
510             int[] result = new int[paddings.length];
511             for (int i = 0; i < paddings.length; i++) {
512                 result[i] = toKeymaster(paddings[i]);
513             }
514             return result;
515         }
516     }
517 
518     /**
519      * @hide
520      */
521     @Retention(RetentionPolicy.SOURCE)
522     @StringDef(prefix = { "DIGEST_" }, value = {
523         DIGEST_NONE,
524         DIGEST_MD5,
525         DIGEST_SHA1,
526         DIGEST_SHA224,
527         DIGEST_SHA256,
528         DIGEST_SHA384,
529         DIGEST_SHA512,
530         })
531     public @interface DigestEnum {}
532 
533     /**
534      * No digest: sign/authenticate the raw message.
535      */
536     public static final String DIGEST_NONE = "NONE";
537 
538     /**
539      * MD5 digest.
540      */
541     public static final String DIGEST_MD5 = "MD5";
542 
543     /**
544      * SHA-1 digest.
545      */
546     public static final String DIGEST_SHA1 = "SHA-1";
547 
548     /**
549      * SHA-2 224 (aka SHA-224) digest.
550      */
551     public static final String DIGEST_SHA224 = "SHA-224";
552 
553     /**
554      * SHA-2 256 (aka SHA-256) digest.
555      */
556     public static final String DIGEST_SHA256 = "SHA-256";
557 
558     /**
559      * SHA-2 384 (aka SHA-384) digest.
560      */
561     public static final String DIGEST_SHA384 = "SHA-384";
562 
563     /**
564      * SHA-2 512 (aka SHA-512) digest.
565      */
566     public static final String DIGEST_SHA512 = "SHA-512";
567 
568     /**
569      * @hide
570      */
571     public static abstract class Digest {
Digest()572         private Digest() {}
573 
toKeymaster(@onNull @igestEnum String digest)574         public static int toKeymaster(@NonNull @DigestEnum String digest) {
575             switch (digest.toUpperCase(Locale.US)) {
576                 case DIGEST_SHA1:
577                     return KeymasterDefs.KM_DIGEST_SHA1;
578                 case DIGEST_SHA224:
579                     return KeymasterDefs.KM_DIGEST_SHA_2_224;
580                 case DIGEST_SHA256:
581                     return KeymasterDefs.KM_DIGEST_SHA_2_256;
582                 case DIGEST_SHA384:
583                     return KeymasterDefs.KM_DIGEST_SHA_2_384;
584                 case DIGEST_SHA512:
585                     return KeymasterDefs.KM_DIGEST_SHA_2_512;
586                 case DIGEST_NONE:
587                     return KeymasterDefs.KM_DIGEST_NONE;
588                 case DIGEST_MD5:
589                     return KeymasterDefs.KM_DIGEST_MD5;
590                 default:
591                     throw new IllegalArgumentException("Unsupported digest algorithm: " + digest);
592             }
593         }
594 
595         @NonNull
fromKeymaster(int digest)596         public static @DigestEnum String fromKeymaster(int digest) {
597             switch (digest) {
598                 case KeymasterDefs.KM_DIGEST_NONE:
599                     return DIGEST_NONE;
600                 case KeymasterDefs.KM_DIGEST_MD5:
601                     return DIGEST_MD5;
602                 case KeymasterDefs.KM_DIGEST_SHA1:
603                     return DIGEST_SHA1;
604                 case KeymasterDefs.KM_DIGEST_SHA_2_224:
605                     return DIGEST_SHA224;
606                 case KeymasterDefs.KM_DIGEST_SHA_2_256:
607                     return DIGEST_SHA256;
608                 case KeymasterDefs.KM_DIGEST_SHA_2_384:
609                     return DIGEST_SHA384;
610                 case KeymasterDefs.KM_DIGEST_SHA_2_512:
611                     return DIGEST_SHA512;
612                 default:
613                     throw new IllegalArgumentException("Unsupported digest algorithm: " + digest);
614             }
615         }
616 
617         @NonNull
fromKeymasterToSignatureAlgorithmDigest(int digest)618         public static @DigestEnum String fromKeymasterToSignatureAlgorithmDigest(int digest) {
619             switch (digest) {
620                 case KeymasterDefs.KM_DIGEST_NONE:
621                     return "NONE";
622                 case KeymasterDefs.KM_DIGEST_MD5:
623                     return "MD5";
624                 case KeymasterDefs.KM_DIGEST_SHA1:
625                     return "SHA1";
626                 case KeymasterDefs.KM_DIGEST_SHA_2_224:
627                     return "SHA224";
628                 case KeymasterDefs.KM_DIGEST_SHA_2_256:
629                     return "SHA256";
630                 case KeymasterDefs.KM_DIGEST_SHA_2_384:
631                     return "SHA384";
632                 case KeymasterDefs.KM_DIGEST_SHA_2_512:
633                     return "SHA512";
634                 default:
635                     throw new IllegalArgumentException("Unsupported digest algorithm: " + digest);
636             }
637         }
638 
639         @NonNull
allFromKeymaster(@onNull Collection<Integer> digests)640         public static @DigestEnum String[] allFromKeymaster(@NonNull Collection<Integer> digests) {
641             if (digests.isEmpty()) {
642                 return EmptyArray.STRING;
643             }
644             String[] result = new String[digests.size()];
645             int offset = 0;
646             for (int digest : digests) {
647                 result[offset] = fromKeymaster(digest);
648                 offset++;
649             }
650             return result;
651         }
652 
653         @NonNull
allToKeymaster(@ullable @igestEnum String[] digests)654         public static int[] allToKeymaster(@Nullable @DigestEnum String[] digests) {
655             if ((digests == null) || (digests.length == 0)) {
656                 return EmptyArray.INT;
657             }
658             int[] result = new int[digests.length];
659             int offset = 0;
660             for (@DigestEnum String digest : digests) {
661                 result[offset] = toKeymaster(digest);
662                 offset++;
663             }
664             return result;
665         }
666     }
667 
668     /**
669      * @hide
670      */
671     @Retention(RetentionPolicy.SOURCE)
672     @IntDef(prefix = { "ORIGIN_" }, value = {
673             ORIGIN_GENERATED,
674             ORIGIN_IMPORTED,
675             ORIGIN_UNKNOWN,
676     })
677 
678     public @interface OriginEnum {}
679 
680     /** Key was generated inside AndroidKeyStore. */
681     public static final int ORIGIN_GENERATED = 1 << 0;
682 
683     /** Key was imported into AndroidKeyStore. */
684     public static final int ORIGIN_IMPORTED = 1 << 1;
685 
686     /**
687      * Origin of the key is unknown. This can occur only for keys backed by an old TEE-backed
688      * implementation which does not record origin information.
689      */
690     public static final int ORIGIN_UNKNOWN = 1 << 2;
691 
692     /**
693      * Key was imported into the AndroidKeyStore in an encrypted wrapper. Unlike imported keys,
694      * securely imported keys can be imported without appearing as plaintext in the device's host
695      * memory.
696      */
697     public static final int ORIGIN_SECURELY_IMPORTED = 1 << 3;
698 
699 
700     /**
701      * @hide
702      */
703     public static abstract class Origin {
Origin()704         private Origin() {}
705 
fromKeymaster(int origin)706         public static @OriginEnum int fromKeymaster(int origin) {
707             switch (origin) {
708                 case KeymasterDefs.KM_ORIGIN_GENERATED:
709                     return ORIGIN_GENERATED;
710                 case KeymasterDefs.KM_ORIGIN_IMPORTED:
711                     return ORIGIN_IMPORTED;
712                 case KeymasterDefs.KM_ORIGIN_UNKNOWN:
713                     return ORIGIN_UNKNOWN;
714                 case KeymasterDefs.KM_ORIGIN_SECURELY_IMPORTED:
715                     return ORIGIN_SECURELY_IMPORTED;
716                 default:
717                     throw new IllegalArgumentException("Unknown origin: " + origin);
718             }
719         }
720     }
721 
getSetFlags(int flags)722     private static int[] getSetFlags(int flags) {
723         if (flags == 0) {
724             return EmptyArray.INT;
725         }
726         int result[] = new int[getSetBitCount(flags)];
727         int resultOffset = 0;
728         int flag = 1;
729         while (flags != 0) {
730             if ((flags & 1) != 0) {
731                 result[resultOffset] = flag;
732                 resultOffset++;
733             }
734             flags >>>= 1;
735             flag <<= 1;
736         }
737         return result;
738     }
739 
getSetBitCount(int value)740     private static int getSetBitCount(int value) {
741         if (value == 0) {
742             return 0;
743         }
744         int result = 0;
745         while (value != 0) {
746             if ((value & 1) != 0) {
747                 result++;
748             }
749             value >>>= 1;
750         }
751         return result;
752     }
753 }
754