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