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