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