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,
     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