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, 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 { Purpose()75 private Purpose() {} 76 toKeymaster(@urposeEnum int purpose)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 fromKeymaster(int purpose)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 allToKeymaster(@urposeEnum int purposes)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 allFromKeymaster(@onNull Collection<Integer> purposes)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 { KeyAlgorithm()169 private KeyAlgorithm() {} 170 toKeymasterAsymmetricKeyAlgorithm( @onNull @eyAlgorithmEnum String algorithm)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 fromKeymasterAsymmetricKeyAlgorithm( int keymasterAlgorithm)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 toKeymasterSecretKeyAlgorithm( @onNull @eyAlgorithmEnum String algorithm)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 fromKeymasterSecretKeyAlgorithm( int keymasterAlgorithm, int keymasterDigest)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 */ toKeymasterDigest(@onNull @eyAlgorithmEnum String algorithm)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 { BlockMode()294 private BlockMode() {} 295 toKeymaster(@onNull @lockModeEnum String blockMode)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 fromKeymaster(int blockMode)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 allFromKeymaster( @onNull Collection<Integer> blockModes)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 allToKeymaster(@ullable @lockModeEnum String[] blockModes)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 { EncryptionPadding()389 private EncryptionPadding() {} 390 toKeymaster(@onNull @ncryptionPaddingEnum String padding)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 fromKeymaster(int padding)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 allToKeymaster(@ullable @ncryptionPaddingEnum String[] paddings)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 { SignaturePadding()457 private SignaturePadding() {} 458 toKeymaster(@onNull @ignaturePaddingEnum String padding)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 fromKeymaster(int padding)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 allToKeymaster(@ullable @ignaturePaddingEnum String[] paddings)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 { Digest()550 private Digest() {} 551 toKeymaster(@onNull @igestEnum String digest)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 fromKeymaster(int digest)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 fromKeymasterToSignatureAlgorithmDigest(int digest)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 allFromKeymaster(@onNull Collection<Integer> digests)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 allToKeymaster(@ullable @igestEnum String[] digests)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 { Origin()673 private Origin() {} 674 fromKeymaster(int origin)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 getSetFlags(int flags)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 getSetBitCount(int value)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