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