Home | History | Annotate | Download | only in keystore
      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 {
     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 {
     80         private Purpose() {}
     81 
     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 
     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
    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 
    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 {
    187         private KeyAlgorithm() {}
    188 
    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
    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 
    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
    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          */
    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 {
    316         private BlockMode() {}
    317 
    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
    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
    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 
    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 {
    411         private EncryptionPadding() {}
    412 
    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
    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
    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 {
    479         private SignaturePadding() {}
    480 
    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
    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
    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 {
    572         private Digest() {}
    573 
    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
    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
    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
    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
    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 {
    704         private Origin() {}
    705 
    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 
    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 
    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