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