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.keystore.cts; 18 19 import android.content.Context; 20 import android.content.pm.PackageManager; 21 import android.content.pm.FeatureInfo; 22 import android.os.Build; 23 import android.os.SystemProperties; 24 import android.security.keystore.KeyGenParameterSpec; 25 import android.security.keystore.KeyInfo; 26 import android.security.keystore.KeyProperties; 27 import android.security.keystore.KeyProtection; 28 import android.test.MoreAsserts; 29 30 import com.android.internal.util.HexDump; 31 32 import junit.framework.Assert; 33 34 import java.io.ByteArrayOutputStream; 35 import java.io.IOException; 36 import java.io.InputStream; 37 import java.math.BigInteger; 38 import java.security.Key; 39 import java.security.KeyFactory; 40 import java.security.KeyPair; 41 import java.security.KeyPairGenerator; 42 import java.security.KeyPairGeneratorSpi; 43 import java.security.KeyStore; 44 import java.security.KeyStoreException; 45 import java.security.MessageDigest; 46 import java.security.NoSuchAlgorithmException; 47 import java.security.NoSuchProviderException; 48 import java.security.PrivateKey; 49 import java.security.ProviderException; 50 import java.security.PublicKey; 51 import java.security.UnrecoverableEntryException; 52 import java.security.cert.Certificate; 53 import java.security.cert.CertificateFactory; 54 import java.security.cert.X509Certificate; 55 import java.security.interfaces.ECKey; 56 import java.security.interfaces.ECPrivateKey; 57 import java.security.interfaces.ECPublicKey; 58 import java.security.interfaces.RSAKey; 59 import java.security.interfaces.RSAPrivateKey; 60 import java.security.interfaces.RSAPublicKey; 61 import java.security.spec.ECParameterSpec; 62 import java.security.spec.EllipticCurve; 63 import java.security.spec.InvalidKeySpecException; 64 import java.security.spec.PKCS8EncodedKeySpec; 65 import java.util.ArrayList; 66 import java.util.Arrays; 67 import java.util.Collections; 68 import java.util.HashMap; 69 import java.util.List; 70 import java.util.Locale; 71 import java.util.Map; 72 import java.security.SecureRandom; 73 74 import javax.crypto.SecretKey; 75 import javax.crypto.SecretKeyFactory; 76 import javax.crypto.spec.SecretKeySpec; 77 78 abstract class TestUtils extends Assert { 79 80 static final String EXPECTED_CRYPTO_OP_PROVIDER_NAME = "AndroidKeyStoreBCWorkaround"; 81 static final String EXPECTED_PROVIDER_NAME = "AndroidKeyStore"; 82 83 static final long DAY_IN_MILLIS = 1000 * 60 * 60 * 24; 84 TestUtils()85 private TestUtils() {} 86 87 // Returns 0 if not implemented. Otherwise returns the feature version. 88 // getFeatureVersionKeystore(Context appContext)89 static int getFeatureVersionKeystore(Context appContext) { 90 PackageManager pm = appContext.getPackageManager(); 91 92 int featureVersionFromPm = 0; 93 if (pm.hasSystemFeature(PackageManager.FEATURE_HARDWARE_KEYSTORE)) { 94 FeatureInfo info = null; 95 FeatureInfo[] infos = pm.getSystemAvailableFeatures(); 96 for (int n = 0; n < infos.length; n++) { 97 FeatureInfo i = infos[n]; 98 if (i.name.equals(PackageManager.FEATURE_HARDWARE_KEYSTORE)) { 99 info = i; 100 break; 101 } 102 } 103 if (info != null) { 104 featureVersionFromPm = info.version; 105 } 106 } 107 108 return featureVersionFromPm; 109 } 110 111 // Returns 0 if not implemented. Otherwise returns the feature version. 112 // getFeatureVersionKeystoreStrongBox(Context appContext)113 static int getFeatureVersionKeystoreStrongBox(Context appContext) { 114 PackageManager pm = appContext.getPackageManager(); 115 116 int featureVersionFromPm = 0; 117 if (pm.hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE)) { 118 FeatureInfo info = null; 119 FeatureInfo[] infos = pm.getSystemAvailableFeatures(); 120 for (int n = 0; n < infos.length; n++) { 121 FeatureInfo i = infos[n]; 122 if (i.name.equals(PackageManager.FEATURE_STRONGBOX_KEYSTORE)) { 123 info = i; 124 break; 125 } 126 } 127 if (info != null) { 128 featureVersionFromPm = info.version; 129 } 130 } 131 132 return featureVersionFromPm; 133 } 134 135 /** 136 * Returns whether 3DES KeyStore tests should run on this device. 3DES support was added in 137 * KeyMaster 4.0 and there should be no software fallback on earlier KeyMaster versions. 138 */ supports3DES()139 static boolean supports3DES() { 140 return "true".equals(SystemProperties.get("ro.hardware.keystore_desede")); 141 } 142 143 /** 144 * Returns whether the device has a StrongBox backed KeyStore. 145 */ hasStrongBox(Context context)146 static boolean hasStrongBox(Context context) { 147 return context.getPackageManager() 148 .hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE); 149 } 150 151 /** 152 * Asserts the the key algorithm and algorithm-specific parameters of the two keys in the 153 * provided pair match. 154 */ assertKeyPairSelfConsistent(KeyPair keyPair)155 static void assertKeyPairSelfConsistent(KeyPair keyPair) { 156 assertKeyPairSelfConsistent(keyPair.getPublic(), keyPair.getPrivate()); 157 } 158 159 /** 160 * Asserts the the key algorithm and public algorithm-specific parameters of the two provided 161 * keys match. 162 */ assertKeyPairSelfConsistent(PublicKey publicKey, PrivateKey privateKey)163 static void assertKeyPairSelfConsistent(PublicKey publicKey, PrivateKey privateKey) { 164 assertNotNull(publicKey); 165 assertNotNull(privateKey); 166 assertEquals(publicKey.getAlgorithm(), privateKey.getAlgorithm()); 167 String keyAlgorithm = publicKey.getAlgorithm(); 168 if ("EC".equalsIgnoreCase(keyAlgorithm)) { 169 assertTrue("EC public key must be instanceof ECKey: " 170 + publicKey.getClass().getName(), 171 publicKey instanceof ECKey); 172 assertTrue("EC private key must be instanceof ECKey: " 173 + privateKey.getClass().getName(), 174 privateKey instanceof ECKey); 175 assertECParameterSpecEqualsIgnoreSeedIfNotPresent( 176 "Private key must have the same EC parameters as public key", 177 ((ECKey) publicKey).getParams(), ((ECKey) privateKey).getParams()); 178 } else if ("RSA".equalsIgnoreCase(keyAlgorithm)) { 179 assertTrue("RSA public key must be instance of RSAKey: " 180 + publicKey.getClass().getName(), 181 publicKey instanceof RSAKey); 182 assertTrue("RSA private key must be instance of RSAKey: " 183 + privateKey.getClass().getName(), 184 privateKey instanceof RSAKey); 185 assertEquals("Private and public key must have the same RSA modulus", 186 ((RSAKey) publicKey).getModulus(), ((RSAKey) privateKey).getModulus()); 187 } else { 188 fail("Unsuported key algorithm: " + keyAlgorithm); 189 } 190 } 191 getKeySizeBits(Key key)192 static int getKeySizeBits(Key key) { 193 if (key instanceof ECKey) { 194 return ((ECKey) key).getParams().getCurve().getField().getFieldSize(); 195 } else if (key instanceof RSAKey) { 196 return ((RSAKey) key).getModulus().bitLength(); 197 } else { 198 throw new IllegalArgumentException("Unsupported key type: " + key.getClass()); 199 } 200 } 201 assertKeySize(int expectedSizeBits, KeyPair keyPair)202 static void assertKeySize(int expectedSizeBits, KeyPair keyPair) { 203 assertEquals(expectedSizeBits, getKeySizeBits(keyPair.getPrivate())); 204 assertEquals(expectedSizeBits, getKeySizeBits(keyPair.getPublic())); 205 } 206 207 /** 208 * Asserts that the provided key pair is an Android Keystore key pair stored under the provided 209 * alias. 210 */ assertKeyStoreKeyPair(KeyStore keyStore, String alias, KeyPair keyPair)211 static void assertKeyStoreKeyPair(KeyStore keyStore, String alias, KeyPair keyPair) { 212 assertKeyMaterialExportable(keyPair.getPublic()); 213 assertKeyMaterialNotExportable(keyPair.getPrivate()); 214 assertTransparentKey(keyPair.getPublic()); 215 assertOpaqueKey(keyPair.getPrivate()); 216 217 KeyStore.Entry entry; 218 Certificate cert; 219 try { 220 entry = keyStore.getEntry(alias, null); 221 cert = keyStore.getCertificate(alias); 222 } catch (KeyStoreException | UnrecoverableEntryException | NoSuchAlgorithmException e) { 223 throw new RuntimeException("Failed to load entry: " + alias, e); 224 } 225 assertNotNull(entry); 226 227 assertTrue(entry instanceof KeyStore.PrivateKeyEntry); 228 KeyStore.PrivateKeyEntry privEntry = (KeyStore.PrivateKeyEntry) entry; 229 assertEquals(cert, privEntry.getCertificate()); 230 assertTrue("Certificate must be an X.509 certificate: " + cert.getClass(), 231 cert instanceof X509Certificate); 232 final X509Certificate x509Cert = (X509Certificate) cert; 233 234 PrivateKey keystorePrivateKey = privEntry.getPrivateKey(); 235 PublicKey keystorePublicKey = cert.getPublicKey(); 236 assertEquals(keyPair.getPrivate(), keystorePrivateKey); 237 assertTrue("Key1:\n" + HexDump.dumpHexString(keyPair.getPublic().getEncoded()) 238 + "\nKey2:\n" + HexDump.dumpHexString(keystorePublicKey.getEncoded()) + "\n", 239 Arrays.equals(keyPair.getPublic().getEncoded(), keystorePublicKey.getEncoded())); 240 241 242 assertEquals( 243 "Public key used to sign certificate should have the same algorithm as in KeyPair", 244 keystorePublicKey.getAlgorithm(), x509Cert.getPublicKey().getAlgorithm()); 245 246 Certificate[] chain = privEntry.getCertificateChain(); 247 if (chain.length == 0) { 248 fail("Empty certificate chain"); 249 return; 250 } 251 assertEquals(cert, chain[0]); 252 } 253 254 assertKeyMaterialExportable(Key key)255 private static void assertKeyMaterialExportable(Key key) { 256 if (key instanceof PublicKey) { 257 assertEquals("X.509", key.getFormat()); 258 } else if (key instanceof PrivateKey) { 259 assertEquals("PKCS#8", key.getFormat()); 260 } else if (key instanceof SecretKey) { 261 assertEquals("RAW", key.getFormat()); 262 } else { 263 fail("Unsupported key type: " + key.getClass().getName()); 264 } 265 byte[] encodedForm = key.getEncoded(); 266 assertNotNull(encodedForm); 267 if (encodedForm.length == 0) { 268 fail("Empty encoded form"); 269 } 270 } 271 assertKeyMaterialNotExportable(Key key)272 private static void assertKeyMaterialNotExportable(Key key) { 273 assertEquals(null, key.getFormat()); 274 assertEquals(null, key.getEncoded()); 275 } 276 assertOpaqueKey(Key key)277 private static void assertOpaqueKey(Key key) { 278 assertFalse(key.getClass().getName() + " is a transparent key", isTransparentKey(key)); 279 } 280 assertTransparentKey(Key key)281 private static void assertTransparentKey(Key key) { 282 assertTrue(key.getClass().getName() + " is not a transparent key", isTransparentKey(key)); 283 } 284 isTransparentKey(Key key)285 private static boolean isTransparentKey(Key key) { 286 if (key instanceof PrivateKey) { 287 return (key instanceof ECPrivateKey) || (key instanceof RSAPrivateKey); 288 } else if (key instanceof PublicKey) { 289 return (key instanceof ECPublicKey) || (key instanceof RSAPublicKey); 290 } else if (key instanceof SecretKey) { 291 return (key instanceof SecretKeySpec); 292 } else { 293 throw new IllegalArgumentException("Unsupported key type: " + key.getClass().getName()); 294 } 295 } 296 assertECParameterSpecEqualsIgnoreSeedIfNotPresent( ECParameterSpec expected, ECParameterSpec actual)297 static void assertECParameterSpecEqualsIgnoreSeedIfNotPresent( 298 ECParameterSpec expected, ECParameterSpec actual) { 299 assertECParameterSpecEqualsIgnoreSeedIfNotPresent(null, expected, actual); 300 } 301 assertECParameterSpecEqualsIgnoreSeedIfNotPresent(String message, ECParameterSpec expected, ECParameterSpec actual)302 static void assertECParameterSpecEqualsIgnoreSeedIfNotPresent(String message, 303 ECParameterSpec expected, ECParameterSpec actual) { 304 EllipticCurve expectedCurve = expected.getCurve(); 305 EllipticCurve actualCurve = actual.getCurve(); 306 String msgPrefix = (message != null) ? message + ": " : ""; 307 assertEquals(msgPrefix + "curve field", expectedCurve.getField(), actualCurve.getField()); 308 assertEquals(msgPrefix + "curve A", expectedCurve.getA(), actualCurve.getA()); 309 assertEquals(msgPrefix + "curve B", expectedCurve.getB(), actualCurve.getB()); 310 assertEquals(msgPrefix + "order", expected.getOrder(), actual.getOrder()); 311 assertEquals(msgPrefix + "generator", 312 expected.getGenerator(), actual.getGenerator()); 313 assertEquals(msgPrefix + "cofactor", expected.getCofactor(), actual.getCofactor()); 314 315 // If present, the seed must be the same 316 byte[] expectedSeed = expectedCurve.getSeed(); 317 byte[] actualSeed = expectedCurve.getSeed(); 318 if ((expectedSeed != null) && (actualSeed != null)) { 319 MoreAsserts.assertEquals(expectedSeed, actualSeed); 320 } 321 } 322 getKeyInfo(Key key)323 static KeyInfo getKeyInfo(Key key) throws InvalidKeySpecException, NoSuchAlgorithmException, 324 NoSuchProviderException { 325 if ((key instanceof PrivateKey) || (key instanceof PublicKey)) { 326 return KeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore") 327 .getKeySpec(key, KeyInfo.class); 328 } else if (key instanceof SecretKey) { 329 return (KeyInfo) SecretKeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore") 330 .getKeySpec((SecretKey) key, KeyInfo.class); 331 } else { 332 throw new IllegalArgumentException("Unexpected key type: " + key.getClass()); 333 } 334 } 335 assertContentsInAnyOrder(Iterable<T> actual, T... expected)336 static <T> void assertContentsInAnyOrder(Iterable<T> actual, T... expected) { 337 assertContentsInAnyOrder(null, actual, expected); 338 } 339 assertContentsInAnyOrder(String message, Iterable<T> actual, T... expected)340 static <T> void assertContentsInAnyOrder(String message, Iterable<T> actual, T... expected) { 341 Map<T, Integer> actualFreq = getFrequencyTable(actual); 342 Map<T, Integer> expectedFreq = getFrequencyTable(expected); 343 if (actualFreq.equals(expectedFreq)) { 344 return; 345 } 346 347 Map<T, Integer> extraneousFreq = new HashMap<T, Integer>(); 348 for (Map.Entry<T, Integer> actualEntry : actualFreq.entrySet()) { 349 int actualCount = actualEntry.getValue(); 350 Integer expectedCount = expectedFreq.get(actualEntry.getKey()); 351 int diff = actualCount - ((expectedCount != null) ? expectedCount : 0); 352 if (diff > 0) { 353 extraneousFreq.put(actualEntry.getKey(), diff); 354 } 355 } 356 357 Map<T, Integer> missingFreq = new HashMap<T, Integer>(); 358 for (Map.Entry<T, Integer> expectedEntry : expectedFreq.entrySet()) { 359 int expectedCount = expectedEntry.getValue(); 360 Integer actualCount = actualFreq.get(expectedEntry.getKey()); 361 int diff = expectedCount - ((actualCount != null) ? actualCount : 0); 362 if (diff > 0) { 363 missingFreq.put(expectedEntry.getKey(), diff); 364 } 365 } 366 367 List<T> extraneous = frequencyTableToValues(extraneousFreq); 368 List<T> missing = frequencyTableToValues(missingFreq); 369 StringBuilder result = new StringBuilder(); 370 String delimiter = ""; 371 if (message != null) { 372 result.append(message).append("."); 373 delimiter = " "; 374 } 375 if (!missing.isEmpty()) { 376 result.append(delimiter).append("missing: " + missing); 377 delimiter = ", "; 378 } 379 if (!extraneous.isEmpty()) { 380 result.append(delimiter).append("extraneous: " + extraneous); 381 } 382 fail(result.toString()); 383 } 384 getFrequencyTable(Iterable<T> values)385 private static <T> Map<T, Integer> getFrequencyTable(Iterable<T> values) { 386 Map<T, Integer> result = new HashMap<T, Integer>(); 387 for (T value : values) { 388 Integer count = result.get(value); 389 if (count == null) { 390 count = 1; 391 } else { 392 count++; 393 } 394 result.put(value, count); 395 } 396 return result; 397 } 398 getFrequencyTable(T... values)399 private static <T> Map<T, Integer> getFrequencyTable(T... values) { 400 Map<T, Integer> result = new HashMap<T, Integer>(); 401 for (T value : values) { 402 Integer count = result.get(value); 403 if (count == null) { 404 count = 1; 405 } else { 406 count++; 407 } 408 result.put(value, count); 409 } 410 return result; 411 } 412 413 @SuppressWarnings("rawtypes") frequencyTableToValues(Map<T, Integer> table)414 private static <T> List<T> frequencyTableToValues(Map<T, Integer> table) { 415 if (table.isEmpty()) { 416 return Collections.emptyList(); 417 } 418 419 List<T> result = new ArrayList<T>(); 420 boolean comparableValues = true; 421 for (Map.Entry<T, Integer> entry : table.entrySet()) { 422 T value = entry.getKey(); 423 if (!(value instanceof Comparable)) { 424 comparableValues = false; 425 } 426 int frequency = entry.getValue(); 427 for (int i = 0; i < frequency; i++) { 428 result.add(value); 429 } 430 } 431 432 if (comparableValues) { 433 sortAssumingComparable(result); 434 } 435 return result; 436 } 437 438 @SuppressWarnings({"rawtypes", "unchecked"}) sortAssumingComparable(List<?> values)439 private static void sortAssumingComparable(List<?> values) { 440 Collections.sort((List<Comparable>)values); 441 } 442 toLowerCase(String... values)443 static String[] toLowerCase(String... values) { 444 if (values == null) { 445 return null; 446 } 447 String[] result = new String[values.length]; 448 for (int i = 0; i < values.length; i++) { 449 String value = values[i]; 450 result[i] = (value != null) ? value.toLowerCase() : null; 451 } 452 return result; 453 } 454 getRawResPrivateKey(Context context, int resId)455 static PrivateKey getRawResPrivateKey(Context context, int resId) throws Exception { 456 byte[] pkcs8EncodedForm; 457 try (InputStream in = context.getResources().openRawResource(resId)) { 458 pkcs8EncodedForm = drain(in); 459 } 460 PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(pkcs8EncodedForm); 461 462 try { 463 return KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); 464 } catch (InvalidKeySpecException e) { 465 try { 466 return KeyFactory.getInstance("RSA").generatePrivate(privateKeySpec); 467 } catch (InvalidKeySpecException e2) { 468 throw new InvalidKeySpecException("The key is neither EC nor RSA", e); 469 } 470 } 471 } 472 getRawResX509Certificate(Context context, int resId)473 static X509Certificate getRawResX509Certificate(Context context, int resId) throws Exception { 474 try (InputStream in = context.getResources().openRawResource(resId)) { 475 return (X509Certificate) CertificateFactory.getInstance("X.509") 476 .generateCertificate(in); 477 } 478 } 479 importIntoAndroidKeyStore( String alias, PrivateKey privateKey, Certificate certificate, KeyProtection keyProtection)480 static KeyPair importIntoAndroidKeyStore( 481 String alias, 482 PrivateKey privateKey, 483 Certificate certificate, 484 KeyProtection keyProtection) throws Exception { 485 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 486 keyStore.load(null); 487 keyStore.setEntry(alias, 488 new KeyStore.PrivateKeyEntry(privateKey, new Certificate[] {certificate}), 489 keyProtection); 490 return new KeyPair( 491 keyStore.getCertificate(alias).getPublicKey(), 492 (PrivateKey) keyStore.getKey(alias, null)); 493 } 494 importIntoAndroidKeyStore( String alias, SecretKey key, KeyProtection keyProtection)495 static ImportedKey importIntoAndroidKeyStore( 496 String alias, 497 SecretKey key, 498 KeyProtection keyProtection) throws Exception { 499 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 500 keyStore.load(null); 501 keyStore.setEntry(alias, 502 new KeyStore.SecretKeyEntry(key), 503 keyProtection); 504 return new ImportedKey(alias, key, (SecretKey) keyStore.getKey(alias, null)); 505 } 506 importIntoAndroidKeyStore( String alias, Context context, int privateResId, int certResId, KeyProtection params)507 static ImportedKey importIntoAndroidKeyStore( 508 String alias, Context context, int privateResId, int certResId, KeyProtection params) 509 throws Exception { 510 Certificate originalCert = TestUtils.getRawResX509Certificate(context, certResId); 511 PublicKey originalPublicKey = originalCert.getPublicKey(); 512 PrivateKey originalPrivateKey = TestUtils.getRawResPrivateKey(context, privateResId); 513 514 // Check that the domain parameters match between the private key and the public key. This 515 // is to catch accidental errors where a test provides the wrong resource ID as one of the 516 // parameters. 517 if (!originalPublicKey.getAlgorithm().equalsIgnoreCase(originalPrivateKey.getAlgorithm())) { 518 throw new IllegalArgumentException("Key algorithm mismatch." 519 + " Public: " + originalPublicKey.getAlgorithm() 520 + ", private: " + originalPrivateKey.getAlgorithm()); 521 } 522 assertKeyPairSelfConsistent(originalPublicKey, originalPrivateKey); 523 524 KeyPair keystoreBacked = TestUtils.importIntoAndroidKeyStore( 525 alias, originalPrivateKey, originalCert, 526 params); 527 assertKeyPairSelfConsistent(keystoreBacked); 528 assertKeyPairSelfConsistent(keystoreBacked.getPublic(), originalPrivateKey); 529 return new ImportedKey( 530 alias, 531 new KeyPair(originalCert.getPublicKey(), originalPrivateKey), 532 keystoreBacked); 533 } 534 drain(InputStream in)535 static byte[] drain(InputStream in) throws IOException { 536 ByteArrayOutputStream result = new ByteArrayOutputStream(); 537 byte[] buffer = new byte[16 * 1024]; 538 int chunkSize; 539 while ((chunkSize = in.read(buffer)) != -1) { 540 result.write(buffer, 0, chunkSize); 541 } 542 return result.toByteArray(); 543 } 544 buildUpon(KeyProtection params)545 static KeyProtection.Builder buildUpon(KeyProtection params) { 546 return buildUponInternal(params, null); 547 } 548 buildUpon(KeyProtection params, int newPurposes)549 static KeyProtection.Builder buildUpon(KeyProtection params, int newPurposes) { 550 return buildUponInternal(params, newPurposes); 551 } 552 buildUpon( KeyProtection.Builder builder)553 static KeyProtection.Builder buildUpon( 554 KeyProtection.Builder builder) { 555 return buildUponInternal(builder.build(), null); 556 } 557 buildUpon( KeyProtection.Builder builder, int newPurposes)558 static KeyProtection.Builder buildUpon( 559 KeyProtection.Builder builder, int newPurposes) { 560 return buildUponInternal(builder.build(), newPurposes); 561 } 562 buildUponInternal( KeyProtection spec, Integer newPurposes)563 private static KeyProtection.Builder buildUponInternal( 564 KeyProtection spec, Integer newPurposes) { 565 int purposes = (newPurposes == null) ? spec.getPurposes() : newPurposes; 566 KeyProtection.Builder result = new KeyProtection.Builder(purposes); 567 result.setBlockModes(spec.getBlockModes()); 568 if (spec.isDigestsSpecified()) { 569 result.setDigests(spec.getDigests()); 570 } 571 result.setEncryptionPaddings(spec.getEncryptionPaddings()); 572 result.setSignaturePaddings(spec.getSignaturePaddings()); 573 result.setKeyValidityStart(spec.getKeyValidityStart()); 574 result.setKeyValidityForOriginationEnd(spec.getKeyValidityForOriginationEnd()); 575 result.setKeyValidityForConsumptionEnd(spec.getKeyValidityForConsumptionEnd()); 576 result.setRandomizedEncryptionRequired(spec.isRandomizedEncryptionRequired()); 577 result.setUserAuthenticationRequired(spec.isUserAuthenticationRequired()); 578 result.setUserAuthenticationValidityDurationSeconds( 579 spec.getUserAuthenticationValidityDurationSeconds()); 580 result.setBoundToSpecificSecureUserId(spec.getBoundToSpecificSecureUserId()); 581 return result; 582 } 583 buildUpon(KeyGenParameterSpec spec)584 static KeyGenParameterSpec.Builder buildUpon(KeyGenParameterSpec spec) { 585 return buildUponInternal(spec, null); 586 } 587 buildUpon(KeyGenParameterSpec spec, int newPurposes)588 static KeyGenParameterSpec.Builder buildUpon(KeyGenParameterSpec spec, int newPurposes) { 589 return buildUponInternal(spec, newPurposes); 590 } 591 buildUpon( KeyGenParameterSpec.Builder builder)592 static KeyGenParameterSpec.Builder buildUpon( 593 KeyGenParameterSpec.Builder builder) { 594 return buildUponInternal(builder.build(), null); 595 } 596 buildUpon( KeyGenParameterSpec.Builder builder, int newPurposes)597 static KeyGenParameterSpec.Builder buildUpon( 598 KeyGenParameterSpec.Builder builder, int newPurposes) { 599 return buildUponInternal(builder.build(), newPurposes); 600 } 601 buildUponInternal( KeyGenParameterSpec spec, Integer newPurposes)602 private static KeyGenParameterSpec.Builder buildUponInternal( 603 KeyGenParameterSpec spec, Integer newPurposes) { 604 int purposes = (newPurposes == null) ? spec.getPurposes() : newPurposes; 605 KeyGenParameterSpec.Builder result = 606 new KeyGenParameterSpec.Builder(spec.getKeystoreAlias(), purposes); 607 if (spec.getKeySize() >= 0) { 608 result.setKeySize(spec.getKeySize()); 609 } 610 if (spec.getAlgorithmParameterSpec() != null) { 611 result.setAlgorithmParameterSpec(spec.getAlgorithmParameterSpec()); 612 } 613 result.setCertificateNotBefore(spec.getCertificateNotBefore()); 614 result.setCertificateNotAfter(spec.getCertificateNotAfter()); 615 result.setCertificateSerialNumber(spec.getCertificateSerialNumber()); 616 result.setCertificateSubject(spec.getCertificateSubject()); 617 result.setBlockModes(spec.getBlockModes()); 618 if (spec.isDigestsSpecified()) { 619 result.setDigests(spec.getDigests()); 620 } 621 result.setEncryptionPaddings(spec.getEncryptionPaddings()); 622 result.setSignaturePaddings(spec.getSignaturePaddings()); 623 result.setKeyValidityStart(spec.getKeyValidityStart()); 624 result.setKeyValidityForOriginationEnd(spec.getKeyValidityForOriginationEnd()); 625 result.setKeyValidityForConsumptionEnd(spec.getKeyValidityForConsumptionEnd()); 626 result.setRandomizedEncryptionRequired(spec.isRandomizedEncryptionRequired()); 627 result.setUserAuthenticationRequired(spec.isUserAuthenticationRequired()); 628 result.setUserAuthenticationValidityDurationSeconds( 629 spec.getUserAuthenticationValidityDurationSeconds()); 630 return result; 631 } 632 getKeyPairForKeyAlgorithm(String keyAlgorithm, Iterable<KeyPair> keyPairs)633 static KeyPair getKeyPairForKeyAlgorithm(String keyAlgorithm, Iterable<KeyPair> keyPairs) { 634 for (KeyPair keyPair : keyPairs) { 635 if (keyAlgorithm.equalsIgnoreCase(keyPair.getPublic().getAlgorithm())) { 636 return keyPair; 637 } 638 } 639 throw new IllegalArgumentException("No KeyPair for key algorithm " + keyAlgorithm); 640 } 641 getKeyForKeyAlgorithm(String keyAlgorithm, Iterable<? extends Key> keys)642 static Key getKeyForKeyAlgorithm(String keyAlgorithm, Iterable<? extends Key> keys) { 643 for (Key key : keys) { 644 if (keyAlgorithm.equalsIgnoreCase(key.getAlgorithm())) { 645 return key; 646 } 647 } 648 throw new IllegalArgumentException("No Key for key algorithm " + keyAlgorithm); 649 } 650 generateLargeKatMsg(byte[] seed, int msgSizeBytes)651 static byte[] generateLargeKatMsg(byte[] seed, int msgSizeBytes) throws Exception { 652 byte[] result = new byte[msgSizeBytes]; 653 MessageDigest digest = MessageDigest.getInstance("SHA-512"); 654 int resultOffset = 0; 655 int resultRemaining = msgSizeBytes; 656 while (resultRemaining > 0) { 657 seed = digest.digest(seed); 658 int chunkSize = Math.min(seed.length, resultRemaining); 659 System.arraycopy(seed, 0, result, resultOffset, chunkSize); 660 resultOffset += chunkSize; 661 resultRemaining -= chunkSize; 662 } 663 return result; 664 } 665 leftPadWithZeroBytes(byte[] array, int length)666 static byte[] leftPadWithZeroBytes(byte[] array, int length) { 667 if (array.length >= length) { 668 return array; 669 } 670 byte[] result = new byte[length]; 671 System.arraycopy(array, 0, result, result.length - array.length, array.length); 672 return result; 673 } 674 contains(int[] array, int value)675 static boolean contains(int[] array, int value) { 676 for (int element : array) { 677 if (element == value) { 678 return true; 679 } 680 } 681 return false; 682 } 683 isHmacAlgorithm(String algorithm)684 static boolean isHmacAlgorithm(String algorithm) { 685 return algorithm.toUpperCase(Locale.US).startsWith("HMAC"); 686 } 687 getHmacAlgorithmDigest(String algorithm)688 static String getHmacAlgorithmDigest(String algorithm) { 689 String algorithmUpperCase = algorithm.toUpperCase(Locale.US); 690 if (!algorithmUpperCase.startsWith("HMAC")) { 691 return null; 692 } 693 String result = algorithmUpperCase.substring("HMAC".length()); 694 if (result.startsWith("SHA")) { 695 result = "SHA-" + result.substring("SHA".length()); 696 } 697 return result; 698 } 699 getKeyAlgorithm(String transformation)700 static String getKeyAlgorithm(String transformation) { 701 try { 702 return getCipherKeyAlgorithm(transformation); 703 } catch (IllegalArgumentException e) { 704 705 } 706 try { 707 return getSignatureAlgorithmKeyAlgorithm(transformation); 708 } catch (IllegalArgumentException e) { 709 710 } 711 String transformationUpperCase = transformation.toUpperCase(Locale.US); 712 if (transformationUpperCase.equals("EC")) { 713 return KeyProperties.KEY_ALGORITHM_EC; 714 } 715 if (transformationUpperCase.equals("RSA")) { 716 return KeyProperties.KEY_ALGORITHM_RSA; 717 } 718 if (transformationUpperCase.equals("DESEDE")) { 719 return KeyProperties.KEY_ALGORITHM_3DES; 720 } 721 if (transformationUpperCase.equals("AES")) { 722 return KeyProperties.KEY_ALGORITHM_AES; 723 } 724 if (transformationUpperCase.startsWith("HMAC")) { 725 if (transformation.endsWith("SHA1")) { 726 return KeyProperties.KEY_ALGORITHM_HMAC_SHA1; 727 } else if (transformation.endsWith("SHA224")) { 728 return KeyProperties.KEY_ALGORITHM_HMAC_SHA224; 729 } else if (transformation.endsWith("SHA256")) { 730 return KeyProperties.KEY_ALGORITHM_HMAC_SHA256; 731 } else if (transformation.endsWith("SHA384")) { 732 return KeyProperties.KEY_ALGORITHM_HMAC_SHA384; 733 } else if (transformation.endsWith("SHA512")) { 734 return KeyProperties.KEY_ALGORITHM_HMAC_SHA512; 735 } 736 } 737 throw new IllegalArgumentException("Unsupported transformation: " + transformation); 738 } 739 getCipherKeyAlgorithm(String transformation)740 static String getCipherKeyAlgorithm(String transformation) { 741 String transformationUpperCase = transformation.toUpperCase(Locale.US); 742 if (transformationUpperCase.startsWith("AES/")) { 743 return KeyProperties.KEY_ALGORITHM_AES; 744 } else if (transformationUpperCase.startsWith("DESEDE/")) { 745 return KeyProperties.KEY_ALGORITHM_3DES; 746 } else if (transformationUpperCase.startsWith("RSA/")) { 747 return KeyProperties.KEY_ALGORITHM_RSA; 748 } else { 749 throw new IllegalArgumentException("Unsupported transformation: " + transformation); 750 } 751 } 752 isCipherSymmetric(String transformation)753 static boolean isCipherSymmetric(String transformation) { 754 String transformationUpperCase = transformation.toUpperCase(Locale.US); 755 if (transformationUpperCase.startsWith("AES/") || transformationUpperCase.startsWith( 756 "DESEDE/")) { 757 return true; 758 } else if (transformationUpperCase.startsWith("RSA/")) { 759 return false; 760 } else { 761 throw new IllegalArgumentException("YYZ: Unsupported transformation: " + transformation); 762 } 763 } 764 getCipherDigest(String transformation)765 static String getCipherDigest(String transformation) { 766 String transformationUpperCase = transformation.toUpperCase(Locale.US); 767 if (transformationUpperCase.contains("/OAEP")) { 768 if (transformationUpperCase.endsWith("/OAEPPADDING")) { 769 return KeyProperties.DIGEST_SHA1; 770 } else if (transformationUpperCase.endsWith( 771 "/OAEPWITHSHA-1ANDMGF1PADDING")) { 772 return KeyProperties.DIGEST_SHA1; 773 } else if (transformationUpperCase.endsWith( 774 "/OAEPWITHSHA-224ANDMGF1PADDING")) { 775 return KeyProperties.DIGEST_SHA224; 776 } else if (transformationUpperCase.endsWith( 777 "/OAEPWITHSHA-256ANDMGF1PADDING")) { 778 return KeyProperties.DIGEST_SHA256; 779 } else if (transformationUpperCase.endsWith( 780 "/OAEPWITHSHA-384ANDMGF1PADDING")) { 781 return KeyProperties.DIGEST_SHA384; 782 } else if (transformationUpperCase.endsWith( 783 "/OAEPWITHSHA-512ANDMGF1PADDING")) { 784 return KeyProperties.DIGEST_SHA512; 785 } else { 786 throw new RuntimeException("Unsupported OAEP padding scheme: " 787 + transformation); 788 } 789 } else { 790 return null; 791 } 792 } 793 getCipherEncryptionPadding(String transformation)794 static String getCipherEncryptionPadding(String transformation) { 795 String transformationUpperCase = transformation.toUpperCase(Locale.US); 796 if (transformationUpperCase.endsWith("/NOPADDING")) { 797 return KeyProperties.ENCRYPTION_PADDING_NONE; 798 } else if (transformationUpperCase.endsWith("/PKCS7PADDING")) { 799 return KeyProperties.ENCRYPTION_PADDING_PKCS7; 800 } else if (transformationUpperCase.endsWith("/PKCS1PADDING")) { 801 return KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1; 802 } else if (transformationUpperCase.split("/")[2].startsWith("OAEP")) { 803 return KeyProperties.ENCRYPTION_PADDING_RSA_OAEP; 804 } else { 805 throw new IllegalArgumentException("Unsupported transformation: " + transformation); 806 } 807 } 808 getCipherBlockMode(String transformation)809 static String getCipherBlockMode(String transformation) { 810 return transformation.split("/")[1].toUpperCase(Locale.US); 811 } 812 getSignatureAlgorithmDigest(String algorithm)813 static String getSignatureAlgorithmDigest(String algorithm) { 814 String algorithmUpperCase = algorithm.toUpperCase(Locale.US); 815 int withIndex = algorithmUpperCase.indexOf("WITH"); 816 if (withIndex == -1) { 817 throw new IllegalArgumentException("Unsupported algorithm: " + algorithm); 818 } 819 String digest = algorithmUpperCase.substring(0, withIndex); 820 if (digest.startsWith("SHA")) { 821 digest = "SHA-" + digest.substring("SHA".length()); 822 } 823 return digest; 824 } 825 getSignatureAlgorithmPadding(String algorithm)826 static String getSignatureAlgorithmPadding(String algorithm) { 827 String algorithmUpperCase = algorithm.toUpperCase(Locale.US); 828 if (algorithmUpperCase.endsWith("WITHECDSA")) { 829 return null; 830 } else if (algorithmUpperCase.endsWith("WITHRSA")) { 831 return KeyProperties.SIGNATURE_PADDING_RSA_PKCS1; 832 } else if (algorithmUpperCase.endsWith("WITHRSA/PSS")) { 833 return KeyProperties.SIGNATURE_PADDING_RSA_PSS; 834 } else { 835 throw new IllegalArgumentException("Unsupported algorithm: " + algorithm); 836 } 837 } 838 getSignatureAlgorithmKeyAlgorithm(String algorithm)839 static String getSignatureAlgorithmKeyAlgorithm(String algorithm) { 840 String algorithmUpperCase = algorithm.toUpperCase(Locale.US); 841 if (algorithmUpperCase.endsWith("WITHECDSA")) { 842 return KeyProperties.KEY_ALGORITHM_EC; 843 } else if ((algorithmUpperCase.endsWith("WITHRSA")) 844 || (algorithmUpperCase.endsWith("WITHRSA/PSS"))) { 845 return KeyProperties.KEY_ALGORITHM_RSA; 846 } else { 847 throw new IllegalArgumentException("Unsupported algorithm: " + algorithm); 848 } 849 } 850 isKeyLongEnoughForSignatureAlgorithm(String algorithm, int keySizeBits)851 static boolean isKeyLongEnoughForSignatureAlgorithm(String algorithm, int keySizeBits) { 852 String keyAlgorithm = getSignatureAlgorithmKeyAlgorithm(algorithm); 853 if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) { 854 // No length restrictions for ECDSA 855 return true; 856 } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) { 857 String digest = getSignatureAlgorithmDigest(algorithm); 858 int digestOutputSizeBits = getDigestOutputSizeBits(digest); 859 if (digestOutputSizeBits == -1) { 860 // No digesting -- assume the key is long enough for the message 861 return true; 862 } 863 String paddingScheme = getSignatureAlgorithmPadding(algorithm); 864 int paddingOverheadBytes; 865 if (KeyProperties.SIGNATURE_PADDING_RSA_PKCS1.equalsIgnoreCase(paddingScheme)) { 866 paddingOverheadBytes = 30; 867 } else if (KeyProperties.SIGNATURE_PADDING_RSA_PSS.equalsIgnoreCase(paddingScheme)) { 868 int saltSizeBytes = (digestOutputSizeBits + 7) / 8; 869 paddingOverheadBytes = saltSizeBytes + 1; 870 } else { 871 throw new IllegalArgumentException( 872 "Unsupported signature padding scheme: " + paddingScheme); 873 } 874 int minKeySizeBytes = paddingOverheadBytes + (digestOutputSizeBits + 7) / 8 + 1; 875 int keySizeBytes = keySizeBits / 8; 876 return keySizeBytes >= minKeySizeBytes; 877 } else { 878 throw new IllegalArgumentException("Unsupported key algorithm: " + keyAlgorithm); 879 } 880 } 881 isKeyLongEnoughForSignatureAlgorithm(String algorithm, Key key)882 static boolean isKeyLongEnoughForSignatureAlgorithm(String algorithm, Key key) { 883 return isKeyLongEnoughForSignatureAlgorithm(algorithm, getKeySizeBits(key)); 884 } 885 getMaxSupportedPlaintextInputSizeBytes(String transformation, int keySizeBits)886 static int getMaxSupportedPlaintextInputSizeBytes(String transformation, int keySizeBits) { 887 String encryptionPadding = getCipherEncryptionPadding(transformation); 888 int modulusSizeBytes = (keySizeBits + 7) / 8; 889 if (KeyProperties.ENCRYPTION_PADDING_NONE.equalsIgnoreCase(encryptionPadding)) { 890 return modulusSizeBytes - 1; 891 } else if (KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1.equalsIgnoreCase( 892 encryptionPadding)) { 893 return modulusSizeBytes - 11; 894 } else if (KeyProperties.ENCRYPTION_PADDING_RSA_OAEP.equalsIgnoreCase( 895 encryptionPadding)) { 896 String digest = getCipherDigest(transformation); 897 int digestOutputSizeBytes = (getDigestOutputSizeBits(digest) + 7) / 8; 898 return modulusSizeBytes - 2 * digestOutputSizeBytes - 2; 899 } else { 900 throw new IllegalArgumentException( 901 "Unsupported encryption padding scheme: " + encryptionPadding); 902 } 903 904 } 905 getMaxSupportedPlaintextInputSizeBytes(String transformation, Key key)906 static int getMaxSupportedPlaintextInputSizeBytes(String transformation, Key key) { 907 String keyAlgorithm = getCipherKeyAlgorithm(transformation); 908 if (KeyProperties.KEY_ALGORITHM_AES.equalsIgnoreCase(keyAlgorithm) 909 || KeyProperties.KEY_ALGORITHM_3DES.equalsIgnoreCase(keyAlgorithm)) { 910 return Integer.MAX_VALUE; 911 } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) { 912 return getMaxSupportedPlaintextInputSizeBytes(transformation, getKeySizeBits(key)); 913 } else { 914 throw new IllegalArgumentException("Unsupported key algorithm: " + keyAlgorithm); 915 } 916 } 917 getDigestOutputSizeBits(String digest)918 static int getDigestOutputSizeBits(String digest) { 919 if (KeyProperties.DIGEST_NONE.equals(digest)) { 920 return -1; 921 } else if (KeyProperties.DIGEST_MD5.equals(digest)) { 922 return 128; 923 } else if (KeyProperties.DIGEST_SHA1.equals(digest)) { 924 return 160; 925 } else if (KeyProperties.DIGEST_SHA224.equals(digest)) { 926 return 224; 927 } else if (KeyProperties.DIGEST_SHA256.equals(digest)) { 928 return 256; 929 } else if (KeyProperties.DIGEST_SHA384.equals(digest)) { 930 return 384; 931 } else if (KeyProperties.DIGEST_SHA512.equals(digest)) { 932 return 512; 933 } else { 934 throw new IllegalArgumentException("Unsupported digest: " + digest); 935 } 936 } 937 concat(byte[] arr1, byte[] arr2)938 static byte[] concat(byte[] arr1, byte[] arr2) { 939 return concat(arr1, 0, (arr1 != null) ? arr1.length : 0, 940 arr2, 0, (arr2 != null) ? arr2.length : 0); 941 } 942 concat(byte[] arr1, int offset1, int len1, byte[] arr2, int offset2, int len2)943 static byte[] concat(byte[] arr1, int offset1, int len1, 944 byte[] arr2, int offset2, int len2) { 945 if (len1 == 0) { 946 return subarray(arr2, offset2, len2); 947 } else if (len2 == 0) { 948 return subarray(arr1, offset1, len1); 949 } 950 byte[] result = new byte[len1 + len2]; 951 if (len1 > 0) { 952 System.arraycopy(arr1, offset1, result, 0, len1); 953 } 954 if (len2 > 0) { 955 System.arraycopy(arr2, offset2, result, len1, len2); 956 } 957 return result; 958 } 959 subarray(byte[] arr, int offset, int len)960 static byte[] subarray(byte[] arr, int offset, int len) { 961 if (len == 0) { 962 return EmptyArray.BYTE; 963 } 964 if ((offset == 0) && (arr.length == len)) { 965 return arr; 966 } 967 byte[] result = new byte[len]; 968 System.arraycopy(arr, offset, result, 0, len); 969 return result; 970 } 971 getMinimalWorkingImportParametersForSigningingWith( String signatureAlgorithm)972 static KeyProtection getMinimalWorkingImportParametersForSigningingWith( 973 String signatureAlgorithm) { 974 String keyAlgorithm = getSignatureAlgorithmKeyAlgorithm(signatureAlgorithm); 975 String digest = getSignatureAlgorithmDigest(signatureAlgorithm); 976 if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) { 977 return new KeyProtection.Builder(KeyProperties.PURPOSE_SIGN) 978 .setDigests(digest) 979 .build(); 980 } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) { 981 String padding = getSignatureAlgorithmPadding(signatureAlgorithm); 982 return new KeyProtection.Builder(KeyProperties.PURPOSE_SIGN) 983 .setDigests(digest) 984 .setSignaturePaddings(padding) 985 .build(); 986 } else { 987 throw new IllegalArgumentException( 988 "Unsupported signature algorithm: " + signatureAlgorithm); 989 } 990 } 991 getMinimalWorkingImportParametersWithLimitedUsageForSigningingWith( String signatureAlgorithm, int maxUsageCount)992 static KeyProtection getMinimalWorkingImportParametersWithLimitedUsageForSigningingWith( 993 String signatureAlgorithm, int maxUsageCount) { 994 String keyAlgorithm = getSignatureAlgorithmKeyAlgorithm(signatureAlgorithm); 995 String digest = getSignatureAlgorithmDigest(signatureAlgorithm); 996 if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) { 997 return new KeyProtection.Builder(KeyProperties.PURPOSE_SIGN) 998 .setDigests(digest) 999 .setMaxUsageCount(maxUsageCount) 1000 .build(); 1001 } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) { 1002 String padding = getSignatureAlgorithmPadding(signatureAlgorithm); 1003 return new KeyProtection.Builder(KeyProperties.PURPOSE_SIGN) 1004 .setDigests(digest) 1005 .setSignaturePaddings(padding) 1006 .setMaxUsageCount(maxUsageCount) 1007 .build(); 1008 } else { 1009 throw new IllegalArgumentException( 1010 "Unsupported signature algorithm: " + signatureAlgorithm); 1011 } 1012 } 1013 getMinimalWorkingImportParametersForCipheringWith( String transformation, int purposes)1014 static KeyProtection getMinimalWorkingImportParametersForCipheringWith( 1015 String transformation, int purposes) { 1016 return getMinimalWorkingImportParametersForCipheringWith(transformation, purposes, false); 1017 } 1018 getMinimalWorkingImportParametersForCipheringWith( String transformation, int purposes, boolean ivProvidedWhenEncrypting)1019 static KeyProtection getMinimalWorkingImportParametersForCipheringWith( 1020 String transformation, int purposes, boolean ivProvidedWhenEncrypting) { 1021 return getMinimalWorkingImportParametersForCipheringWith(transformation, purposes, 1022 ivProvidedWhenEncrypting, false, false); 1023 } 1024 getMinimalWorkingImportParametersForCipheringWith( String transformation, int purposes, boolean ivProvidedWhenEncrypting, boolean isUnlockedDeviceRequired, boolean isUserAuthRequired)1025 static KeyProtection getMinimalWorkingImportParametersForCipheringWith( 1026 String transformation, int purposes, boolean ivProvidedWhenEncrypting, 1027 boolean isUnlockedDeviceRequired, boolean isUserAuthRequired) { 1028 String keyAlgorithm = TestUtils.getCipherKeyAlgorithm(transformation); 1029 if (KeyProperties.KEY_ALGORITHM_AES.equalsIgnoreCase(keyAlgorithm) 1030 || KeyProperties.KEY_ALGORITHM_3DES.equalsIgnoreCase(keyAlgorithm)) { 1031 String encryptionPadding = TestUtils.getCipherEncryptionPadding(transformation); 1032 String blockMode = TestUtils.getCipherBlockMode(transformation); 1033 boolean randomizedEncryptionRequired = true; 1034 if (KeyProperties.BLOCK_MODE_ECB.equalsIgnoreCase(blockMode)) { 1035 randomizedEncryptionRequired = false; 1036 } else if ((ivProvidedWhenEncrypting) 1037 && ((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0)) { 1038 randomizedEncryptionRequired = false; 1039 } 1040 return new KeyProtection.Builder( 1041 purposes) 1042 .setBlockModes(blockMode) 1043 .setEncryptionPaddings(encryptionPadding) 1044 .setRandomizedEncryptionRequired(randomizedEncryptionRequired) 1045 .setUnlockedDeviceRequired(isUnlockedDeviceRequired) 1046 .setUserAuthenticationRequired(isUserAuthRequired) 1047 .setUserAuthenticationValidityDurationSeconds(3600) 1048 .build(); 1049 } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) { 1050 String digest = TestUtils.getCipherDigest(transformation); 1051 String encryptionPadding = TestUtils.getCipherEncryptionPadding(transformation); 1052 boolean randomizedEncryptionRequired = 1053 !KeyProperties.ENCRYPTION_PADDING_NONE.equalsIgnoreCase(encryptionPadding); 1054 return new KeyProtection.Builder( 1055 purposes) 1056 .setDigests((digest != null) ? new String[] {digest} : EmptyArray.STRING) 1057 .setEncryptionPaddings(encryptionPadding) 1058 .setRandomizedEncryptionRequired(randomizedEncryptionRequired) 1059 .setUserAuthenticationRequired(isUserAuthRequired) 1060 .setUserAuthenticationValidityDurationSeconds(3600) 1061 .setUnlockedDeviceRequired(isUnlockedDeviceRequired) 1062 .build(); 1063 } else { 1064 throw new IllegalArgumentException("Unsupported key algorithm: " + keyAlgorithm); 1065 } 1066 } 1067 getBigIntegerMagnitudeBytes(BigInteger value)1068 static byte[] getBigIntegerMagnitudeBytes(BigInteger value) { 1069 return removeLeadingZeroByteIfPresent(value.toByteArray()); 1070 } 1071 removeLeadingZeroByteIfPresent(byte[] value)1072 private static byte[] removeLeadingZeroByteIfPresent(byte[] value) { 1073 if ((value.length < 1) || (value[0] != 0)) { 1074 return value; 1075 } 1076 return TestUtils.subarray(value, 1, value.length - 1); 1077 } 1078 generateRandomMessage(int messageSize)1079 static byte[] generateRandomMessage(int messageSize) { 1080 byte[] message = new byte[messageSize]; 1081 new SecureRandom().nextBytes(message); 1082 return message; 1083 } 1084 isAttestationSupported()1085 public static boolean isAttestationSupported() { 1086 return Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.O; 1087 } 1088 } 1089