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