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.annotation.SystemApi; 24 import android.os.Process; 25 import android.security.keymaster.KeymasterDefs; 26 import java.lang.annotation.Retention; 27 import java.lang.annotation.RetentionPolicy; 28 import java.security.spec.AlgorithmParameterSpec; 29 import java.security.spec.ECParameterSpec; 30 import java.security.spec.MGF1ParameterSpec; 31 import java.util.Collection; 32 import java.util.Locale; 33 import libcore.util.EmptyArray; 34 35 /** 36 * Properties of <a href="{@docRoot}training/articles/keystore.html">Android Keystore</a> keys. 37 */ 38 public abstract class KeyProperties { KeyProperties()39 private KeyProperties() {} 40 41 /** 42 * @hide 43 */ 44 @Retention(RetentionPolicy.SOURCE) 45 @IntDef(flag = true, prefix = { "AUTH_" }, value = { 46 AUTH_BIOMETRIC_STRONG, 47 AUTH_DEVICE_CREDENTIAL, 48 }) 49 public @interface AuthEnum {} 50 51 /** 52 * The non-biometric credential used to secure the device (i.e., PIN, pattern, or password) 53 */ 54 public static final int AUTH_DEVICE_CREDENTIAL = 1 << 0; 55 56 /** 57 * Any biometric (e.g. fingerprint, iris, or face) on the device that meets or exceeds the 58 * requirements for <strong>Strong</strong>, as defined by the Android CDD. 59 */ 60 public static final int AUTH_BIOMETRIC_STRONG = 1 << 1; 61 62 /** 63 * @hide 64 */ 65 @Retention(RetentionPolicy.SOURCE) 66 @IntDef(flag = true, prefix = { "PURPOSE_" }, value = { 67 PURPOSE_ENCRYPT, 68 PURPOSE_DECRYPT, 69 PURPOSE_SIGN, 70 PURPOSE_VERIFY, 71 PURPOSE_WRAP_KEY, 72 PURPOSE_AGREE_KEY, 73 PURPOSE_ATTEST_KEY, 74 }) 75 public @interface PurposeEnum {} 76 77 /** 78 * Purpose of key: encryption. 79 */ 80 public static final int PURPOSE_ENCRYPT = 1 << 0; 81 82 /** 83 * Purpose of key: decryption. 84 */ 85 public static final int PURPOSE_DECRYPT = 1 << 1; 86 87 /** 88 * Purpose of key: signing or generating a Message Authentication Code (MAC). 89 */ 90 public static final int PURPOSE_SIGN = 1 << 2; 91 92 /** 93 * Purpose of key: signature or Message Authentication Code (MAC) verification. 94 */ 95 public static final int PURPOSE_VERIFY = 1 << 3; 96 97 /** 98 * Purpose of key: wrapping and unwrapping wrapped keys for secure import. 99 */ 100 public static final int PURPOSE_WRAP_KEY = 1 << 5; 101 102 /** 103 * Purpose of key: creating a shared ECDH secret through key agreement. 104 * 105 * <p>A key having this purpose can be combined with the elliptic curve public key of another 106 * party to establish a shared secret over an insecure channel. It should be used as a 107 * parameter to {@link javax.crypto.KeyAgreement#init(java.security.Key)} (a complete example is 108 * available <a 109 * href="{@docRoot}reference/android/security/keystore/KeyGenParameterSpec#example:ecdh" 110 * >here</a>). 111 * See <a href="https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman">this 112 * article</a> for a more detailed explanation. 113 */ 114 public static final int PURPOSE_AGREE_KEY = 1 << 6; 115 116 /** 117 * Purpose of key: Signing attestations. This purpose is incompatible with all others, meaning 118 * that when generating a key with PURPOSE_ATTEST_KEY, no other purposes may be specified. In 119 * addition, PURPOSE_ATTEST_KEY may not be specified for imported keys. 120 */ 121 public static final int PURPOSE_ATTEST_KEY = 1 << 7; 122 123 /** 124 * @hide 125 */ 126 public static abstract class Purpose { Purpose()127 private Purpose() {} 128 toKeymaster(@urposeEnum int purpose)129 public static int toKeymaster(@PurposeEnum int purpose) { 130 switch (purpose) { 131 case PURPOSE_ENCRYPT: 132 return KeymasterDefs.KM_PURPOSE_ENCRYPT; 133 case PURPOSE_DECRYPT: 134 return KeymasterDefs.KM_PURPOSE_DECRYPT; 135 case PURPOSE_SIGN: 136 return KeymasterDefs.KM_PURPOSE_SIGN; 137 case PURPOSE_VERIFY: 138 return KeymasterDefs.KM_PURPOSE_VERIFY; 139 case PURPOSE_WRAP_KEY: 140 return KeymasterDefs.KM_PURPOSE_WRAP; 141 case PURPOSE_AGREE_KEY: 142 return KeymasterDefs.KM_PURPOSE_AGREE_KEY; 143 case PURPOSE_ATTEST_KEY: 144 return KeymasterDefs.KM_PURPOSE_ATTEST_KEY; 145 default: 146 throw new IllegalArgumentException("Unknown purpose: " + purpose); 147 } 148 } 149 fromKeymaster(int purpose)150 public static @PurposeEnum int fromKeymaster(int purpose) { 151 switch (purpose) { 152 case KeymasterDefs.KM_PURPOSE_ENCRYPT: 153 return PURPOSE_ENCRYPT; 154 case KeymasterDefs.KM_PURPOSE_DECRYPT: 155 return PURPOSE_DECRYPT; 156 case KeymasterDefs.KM_PURPOSE_SIGN: 157 return PURPOSE_SIGN; 158 case KeymasterDefs.KM_PURPOSE_VERIFY: 159 return PURPOSE_VERIFY; 160 case KeymasterDefs.KM_PURPOSE_WRAP: 161 return PURPOSE_WRAP_KEY; 162 case KeymasterDefs.KM_PURPOSE_AGREE_KEY: 163 return PURPOSE_AGREE_KEY; 164 case KeymasterDefs.KM_PURPOSE_ATTEST_KEY: 165 return PURPOSE_ATTEST_KEY; 166 default: 167 throw new IllegalArgumentException("Unknown purpose: " + purpose); 168 } 169 } 170 171 @NonNull allToKeymaster(@urposeEnum int purposes)172 public static int[] allToKeymaster(@PurposeEnum int purposes) { 173 int[] result = getSetFlags(purposes); 174 for (int i = 0; i < result.length; i++) { 175 result[i] = toKeymaster(result[i]); 176 } 177 return result; 178 } 179 allFromKeymaster(@onNull Collection<Integer> purposes)180 public static @PurposeEnum int allFromKeymaster(@NonNull Collection<Integer> purposes) { 181 @PurposeEnum int result = 0; 182 for (int keymasterPurpose : purposes) { 183 result |= fromKeymaster(keymasterPurpose); 184 } 185 return result; 186 } 187 } 188 189 /** 190 * @hide 191 */ 192 @Retention(RetentionPolicy.SOURCE) 193 @StringDef(prefix = { "KEY_" }, value = { 194 KEY_ALGORITHM_RSA, 195 KEY_ALGORITHM_EC, 196 KEY_ALGORITHM_XDH, 197 KEY_ALGORITHM_AES, 198 KEY_ALGORITHM_HMAC_SHA1, 199 KEY_ALGORITHM_HMAC_SHA224, 200 KEY_ALGORITHM_HMAC_SHA256, 201 KEY_ALGORITHM_HMAC_SHA384, 202 KEY_ALGORITHM_HMAC_SHA512, 203 }) 204 public @interface KeyAlgorithmEnum {} 205 206 /** Rivest Shamir Adleman (RSA) key. */ 207 public static final String KEY_ALGORITHM_RSA = "RSA"; 208 209 /** Elliptic Curve (EC) Cryptography key. */ 210 public static final String KEY_ALGORITHM_EC = "EC"; 211 212 /** Curve 25519 based Agreement key. 213 * @hide 214 */ 215 public static final String KEY_ALGORITHM_XDH = "XDH"; 216 217 /** Advanced Encryption Standard (AES) key. */ 218 public static final String KEY_ALGORITHM_AES = "AES"; 219 220 /** 221 * Triple Data Encryption Algorithm (3DES) key. 222 * 223 * @deprecated Included for interoperability with legacy systems. Prefer {@link 224 * KeyProperties#KEY_ALGORITHM_AES} for new development. 225 */ 226 @Deprecated 227 public static final String KEY_ALGORITHM_3DES = "DESede"; 228 229 /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-1 as the hash. */ 230 public static final String KEY_ALGORITHM_HMAC_SHA1 = "HmacSHA1"; 231 232 /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-224 as the hash. */ 233 public static final String KEY_ALGORITHM_HMAC_SHA224 = "HmacSHA224"; 234 235 /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-256 as the hash. */ 236 public static final String KEY_ALGORITHM_HMAC_SHA256 = "HmacSHA256"; 237 238 /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-384 as the hash. */ 239 public static final String KEY_ALGORITHM_HMAC_SHA384 = "HmacSHA384"; 240 241 /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-512 as the hash. */ 242 public static final String KEY_ALGORITHM_HMAC_SHA512 = "HmacSHA512"; 243 244 /** 245 * @hide 246 */ 247 public static abstract class KeyAlgorithm { KeyAlgorithm()248 private KeyAlgorithm() {} 249 toKeymasterAsymmetricKeyAlgorithm( @onNull @eyAlgorithmEnum String algorithm)250 public static int toKeymasterAsymmetricKeyAlgorithm( 251 @NonNull @KeyAlgorithmEnum String algorithm) { 252 if (KEY_ALGORITHM_EC.equalsIgnoreCase(algorithm) 253 || KEY_ALGORITHM_XDH.equalsIgnoreCase(algorithm)) { 254 return KeymasterDefs.KM_ALGORITHM_EC; 255 } else if (KEY_ALGORITHM_RSA.equalsIgnoreCase(algorithm)) { 256 return KeymasterDefs.KM_ALGORITHM_RSA; 257 } else { 258 throw new IllegalArgumentException("Unsupported key algorithm: " + algorithm); 259 } 260 } 261 262 @NonNull fromKeymasterAsymmetricKeyAlgorithm( int keymasterAlgorithm)263 public static @KeyAlgorithmEnum String fromKeymasterAsymmetricKeyAlgorithm( 264 int keymasterAlgorithm) { 265 switch (keymasterAlgorithm) { 266 case KeymasterDefs.KM_ALGORITHM_EC: 267 return KEY_ALGORITHM_EC; 268 case KeymasterDefs.KM_ALGORITHM_RSA: 269 return KEY_ALGORITHM_RSA; 270 default: 271 throw new IllegalArgumentException( 272 "Unsupported key algorithm: " + keymasterAlgorithm); 273 } 274 } 275 toKeymasterSecretKeyAlgorithm( @onNull @eyAlgorithmEnum String algorithm)276 public static int toKeymasterSecretKeyAlgorithm( 277 @NonNull @KeyAlgorithmEnum String algorithm) { 278 if (KEY_ALGORITHM_AES.equalsIgnoreCase(algorithm)) { 279 return KeymasterDefs.KM_ALGORITHM_AES; 280 } else if (KEY_ALGORITHM_3DES.equalsIgnoreCase(algorithm)) { 281 return KeymasterDefs.KM_ALGORITHM_3DES; 282 } else if (algorithm.toUpperCase(Locale.US).startsWith("HMAC")) { 283 return KeymasterDefs.KM_ALGORITHM_HMAC; 284 } else { 285 throw new IllegalArgumentException( 286 "Unsupported secret key algorithm: " + algorithm); 287 } 288 } 289 290 @NonNull fromKeymasterSecretKeyAlgorithm( int keymasterAlgorithm, int keymasterDigest)291 public static @KeyAlgorithmEnum String fromKeymasterSecretKeyAlgorithm( 292 int keymasterAlgorithm, int keymasterDigest) { 293 switch (keymasterAlgorithm) { 294 case KeymasterDefs.KM_ALGORITHM_AES: 295 return KEY_ALGORITHM_AES; 296 case KeymasterDefs.KM_ALGORITHM_3DES: 297 return KEY_ALGORITHM_3DES; 298 case KeymasterDefs.KM_ALGORITHM_HMAC: 299 switch (keymasterDigest) { 300 case KeymasterDefs.KM_DIGEST_SHA1: 301 return KEY_ALGORITHM_HMAC_SHA1; 302 case KeymasterDefs.KM_DIGEST_SHA_2_224: 303 return KEY_ALGORITHM_HMAC_SHA224; 304 case KeymasterDefs.KM_DIGEST_SHA_2_256: 305 return KEY_ALGORITHM_HMAC_SHA256; 306 case KeymasterDefs.KM_DIGEST_SHA_2_384: 307 return KEY_ALGORITHM_HMAC_SHA384; 308 case KeymasterDefs.KM_DIGEST_SHA_2_512: 309 return KEY_ALGORITHM_HMAC_SHA512; 310 default: 311 throw new IllegalArgumentException("Unsupported HMAC digest: " 312 + Digest.fromKeymaster(keymasterDigest)); 313 } 314 default: 315 throw new IllegalArgumentException( 316 "Unsupported key algorithm: " + keymasterAlgorithm); 317 } 318 } 319 320 /** 321 * @hide 322 * 323 * @return keymaster digest or {@code -1} if the algorithm does not involve a digest. 324 */ toKeymasterDigest(@onNull @eyAlgorithmEnum String algorithm)325 public static int toKeymasterDigest(@NonNull @KeyAlgorithmEnum String algorithm) { 326 String algorithmUpper = algorithm.toUpperCase(Locale.US); 327 if (algorithmUpper.startsWith("HMAC")) { 328 String digestUpper = algorithmUpper.substring("HMAC".length()); 329 switch (digestUpper) { 330 case "SHA1": 331 return KeymasterDefs.KM_DIGEST_SHA1; 332 case "SHA224": 333 return KeymasterDefs.KM_DIGEST_SHA_2_224; 334 case "SHA256": 335 return KeymasterDefs.KM_DIGEST_SHA_2_256; 336 case "SHA384": 337 return KeymasterDefs.KM_DIGEST_SHA_2_384; 338 case "SHA512": 339 return KeymasterDefs.KM_DIGEST_SHA_2_512; 340 default: 341 throw new IllegalArgumentException( 342 "Unsupported HMAC digest: " + digestUpper); 343 } 344 } else { 345 return -1; 346 } 347 } 348 } 349 350 /** 351 * @hide 352 */ 353 @Retention(RetentionPolicy.SOURCE) 354 @StringDef(prefix = { "BLOCK_MODE_" }, value = { 355 BLOCK_MODE_ECB, 356 BLOCK_MODE_CBC, 357 BLOCK_MODE_CTR, 358 BLOCK_MODE_GCM, 359 }) 360 public @interface BlockModeEnum {} 361 362 /** Electronic Codebook (ECB) block mode. */ 363 public static final String BLOCK_MODE_ECB = "ECB"; 364 365 /** Cipher Block Chaining (CBC) block mode. */ 366 public static final String BLOCK_MODE_CBC = "CBC"; 367 368 /** Counter (CTR) block mode. */ 369 public static final String BLOCK_MODE_CTR = "CTR"; 370 371 /** Galois/Counter Mode (GCM) block mode. */ 372 public static final String BLOCK_MODE_GCM = "GCM"; 373 374 /** 375 * @hide 376 */ 377 public static abstract class BlockMode { BlockMode()378 private BlockMode() {} 379 toKeymaster(@onNull @lockModeEnum String blockMode)380 public static int toKeymaster(@NonNull @BlockModeEnum String blockMode) { 381 if (BLOCK_MODE_ECB.equalsIgnoreCase(blockMode)) { 382 return KeymasterDefs.KM_MODE_ECB; 383 } else if (BLOCK_MODE_CBC.equalsIgnoreCase(blockMode)) { 384 return KeymasterDefs.KM_MODE_CBC; 385 } else if (BLOCK_MODE_CTR.equalsIgnoreCase(blockMode)) { 386 return KeymasterDefs.KM_MODE_CTR; 387 } else if (BLOCK_MODE_GCM.equalsIgnoreCase(blockMode)) { 388 return KeymasterDefs.KM_MODE_GCM; 389 } else { 390 throw new IllegalArgumentException("Unsupported block mode: " + blockMode); 391 } 392 } 393 394 @NonNull fromKeymaster(int blockMode)395 public static @BlockModeEnum String fromKeymaster(int blockMode) { 396 switch (blockMode) { 397 case KeymasterDefs.KM_MODE_ECB: 398 return BLOCK_MODE_ECB; 399 case KeymasterDefs.KM_MODE_CBC: 400 return BLOCK_MODE_CBC; 401 case KeymasterDefs.KM_MODE_CTR: 402 return BLOCK_MODE_CTR; 403 case KeymasterDefs.KM_MODE_GCM: 404 return BLOCK_MODE_GCM; 405 default: 406 throw new IllegalArgumentException("Unsupported block mode: " + blockMode); 407 } 408 } 409 410 @NonNull allFromKeymaster( @onNull Collection<Integer> blockModes)411 public static @BlockModeEnum String[] allFromKeymaster( 412 @NonNull Collection<Integer> blockModes) { 413 if ((blockModes == null) || (blockModes.isEmpty())) { 414 return EmptyArray.STRING; 415 } 416 @BlockModeEnum String[] result = new String[blockModes.size()]; 417 int offset = 0; 418 for (int blockMode : blockModes) { 419 result[offset] = fromKeymaster(blockMode); 420 offset++; 421 } 422 return result; 423 } 424 allToKeymaster(@ullable @lockModeEnum String[] blockModes)425 public static int[] allToKeymaster(@Nullable @BlockModeEnum String[] blockModes) { 426 if ((blockModes == null) || (blockModes.length == 0)) { 427 return EmptyArray.INT; 428 } 429 int[] result = new int[blockModes.length]; 430 for (int i = 0; i < blockModes.length; i++) { 431 result[i] = toKeymaster(blockModes[i]); 432 } 433 return result; 434 } 435 } 436 437 /** 438 * @hide 439 */ 440 @Retention(RetentionPolicy.SOURCE) 441 @StringDef(prefix = { "ENCRYPTION_PADDING_" }, value = { 442 ENCRYPTION_PADDING_NONE, 443 ENCRYPTION_PADDING_PKCS7, 444 ENCRYPTION_PADDING_RSA_PKCS1, 445 ENCRYPTION_PADDING_RSA_OAEP, 446 }) 447 public @interface EncryptionPaddingEnum {} 448 449 /** 450 * No encryption padding. 451 */ 452 public static final String ENCRYPTION_PADDING_NONE = "NoPadding"; 453 454 /** 455 * PKCS#7 encryption padding scheme. 456 */ 457 public static final String ENCRYPTION_PADDING_PKCS7 = "PKCS7Padding"; 458 459 /** 460 * RSA PKCS#1 v1.5 padding scheme for encryption. 461 */ 462 public static final String ENCRYPTION_PADDING_RSA_PKCS1 = "PKCS1Padding"; 463 464 /** 465 * RSA Optimal Asymmetric Encryption Padding (OAEP) scheme. 466 */ 467 public static final String ENCRYPTION_PADDING_RSA_OAEP = "OAEPPadding"; 468 469 /** 470 * @hide 471 */ 472 public static abstract class EncryptionPadding { EncryptionPadding()473 private EncryptionPadding() {} 474 toKeymaster(@onNull @ncryptionPaddingEnum String padding)475 public static int toKeymaster(@NonNull @EncryptionPaddingEnum String padding) { 476 if (ENCRYPTION_PADDING_NONE.equalsIgnoreCase(padding)) { 477 return KeymasterDefs.KM_PAD_NONE; 478 } else if (ENCRYPTION_PADDING_PKCS7.equalsIgnoreCase(padding)) { 479 return KeymasterDefs.KM_PAD_PKCS7; 480 } else if (ENCRYPTION_PADDING_RSA_PKCS1.equalsIgnoreCase(padding)) { 481 return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT; 482 } else if (ENCRYPTION_PADDING_RSA_OAEP.equalsIgnoreCase(padding)) { 483 return KeymasterDefs.KM_PAD_RSA_OAEP; 484 } else { 485 throw new IllegalArgumentException( 486 "Unsupported encryption padding scheme: " + padding); 487 } 488 } 489 490 @NonNull fromKeymaster(int padding)491 public static @EncryptionPaddingEnum String fromKeymaster(int padding) { 492 switch (padding) { 493 case KeymasterDefs.KM_PAD_NONE: 494 return ENCRYPTION_PADDING_NONE; 495 case KeymasterDefs.KM_PAD_PKCS7: 496 return ENCRYPTION_PADDING_PKCS7; 497 case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT: 498 return ENCRYPTION_PADDING_RSA_PKCS1; 499 case KeymasterDefs.KM_PAD_RSA_OAEP: 500 return ENCRYPTION_PADDING_RSA_OAEP; 501 default: 502 throw new IllegalArgumentException( 503 "Unsupported encryption padding: " + padding); 504 } 505 } 506 507 @NonNull allToKeymaster(@ullable @ncryptionPaddingEnum String[] paddings)508 public static int[] allToKeymaster(@Nullable @EncryptionPaddingEnum String[] paddings) { 509 if ((paddings == null) || (paddings.length == 0)) { 510 return EmptyArray.INT; 511 } 512 int[] result = new int[paddings.length]; 513 for (int i = 0; i < paddings.length; i++) { 514 result[i] = toKeymaster(paddings[i]); 515 } 516 return result; 517 } 518 } 519 520 /** 521 * @hide 522 */ 523 @Retention(RetentionPolicy.SOURCE) 524 @StringDef(prefix = { "SIGNATURE_PADDING_" }, value = { 525 SIGNATURE_PADDING_RSA_PKCS1, 526 SIGNATURE_PADDING_RSA_PSS, 527 }) 528 public @interface SignaturePaddingEnum {} 529 530 /** 531 * RSA PKCS#1 v1.5 padding for signatures. 532 */ 533 public static final String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1"; 534 535 /** 536 * RSA PKCS#1 v2.1 Probabilistic Signature Scheme (PSS) padding. 537 */ 538 public static final String SIGNATURE_PADDING_RSA_PSS = "PSS"; 539 540 /** 541 * @hide 542 */ 543 public abstract static class SignaturePadding { SignaturePadding()544 private SignaturePadding() {} 545 546 /** 547 * @hide 548 */ toKeymaster(@onNull @ignaturePaddingEnum String padding)549 public static int toKeymaster(@NonNull @SignaturePaddingEnum String padding) { 550 switch (padding.toUpperCase(Locale.US)) { 551 case SIGNATURE_PADDING_RSA_PKCS1: 552 return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN; 553 case SIGNATURE_PADDING_RSA_PSS: 554 return KeymasterDefs.KM_PAD_RSA_PSS; 555 default: 556 throw new IllegalArgumentException( 557 "Unsupported signature padding scheme: " + padding); 558 } 559 } 560 561 @NonNull fromKeymaster(int padding)562 public static @SignaturePaddingEnum String fromKeymaster(int padding) { 563 switch (padding) { 564 case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN: 565 return SIGNATURE_PADDING_RSA_PKCS1; 566 case KeymasterDefs.KM_PAD_RSA_PSS: 567 return SIGNATURE_PADDING_RSA_PSS; 568 default: 569 throw new IllegalArgumentException("Unsupported signature padding: " + padding); 570 } 571 } 572 573 @NonNull allToKeymaster(@ullable @ignaturePaddingEnum String[] paddings)574 public static int[] allToKeymaster(@Nullable @SignaturePaddingEnum String[] paddings) { 575 if ((paddings == null) || (paddings.length == 0)) { 576 return EmptyArray.INT; 577 } 578 int[] result = new int[paddings.length]; 579 for (int i = 0; i < paddings.length; i++) { 580 result[i] = toKeymaster(paddings[i]); 581 } 582 return result; 583 } 584 } 585 586 /** 587 * @hide 588 */ 589 @Retention(RetentionPolicy.SOURCE) 590 @StringDef(prefix = { "DIGEST_" }, value = { 591 DIGEST_NONE, 592 DIGEST_MD5, 593 DIGEST_SHA1, 594 DIGEST_SHA224, 595 DIGEST_SHA256, 596 DIGEST_SHA384, 597 DIGEST_SHA512, 598 }) 599 public @interface DigestEnum {} 600 601 /** 602 * No digest: sign/authenticate the raw message. 603 */ 604 public static final String DIGEST_NONE = "NONE"; 605 606 /** 607 * MD5 digest. 608 */ 609 public static final String DIGEST_MD5 = "MD5"; 610 611 /** 612 * SHA-1 digest. 613 */ 614 public static final String DIGEST_SHA1 = "SHA-1"; 615 616 /** 617 * SHA-2 224 (aka SHA-224) digest. 618 */ 619 public static final String DIGEST_SHA224 = "SHA-224"; 620 621 /** 622 * SHA-2 256 (aka SHA-256) digest. 623 */ 624 public static final String DIGEST_SHA256 = "SHA-256"; 625 626 /** 627 * SHA-2 384 (aka SHA-384) digest. 628 */ 629 public static final String DIGEST_SHA384 = "SHA-384"; 630 631 /** 632 * SHA-2 512 (aka SHA-512) digest. 633 */ 634 public static final String DIGEST_SHA512 = "SHA-512"; 635 636 /** 637 * @hide 638 */ 639 public static abstract class Digest { Digest()640 private Digest() {} 641 toKeymaster(@onNull @igestEnum String digest)642 public static int toKeymaster(@NonNull @DigestEnum String digest) { 643 switch (digest.toUpperCase(Locale.US)) { 644 case DIGEST_SHA1: 645 return KeymasterDefs.KM_DIGEST_SHA1; 646 case DIGEST_SHA224: 647 return KeymasterDefs.KM_DIGEST_SHA_2_224; 648 case DIGEST_SHA256: 649 return KeymasterDefs.KM_DIGEST_SHA_2_256; 650 case DIGEST_SHA384: 651 return KeymasterDefs.KM_DIGEST_SHA_2_384; 652 case DIGEST_SHA512: 653 return KeymasterDefs.KM_DIGEST_SHA_2_512; 654 case DIGEST_NONE: 655 return KeymasterDefs.KM_DIGEST_NONE; 656 case DIGEST_MD5: 657 return KeymasterDefs.KM_DIGEST_MD5; 658 default: 659 throw new IllegalArgumentException("Unsupported digest algorithm: " + digest); 660 } 661 } 662 663 @NonNull fromKeymaster(int digest)664 public static @DigestEnum String fromKeymaster(int digest) { 665 switch (digest) { 666 case KeymasterDefs.KM_DIGEST_NONE: 667 return DIGEST_NONE; 668 case KeymasterDefs.KM_DIGEST_MD5: 669 return DIGEST_MD5; 670 case KeymasterDefs.KM_DIGEST_SHA1: 671 return DIGEST_SHA1; 672 case KeymasterDefs.KM_DIGEST_SHA_2_224: 673 return DIGEST_SHA224; 674 case KeymasterDefs.KM_DIGEST_SHA_2_256: 675 return DIGEST_SHA256; 676 case KeymasterDefs.KM_DIGEST_SHA_2_384: 677 return DIGEST_SHA384; 678 case KeymasterDefs.KM_DIGEST_SHA_2_512: 679 return DIGEST_SHA512; 680 default: 681 throw new IllegalArgumentException("Unsupported digest algorithm: " + digest); 682 } 683 } 684 685 /** 686 * @hide 687 */ 688 @NonNull public static @DigestEnum fromKeymasterToMGF1ParameterSpec(int digest)689 AlgorithmParameterSpec fromKeymasterToMGF1ParameterSpec(int digest) { 690 switch (digest) { 691 default: 692 case KeymasterDefs.KM_DIGEST_SHA1: 693 return MGF1ParameterSpec.SHA1; 694 case KeymasterDefs.KM_DIGEST_SHA_2_224: 695 return MGF1ParameterSpec.SHA224; 696 case KeymasterDefs.KM_DIGEST_SHA_2_256: 697 return MGF1ParameterSpec.SHA256; 698 case KeymasterDefs.KM_DIGEST_SHA_2_384: 699 return MGF1ParameterSpec.SHA384; 700 case KeymasterDefs.KM_DIGEST_SHA_2_512: 701 return MGF1ParameterSpec.SHA512; 702 } 703 } 704 705 @NonNull fromKeymasterToSignatureAlgorithmDigest(int digest)706 public static @DigestEnum String fromKeymasterToSignatureAlgorithmDigest(int digest) { 707 switch (digest) { 708 case KeymasterDefs.KM_DIGEST_NONE: 709 return "NONE"; 710 case KeymasterDefs.KM_DIGEST_MD5: 711 return "MD5"; 712 case KeymasterDefs.KM_DIGEST_SHA1: 713 return "SHA1"; 714 case KeymasterDefs.KM_DIGEST_SHA_2_224: 715 return "SHA224"; 716 case KeymasterDefs.KM_DIGEST_SHA_2_256: 717 return "SHA256"; 718 case KeymasterDefs.KM_DIGEST_SHA_2_384: 719 return "SHA384"; 720 case KeymasterDefs.KM_DIGEST_SHA_2_512: 721 return "SHA512"; 722 default: 723 throw new IllegalArgumentException("Unsupported digest algorithm: " + digest); 724 } 725 } 726 727 @NonNull allFromKeymaster(@onNull Collection<Integer> digests)728 public static @DigestEnum String[] allFromKeymaster(@NonNull Collection<Integer> digests) { 729 if (digests.isEmpty()) { 730 return EmptyArray.STRING; 731 } 732 String[] result = new String[digests.size()]; 733 int offset = 0; 734 for (int digest : digests) { 735 result[offset] = fromKeymaster(digest); 736 offset++; 737 } 738 return result; 739 } 740 741 @NonNull allToKeymaster(@ullable @igestEnum String[] digests)742 public static int[] allToKeymaster(@Nullable @DigestEnum String[] digests) { 743 if ((digests == null) || (digests.length == 0)) { 744 return EmptyArray.INT; 745 } 746 int[] result = new int[digests.length]; 747 int offset = 0; 748 for (@DigestEnum String digest : digests) { 749 result[offset] = toKeymaster(digest); 750 offset++; 751 } 752 return result; 753 } 754 } 755 756 /** 757 * @hide 758 */ 759 @Retention(RetentionPolicy.SOURCE) 760 @IntDef(prefix = { "ORIGIN_" }, value = { 761 ORIGIN_GENERATED, 762 ORIGIN_IMPORTED, 763 ORIGIN_UNKNOWN, 764 }) 765 766 public @interface OriginEnum {} 767 768 /** Key was generated inside AndroidKeyStore. */ 769 public static final int ORIGIN_GENERATED = 1 << 0; 770 771 /** Key was imported into AndroidKeyStore. */ 772 public static final int ORIGIN_IMPORTED = 1 << 1; 773 774 /** 775 * Origin of the key is unknown. This can occur only for keys backed by an old TEE-backed 776 * implementation which does not record origin information. 777 */ 778 public static final int ORIGIN_UNKNOWN = 1 << 2; 779 780 /** 781 * Key was imported into the AndroidKeyStore in an encrypted wrapper. Unlike imported keys, 782 * securely imported keys can be imported without appearing as plaintext in the device's host 783 * memory. 784 */ 785 public static final int ORIGIN_SECURELY_IMPORTED = 1 << 3; 786 787 788 /** 789 * @hide 790 */ 791 public static abstract class Origin { Origin()792 private Origin() {} 793 fromKeymaster(int origin)794 public static @OriginEnum int fromKeymaster(int origin) { 795 switch (origin) { 796 case KeymasterDefs.KM_ORIGIN_GENERATED: 797 return ORIGIN_GENERATED; 798 case KeymasterDefs.KM_ORIGIN_IMPORTED: 799 return ORIGIN_IMPORTED; 800 case KeymasterDefs.KM_ORIGIN_UNKNOWN: 801 return ORIGIN_UNKNOWN; 802 case KeymasterDefs.KM_ORIGIN_SECURELY_IMPORTED: 803 return ORIGIN_SECURELY_IMPORTED; 804 default: 805 throw new IllegalArgumentException("Unknown origin: " + origin); 806 } 807 } 808 } 809 getSetFlags(int flags)810 private static int[] getSetFlags(int flags) { 811 if (flags == 0) { 812 return EmptyArray.INT; 813 } 814 int result[] = new int[getSetBitCount(flags)]; 815 int resultOffset = 0; 816 int flag = 1; 817 while (flags != 0) { 818 if ((flags & 1) != 0) { 819 result[resultOffset] = flag; 820 resultOffset++; 821 } 822 flags >>>= 1; 823 flag <<= 1; 824 } 825 return result; 826 } 827 getSetBitCount(int value)828 private static int getSetBitCount(int value) { 829 if (value == 0) { 830 return 0; 831 } 832 int result = 0; 833 while (value != 0) { 834 if ((value & 1) != 0) { 835 result++; 836 } 837 value >>>= 1; 838 } 839 return result; 840 } 841 842 /** 843 * @hide 844 */ 845 @Retention(RetentionPolicy.SOURCE) 846 @IntDef(prefix = { "SECURITY_LEVEL_" }, value = { 847 SECURITY_LEVEL_UNKNOWN, 848 SECURITY_LEVEL_UNKNOWN_SECURE, 849 SECURITY_LEVEL_SOFTWARE, 850 SECURITY_LEVEL_TRUSTED_ENVIRONMENT, 851 SECURITY_LEVEL_STRONGBOX, 852 }) 853 public @interface SecurityLevelEnum {} 854 855 /** 856 * This security level indicates that no assumptions can be made about the security level of the 857 * respective key. 858 */ 859 public static final int SECURITY_LEVEL_UNKNOWN = -2; 860 /** 861 * This security level indicates that due to the target API level of the caller no exact 862 * statement can be made about the security level of the key, however, the security level 863 * can be considered is at least equivalent to {@link #SECURITY_LEVEL_TRUSTED_ENVIRONMENT}. 864 */ 865 public static final int SECURITY_LEVEL_UNKNOWN_SECURE = -1; 866 867 /** Indicates enforcement by system software. */ 868 public static final int SECURITY_LEVEL_SOFTWARE = 0; 869 870 /** Indicates enforcement by a trusted execution environment. */ 871 public static final int SECURITY_LEVEL_TRUSTED_ENVIRONMENT = 1; 872 873 /** 874 * Indicates enforcement by environment meeting the Strongbox security profile, 875 * such as a secure element. 876 */ 877 public static final int SECURITY_LEVEL_STRONGBOX = 2; 878 879 /** 880 * @hide 881 */ 882 public abstract static class SecurityLevel { SecurityLevel()883 private SecurityLevel() {} 884 885 /** 886 * @hide 887 */ toKeymaster(int securityLevel)888 public static int toKeymaster(int securityLevel) { 889 switch (securityLevel) { 890 case SECURITY_LEVEL_SOFTWARE: 891 return KeymasterDefs.KM_SECURITY_LEVEL_SOFTWARE; 892 case SECURITY_LEVEL_TRUSTED_ENVIRONMENT: 893 return KeymasterDefs.KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT; 894 case SECURITY_LEVEL_STRONGBOX: 895 return KeymasterDefs.KM_SECURITY_LEVEL_STRONGBOX; 896 default: 897 throw new IllegalArgumentException("Unsupported security level: " 898 + securityLevel); 899 } 900 } 901 902 /** 903 * @hide 904 */ 905 @NonNull fromKeymaster(int securityLevel)906 public static int fromKeymaster(int securityLevel) { 907 switch (securityLevel) { 908 case KeymasterDefs.KM_SECURITY_LEVEL_SOFTWARE: 909 return SECURITY_LEVEL_SOFTWARE; 910 case KeymasterDefs.KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT: 911 return SECURITY_LEVEL_TRUSTED_ENVIRONMENT; 912 case KeymasterDefs.KM_SECURITY_LEVEL_STRONGBOX: 913 return SECURITY_LEVEL_STRONGBOX; 914 default: 915 throw new IllegalArgumentException("Unsupported security level: " 916 + securityLevel); 917 } 918 } 919 } 920 921 /** 922 * @hide 923 */ 924 public abstract static class EcCurve { EcCurve()925 private EcCurve() {} 926 927 /** 928 * @hide 929 */ toKeymasterCurve(ECParameterSpec spec)930 public static int toKeymasterCurve(ECParameterSpec spec) { 931 int keySize = spec.getCurve().getField().getFieldSize(); 932 switch (keySize) { 933 case 224: 934 return android.hardware.security.keymint.EcCurve.P_224; 935 case 256: 936 return android.hardware.security.keymint.EcCurve.P_256; 937 case 384: 938 return android.hardware.security.keymint.EcCurve.P_384; 939 case 521: 940 return android.hardware.security.keymint.EcCurve.P_521; 941 default: 942 return -1; 943 } 944 } 945 946 /** 947 * @hide 948 */ fromKeymasterCurve(int ecCurve)949 public static int fromKeymasterCurve(int ecCurve) { 950 switch (ecCurve) { 951 case android.hardware.security.keymint.EcCurve.P_224: 952 return 224; 953 case android.hardware.security.keymint.EcCurve.P_256: 954 case android.hardware.security.keymint.EcCurve.CURVE_25519: 955 return 256; 956 case android.hardware.security.keymint.EcCurve.P_384: 957 return 384; 958 case android.hardware.security.keymint.EcCurve.P_521: 959 return 521; 960 default: 961 return -1; 962 } 963 } 964 } 965 966 /** 967 * Namespaces provide system developers and vendors with a way to use keystore without 968 * requiring an applications uid. Namespaces can be configured using SEPolicy. 969 * See <a href="https://source.android.com/security/keystore#access-control"> 970 * Keystore 2.0 access-control</a> 971 * {@See KeyGenParameterSpec.Builder#setNamespace} 972 * {@See android.security.keystore2.AndroidKeyStoreLoadStoreParameter} 973 * @hide 974 */ 975 @Retention(RetentionPolicy.SOURCE) 976 @IntDef(prefix = { "NAMESPACE_" }, value = { 977 NAMESPACE_APPLICATION, 978 NAMESPACE_WIFI, 979 NAMESPACE_LOCKSETTINGS, 980 }) 981 public @interface Namespace {} 982 983 /** 984 * This value indicates the implicit keystore namespace of the calling application. 985 * It is used by default. Only select system components can choose a different namespace 986 * which it must be configured in SEPolicy. 987 * @hide 988 */ 989 @SystemApi 990 public static final int NAMESPACE_APPLICATION = -1; 991 992 /** 993 * The namespace identifier for the WIFI Keystore namespace. 994 * This must be kept in sync with system/sepolicy/private/keystore2_key_contexts 995 * @hide 996 */ 997 @SystemApi 998 public static final int NAMESPACE_WIFI = 102; 999 1000 /** 1001 * The namespace identifier for the LOCKSETTINGS Keystore namespace. 1002 * This must be kept in sync with system/sepolicy/private/keystore2_key_contexts 1003 * @hide 1004 */ 1005 public static final int NAMESPACE_LOCKSETTINGS = 103; 1006 1007 /** 1008 * The legacy UID that corresponds to {@link #NAMESPACE_APPLICATION}. 1009 * In new code, prefer to work with Keystore namespaces directly. 1010 * @hide 1011 */ 1012 public static final int UID_SELF = -1; 1013 1014 /** 1015 * For legacy support, translate namespaces into known UIDs. 1016 * @hide 1017 */ namespaceToLegacyUid(@amespace int namespace)1018 public static int namespaceToLegacyUid(@Namespace int namespace) { 1019 switch (namespace) { 1020 case NAMESPACE_APPLICATION: 1021 return UID_SELF; 1022 case NAMESPACE_WIFI: 1023 return Process.WIFI_UID; 1024 default: 1025 throw new IllegalArgumentException("No UID corresponding to namespace " 1026 + namespace); 1027 } 1028 } 1029 1030 /** 1031 * For legacy support, translate namespaces into known UIDs. 1032 * @hide 1033 */ legacyUidToNamespace(int uid)1034 public static @Namespace int legacyUidToNamespace(int uid) { 1035 switch (uid) { 1036 case UID_SELF: 1037 return NAMESPACE_APPLICATION; 1038 case Process.WIFI_UID: 1039 return NAMESPACE_WIFI; 1040 default: 1041 throw new IllegalArgumentException("No namespace corresponding to uid " 1042 + uid); 1043 } 1044 } 1045 1046 /** 1047 * This value indicates that there is no restriction on the number of times the key can be used. 1048 */ 1049 public static final int UNRESTRICTED_USAGE_COUNT = -1; 1050 } 1051