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