KeyProperties.java revision ca7aaeaeee616d9d1d557ee2fb19dd14783be1f0
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 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 * <p><b>NOTE</b>: If a key is authorized to be used with no padding, then it can be used with 369 * any padding scheme, both for encryption and signing. 370 */ 371 public static final String ENCRYPTION_PADDING_NONE = "NoPadding"; 372 373 /** 374 * PKCS#7 encryption padding scheme. 375 */ 376 public static final String ENCRYPTION_PADDING_PKCS7 = "PKCS7Padding"; 377 378 /** 379 * RSA PKCS#1 v1.5 padding scheme for encryption. 380 */ 381 public static final String ENCRYPTION_PADDING_RSA_PKCS1 = "PKCS1Padding"; 382 383 /** 384 * RSA Optimal Asymmetric Encryption Padding (OAEP) scheme. 385 */ 386 public static final String ENCRYPTION_PADDING_RSA_OAEP = "OAEPPadding"; 387 388 /** 389 * @hide 390 */ 391 public static abstract class EncryptionPadding { 392 private EncryptionPadding() {} 393 394 public static int toKeymaster(@NonNull @EncryptionPaddingEnum String padding) { 395 if (ENCRYPTION_PADDING_NONE.equalsIgnoreCase(padding)) { 396 return KeymasterDefs.KM_PAD_NONE; 397 } else if (ENCRYPTION_PADDING_PKCS7.equalsIgnoreCase(padding)) { 398 return KeymasterDefs.KM_PAD_PKCS7; 399 } else if (ENCRYPTION_PADDING_RSA_PKCS1.equalsIgnoreCase(padding)) { 400 return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT; 401 } else if (ENCRYPTION_PADDING_RSA_OAEP.equalsIgnoreCase(padding)) { 402 return KeymasterDefs.KM_PAD_RSA_OAEP; 403 } else { 404 throw new IllegalArgumentException( 405 "Unsupported encryption padding scheme: " + padding); 406 } 407 } 408 409 @NonNull 410 public static @EncryptionPaddingEnum String fromKeymaster(int padding) { 411 switch (padding) { 412 case KeymasterDefs.KM_PAD_NONE: 413 return ENCRYPTION_PADDING_NONE; 414 case KeymasterDefs.KM_PAD_PKCS7: 415 return ENCRYPTION_PADDING_PKCS7; 416 case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT: 417 return ENCRYPTION_PADDING_RSA_PKCS1; 418 case KeymasterDefs.KM_PAD_RSA_OAEP: 419 return ENCRYPTION_PADDING_RSA_OAEP; 420 default: 421 throw new IllegalArgumentException( 422 "Unsupported encryption padding: " + padding); 423 } 424 } 425 426 @NonNull 427 public static int[] allToKeymaster(@Nullable @EncryptionPaddingEnum String[] paddings) { 428 if ((paddings == null) || (paddings.length == 0)) { 429 return EmptyArray.INT; 430 } 431 int[] result = new int[paddings.length]; 432 for (int i = 0; i < paddings.length; i++) { 433 result[i] = toKeymaster(paddings[i]); 434 } 435 return result; 436 } 437 } 438 439 /** 440 * @hide 441 */ 442 @Retention(RetentionPolicy.SOURCE) 443 @StringDef({ 444 SIGNATURE_PADDING_RSA_PKCS1, 445 SIGNATURE_PADDING_RSA_PSS, 446 }) 447 public @interface SignaturePaddingEnum {} 448 449 /** 450 * RSA PKCS#1 v1.5 padding for signatures. 451 */ 452 public static final String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1"; 453 454 /** 455 * RSA PKCS#1 v2.1 Probabilistic Signature Scheme (PSS) padding. 456 */ 457 public static final String SIGNATURE_PADDING_RSA_PSS = "PSS"; 458 459 static abstract class SignaturePadding { 460 private SignaturePadding() {} 461 462 static int toKeymaster(@NonNull @SignaturePaddingEnum String padding) { 463 switch (padding.toUpperCase(Locale.US)) { 464 case SIGNATURE_PADDING_RSA_PKCS1: 465 return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN; 466 case SIGNATURE_PADDING_RSA_PSS: 467 return KeymasterDefs.KM_PAD_RSA_PSS; 468 default: 469 throw new IllegalArgumentException( 470 "Unsupported signature padding scheme: " + padding); 471 } 472 } 473 474 @NonNull 475 static @SignaturePaddingEnum String fromKeymaster(int padding) { 476 switch (padding) { 477 case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN: 478 return SIGNATURE_PADDING_RSA_PKCS1; 479 case KeymasterDefs.KM_PAD_RSA_PSS: 480 return SIGNATURE_PADDING_RSA_PSS; 481 default: 482 throw new IllegalArgumentException("Unsupported signature padding: " + padding); 483 } 484 } 485 486 @NonNull 487 static int[] allToKeymaster(@Nullable @SignaturePaddingEnum String[] paddings) { 488 if ((paddings == null) || (paddings.length == 0)) { 489 return EmptyArray.INT; 490 } 491 int[] result = new int[paddings.length]; 492 for (int i = 0; i < paddings.length; i++) { 493 result[i] = toKeymaster(paddings[i]); 494 } 495 return result; 496 } 497 } 498 499 /** 500 * @hide 501 */ 502 @Retention(RetentionPolicy.SOURCE) 503 @StringDef({ 504 DIGEST_NONE, 505 DIGEST_MD5, 506 DIGEST_SHA1, 507 DIGEST_SHA224, 508 DIGEST_SHA256, 509 DIGEST_SHA384, 510 DIGEST_SHA512, 511 }) 512 public @interface DigestEnum {} 513 514 /** 515 * No digest: sign/authenticate the raw message. 516 * 517 * <p><b>NOTE</b>: If a key is authorized to be used with no digest, then it can be used with 518 * any digest. 519 */ 520 public static final String DIGEST_NONE = "NONE"; 521 522 /** 523 * MD5 digest. 524 */ 525 public static final String DIGEST_MD5 = "MD5"; 526 527 /** 528 * SHA-1 digest. 529 */ 530 public static final String DIGEST_SHA1 = "SHA-1"; 531 532 /** 533 * SHA-2 224 (aka SHA-224) digest. 534 */ 535 public static final String DIGEST_SHA224 = "SHA-224"; 536 537 /** 538 * SHA-2 256 (aka SHA-256) digest. 539 */ 540 public static final String DIGEST_SHA256 = "SHA-256"; 541 542 /** 543 * SHA-2 384 (aka SHA-384) digest. 544 */ 545 public static final String DIGEST_SHA384 = "SHA-384"; 546 547 /** 548 * SHA-2 512 (aka SHA-512) digest. 549 */ 550 public static final String DIGEST_SHA512 = "SHA-512"; 551 552 /** 553 * @hide 554 */ 555 public static abstract class Digest { 556 private Digest() {} 557 558 public static int toKeymaster(@NonNull @DigestEnum String digest) { 559 switch (digest.toUpperCase(Locale.US)) { 560 case DIGEST_SHA1: 561 return KeymasterDefs.KM_DIGEST_SHA1; 562 case DIGEST_SHA224: 563 return KeymasterDefs.KM_DIGEST_SHA_2_224; 564 case DIGEST_SHA256: 565 return KeymasterDefs.KM_DIGEST_SHA_2_256; 566 case DIGEST_SHA384: 567 return KeymasterDefs.KM_DIGEST_SHA_2_384; 568 case DIGEST_SHA512: 569 return KeymasterDefs.KM_DIGEST_SHA_2_512; 570 case DIGEST_NONE: 571 return KeymasterDefs.KM_DIGEST_NONE; 572 case DIGEST_MD5: 573 return KeymasterDefs.KM_DIGEST_MD5; 574 default: 575 throw new IllegalArgumentException("Unsupported digest algorithm: " + digest); 576 } 577 } 578 579 @NonNull 580 public static @DigestEnum String fromKeymaster(int digest) { 581 switch (digest) { 582 case KeymasterDefs.KM_DIGEST_NONE: 583 return DIGEST_NONE; 584 case KeymasterDefs.KM_DIGEST_MD5: 585 return DIGEST_MD5; 586 case KeymasterDefs.KM_DIGEST_SHA1: 587 return DIGEST_SHA1; 588 case KeymasterDefs.KM_DIGEST_SHA_2_224: 589 return DIGEST_SHA224; 590 case KeymasterDefs.KM_DIGEST_SHA_2_256: 591 return DIGEST_SHA256; 592 case KeymasterDefs.KM_DIGEST_SHA_2_384: 593 return DIGEST_SHA384; 594 case KeymasterDefs.KM_DIGEST_SHA_2_512: 595 return DIGEST_SHA512; 596 default: 597 throw new IllegalArgumentException("Unsupported digest algorithm: " + digest); 598 } 599 } 600 601 @NonNull 602 public static @DigestEnum String fromKeymasterToSignatureAlgorithmDigest(int digest) { 603 switch (digest) { 604 case KeymasterDefs.KM_DIGEST_NONE: 605 return "NONE"; 606 case KeymasterDefs.KM_DIGEST_MD5: 607 return "MD5"; 608 case KeymasterDefs.KM_DIGEST_SHA1: 609 return "SHA1"; 610 case KeymasterDefs.KM_DIGEST_SHA_2_224: 611 return "SHA224"; 612 case KeymasterDefs.KM_DIGEST_SHA_2_256: 613 return "SHA256"; 614 case KeymasterDefs.KM_DIGEST_SHA_2_384: 615 return "SHA384"; 616 case KeymasterDefs.KM_DIGEST_SHA_2_512: 617 return "SHA512"; 618 default: 619 throw new IllegalArgumentException("Unsupported digest algorithm: " + digest); 620 } 621 } 622 623 @NonNull 624 public static @DigestEnum String[] allFromKeymaster(@NonNull Collection<Integer> digests) { 625 if (digests.isEmpty()) { 626 return EmptyArray.STRING; 627 } 628 String[] result = new String[digests.size()]; 629 int offset = 0; 630 for (int digest : digests) { 631 result[offset] = fromKeymaster(digest); 632 offset++; 633 } 634 return result; 635 } 636 637 @NonNull 638 public static int[] allToKeymaster(@Nullable @DigestEnum String[] digests) { 639 if ((digests == null) || (digests.length == 0)) { 640 return EmptyArray.INT; 641 } 642 int[] result = new int[digests.length]; 643 int offset = 0; 644 for (@DigestEnum String digest : digests) { 645 result[offset] = toKeymaster(digest); 646 offset++; 647 } 648 return result; 649 } 650 } 651 652 /** 653 * @hide 654 */ 655 @Retention(RetentionPolicy.SOURCE) 656 @IntDef({ 657 ORIGIN_GENERATED, 658 ORIGIN_IMPORTED, 659 ORIGIN_UNKNOWN, 660 }) 661 public @interface OriginEnum {} 662 663 /** Key was generated inside AndroidKeyStore. */ 664 public static final int ORIGIN_GENERATED = 1 << 0; 665 666 /** Key was imported into AndroidKeyStore. */ 667 public static final int ORIGIN_IMPORTED = 1 << 1; 668 669 /** 670 * Origin of the key is unknown. This can occur only for keys backed by an old TEE-backed 671 * implementation which does not record origin information. 672 */ 673 public static final int ORIGIN_UNKNOWN = 1 << 2; 674 675 /** 676 * @hide 677 */ 678 public static abstract class Origin { 679 private Origin() {} 680 681 public static @OriginEnum int fromKeymaster(int origin) { 682 switch (origin) { 683 case KeymasterDefs.KM_ORIGIN_GENERATED: 684 return ORIGIN_GENERATED; 685 case KeymasterDefs.KM_ORIGIN_IMPORTED: 686 return ORIGIN_IMPORTED; 687 case KeymasterDefs.KM_ORIGIN_UNKNOWN: 688 return ORIGIN_UNKNOWN; 689 default: 690 throw new IllegalArgumentException("Unknown origin: " + origin); 691 } 692 } 693 } 694 695 private static int[] getSetFlags(int flags) { 696 if (flags == 0) { 697 return EmptyArray.INT; 698 } 699 int result[] = new int[getSetBitCount(flags)]; 700 int resultOffset = 0; 701 int flag = 1; 702 while (flags != 0) { 703 if ((flags & 1) != 0) { 704 result[resultOffset] = flag; 705 resultOffset++; 706 } 707 flags >>>= 1; 708 flag <<= 1; 709 } 710 return result; 711 } 712 713 private static int getSetBitCount(int value) { 714 if (value == 0) { 715 return 0; 716 } 717 int result = 0; 718 while (value != 0) { 719 if ((value & 1) != 0) { 720 result++; 721 } 722 value >>>= 1; 723 } 724 return result; 725 } 726} 727