1 /* 2 * Copyright 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 static com.google.common.truth.Truth.assertThat; 20 21 import static org.junit.Assert.assertArrayEquals; 22 import static org.junit.Assert.assertEquals; 23 import static org.junit.Assert.assertFalse; 24 import static org.junit.Assert.assertNotNull; 25 import static org.junit.Assert.assertSame; 26 import static org.junit.Assert.assertTrue; 27 import static org.junit.Assert.fail; 28 29 import android.app.KeyguardManager; 30 import android.content.Context; 31 import android.content.pm.PackageManager; 32 import android.keystore.cts.util.EmptyArray; 33 import android.keystore.cts.util.ImportedKey; 34 import android.keystore.cts.util.TestUtils; 35 import android.os.SystemClock; 36 import android.platform.test.annotations.Presubmit; 37 import android.security.keystore.KeyProperties; 38 import android.security.keystore.KeyProtection; 39 import android.server.wm.ActivityManagerTestBase; 40 import android.server.wm.UiDeviceUtils; 41 42 import androidx.test.InstrumentationRegistry; 43 import androidx.test.runner.AndroidJUnit4; 44 45 import com.android.compatibility.common.util.ApiTest; 46 47 import com.google.common.collect.ObjectArrays; 48 49 import org.junit.Test; 50 import org.junit.runner.RunWith; 51 52 import java.io.ByteArrayInputStream; 53 import java.io.ByteArrayOutputStream; 54 import java.security.AlgorithmParameters; 55 import java.security.InvalidKeyException; 56 import java.security.Key; 57 import java.security.KeyStoreException; 58 import java.security.Provider; 59 import java.security.Provider.Service; 60 import java.security.Security; 61 import java.security.spec.AlgorithmParameterSpec; 62 import java.security.spec.MGF1ParameterSpec; 63 import java.util.Arrays; 64 import java.util.Collection; 65 import java.util.Date; 66 import java.util.HashSet; 67 import java.util.List; 68 import java.util.Locale; 69 import java.util.Map; 70 import java.util.Random; 71 import java.util.Set; 72 import java.util.TreeMap; 73 74 import javax.crypto.BadPaddingException; 75 import javax.crypto.Cipher; 76 import javax.crypto.CipherInputStream; 77 import javax.crypto.CipherOutputStream; 78 import javax.crypto.IllegalBlockSizeException; 79 import javax.crypto.spec.GCMParameterSpec; 80 import javax.crypto.spec.IvParameterSpec; 81 import javax.crypto.spec.OAEPParameterSpec; 82 import javax.crypto.spec.PSource; 83 import javax.crypto.spec.SecretKeySpec; 84 85 /** 86 * Tests for algorithm-agnostic functionality of {@code Cipher} implementations backed by Android 87 * Keystore. 88 */ 89 @RunWith(AndroidJUnit4.class) 90 public class CipherTest { 91 92 private static final String EXPECTED_PROVIDER_NAME = TestUtils.EXPECTED_CRYPTO_OP_PROVIDER_NAME; 93 94 private static final String[] BASE_EXPECTED_ALGORITHMS = { 95 "AES/ECB/NoPadding", 96 "AES/ECB/PKCS7Padding", 97 "AES/CBC/NoPadding", 98 "AES/CBC/PKCS7Padding", 99 "AES/CTR/NoPadding", 100 "AES/GCM/NoPadding", 101 "RSA/ECB/NoPadding", 102 "RSA/ECB/PKCS1Padding", 103 "RSA/ECB/OAEPPadding", 104 "RSA/ECB/OAEPWithSHA-1AndMGF1Padding", 105 "RSA/ECB/OAEPWithSHA-224AndMGF1Padding", 106 "RSA/ECB/OAEPWithSHA-256AndMGF1Padding", 107 "RSA/ECB/OAEPWithSHA-384AndMGF1Padding", 108 "RSA/ECB/OAEPWithSHA-512AndMGF1Padding" 109 }; 110 111 private static final String[] DESEDE_ALGORITHMS = { 112 "DESede/CBC/NoPadding", 113 "DESede/CBC/PKCS7Padding", 114 "DESede/ECB/NoPadding", 115 "DESede/ECB/PKCS7Padding", 116 }; 117 118 private static String[] EXPECTED_ALGORITHMS = BASE_EXPECTED_ALGORITHMS; 119 120 // For tests of behavior largely unrelated to the selected algorithm, such as 121 // unlockedDeviceRequired 122 private static final String[] BASIC_ALGORITHMS = { 123 "AES/GCM/NoPadding", 124 "RSA/ECB/OAEPWithSHA-256AndMGF1Padding", 125 }; 126 127 static { 128 if (TestUtils.supports3DES()) { 129 EXPECTED_ALGORITHMS = ObjectArrays 130 .concat(BASE_EXPECTED_ALGORITHMS, DESEDE_ALGORITHMS, String.class); 131 } 132 } 133 134 private static class KatVector { 135 private final byte[] plaintext; 136 private final byte[] ciphertext; 137 private final AlgorithmParameterSpec params; 138 KatVector(String plaintextHex, String ciphertextHex)139 private KatVector(String plaintextHex, String ciphertextHex) { 140 this(plaintextHex, null, ciphertextHex); 141 } 142 KatVector(String plaintextHex, AlgorithmParameterSpec params, String ciphertextHex)143 private KatVector(String plaintextHex, AlgorithmParameterSpec params, 144 String ciphertextHex) { 145 this(HexEncoding.decode(plaintextHex), params, HexEncoding.decode(ciphertextHex)); 146 } 147 KatVector(byte[] plaintext, byte[] ciphertext)148 private KatVector(byte[] plaintext, byte[] ciphertext) { 149 this(plaintext, null, ciphertext); 150 } 151 KatVector(byte[] plaintext, AlgorithmParameterSpec params, byte[] ciphertext)152 private KatVector(byte[] plaintext, AlgorithmParameterSpec params, byte[] ciphertext) { 153 this.plaintext = plaintext; 154 this.ciphertext = ciphertext; 155 this.params = params; 156 } 157 } 158 private static final Map<String, KatVector> KAT_VECTORS = 159 new TreeMap<String, KatVector>(String.CASE_INSENSITIVE_ORDER); 160 static { 161 // From RI 162 KAT_VECTORS.put("AES/ECB/NoPadding", new KatVector( 163 "0383911bb1519d58e6656f3fd35639c502dbeb2196cea937fca272666cb4a80b", 164 "6574c5065283b89e0c930019e4655d8516b98170db6516cd83e589bd9c5e5adc")); 165 KAT_VECTORS.put("AES/ECB/PKCS7Padding", new KatVector( 166 "1ad3d73a3cfa66dac78a51a95c2cb2125ea701e6e9ecbca2415b436f0258e2ba7439b67545", 167 "920f873f2f9e91bac4c9c948d66496a21b8b2606850490dac7abecae83317488ee550b9973ac5cd142" 168 + "f387d7d2a12752")); 169 KAT_VECTORS.put("AES/CBC/NoPadding", new KatVector( 170 "1dffe21c8f18276c3a39ed0c53ab257b84efcedab60095c4cadd131143058cf7", 171 new IvParameterSpec(HexEncoding.decode("10b3eea6cc8a7d6f48337e9b6987d28c")), 172 "47ab115bfadca91eaebec73ab942a06f3121fdd5aa55d223bd2cbcc3855e1ef8")); 173 KAT_VECTORS.put("AES/CBC/PKCS7Padding", new KatVector( 174 "9d49fb970b23bfe742ae7c45a773ada9faad84708c8858a06e4a192e0a90e2f6083548e0bf3f67", 175 new IvParameterSpec(HexEncoding.decode("ecd87bf9c49f37dcd2294e309192289a")), 176 "aeb64f48ec18a086eda7ee080948651a50b6f582ab54aac5454c9ab0a4de5b4a4abac526a4307011d1" 177 + "2881f1849c32ae")); 178 KAT_VECTORS.put("AES/CTR/NoPadding", new KatVector( 179 "b4e786cab9df48d2fce0c7872651314db1318d1f31a1b10a2c334d2555b4117668", 180 new IvParameterSpec(HexEncoding.decode("94d9f7a6d16f58018819b668020b68cc")), 181 "022e74572a70be57a0b65b2fb5bc9b803ce48973b6163f528bbe1fd001e29d330a")); 182 KAT_VECTORS.put("AES/GCM/NoPadding", new KatVector( 183 "03889a6ca811e3fd7e78467e3dae587d2110e80e98edbc9dfe17afba238c4c493186", 184 new GCMParameterSpec(128, HexEncoding.decode("f67aaf97cdec65b12188315e")), 185 "159eb1ffc86589b38f18097c32db646c7de3525b603876c3ae671bc2ca52a5395a374b377a915c9ed1" 186 + "a349abf9fc54c9ca81")); 187 KAT_VECTORS.put("RSA/ECB/NoPadding", new KatVector( 188 "50c499d558c38fd48ea76832887db2abc76e4e153a98fd4323ccb8006d34f11724a5692fb101b0eb96" 189 + "060eb9d15222", 190 "349b1d5061e98d0ab3f2327680bbc0cbb1b8ef8ee26148d7c67cf535223e3f78d822d369592ede29b1" 191 + "654aab25e6ae5e098318e55c13dc405f5ba27e5cc69ced32778592a51e6293a03f95e14ed17099fb" 192 + "0ac585e41297b87c3432953df0d98be7e505dc7de7bfe9d9ec750f475afeba4cc2dd78838c0d4399" 193 + "d8de02b07f00b292dc3d32d2a2f98ea5a5dac1a0fec4d01e5c3aea8c56eeff264896fb6cf2144401" 194 + "278c6663417bc00aafbb9eb97c056573cdec88d6ac6fd6c333d131337b16031da229029e3b6fe6f8" 195 + "ee427f2e90041e9636d67cddac75845914ce4be56092eed7188fe7e2bb33769efdeed86a7acbe15d" 196 + "debf92d9fbaaddede206acfa650697")); 197 KAT_VECTORS.put("RSA/ECB/PKCS1Padding", new KatVector( 198 "aed8cd94f35b2a54cdd3ed771482bd87e256b995408558fb82e5d475d1ee54711472f899ad6cbb6847" 199 + "99e52ff1d57cbc39f4", 200 "64148dee294dd3ea31d2b595ea661318cf90c89f71393cf6559087d6e8993e73eb1e6b5f4d3cfde3cb" 201 + "267938c5eca522b95a2df02df9c703dbe3103c157af0d2ed5b70da51cb4caa49061319420d0ea433" 202 + "f24b727530c162226bc806b7f39079cd494a5c8a242737413d27063f9fb74aadd20f521211316719" 203 + "c628fd4351d0608928949b6f59f351d9ccec4c596514335010834fcabd53a2cbb2642e0f83c4f89c" 204 + "199ee2c68ace9182cf484d99e86b0b2213c1cc113d24891958e5a0774b7486abae1475e46a939a94" 205 + "5d6491b98ad7979fd6e752b47e43e960557a0c0589d7d0444b011d75c9f5b143da6e1dcf7b678a2e" 206 + "f82fbe37a74df3e20fb1a9dbfd5978")); 207 KAT_VECTORS.put("RSA/ECB/OAEPPadding", new KatVector( 208 "c219f4e3e37eae2315f0fa4ebc4b46ef0c6befbb43a51ceda07435fc88a9", 209 "7a9bcfd0d02b6434025bbf5ba09c2dad118a4a3bca7cced8b404bc0fc2f17ddee13de82c8324294bf2" 210 + "60ad6e5171c2c3728a0c0fab20dd60e4e56cfef3e66239439ed2eddcc83ac8eeaedfd970e9966de3" 211 + "94ad1df0df503a0a640a49e10885b3a4115c3e94e893fff87bf9a5808350f957d6bc556ca6b08f81" 212 + "bf697704a3eb3db774797f883af0dcdc9bd9196d7595bab5e87d3187eb45b5771abe4e4dc70c25fa" 213 + "b9e3cddb6ae453a1d8e517d000779472e1376e5848b1654a51a9e90be4a4a6d0f6b8723c6e93c471" 214 + "313ea94f24504ca377b502057331355965a7e0b9c3b1d1fbd24ab5a4167f721d1ddac4d3c094d5c9" 215 + "0d2e277e9b5617cbf2770186323e89")); 216 KAT_VECTORS.put("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", new KatVector( 217 "bb2854620bb0e361d1384703dda12acee1fefc22024bcfc40a86390d5342c693aab8c7ed6517d8da86" 218 + "04492c9d", 219 "77033c578f24ef0ed93bfe6dc6f7c3f9f0505e7562f67ce987a269cabaa8a3ae7dd5e567a8b37db42d" 220 + "a79aa86ea2e189af5b9560b39407ff86f2785cdaf660fc7c93649bc24a818de564cb0d03e7681fa8" 221 + "f3cd42b3bfc58c49d3f049e0c98b07aff95876f05ddc45ebaa7127a198f27ae0cfd161c5598ac795" 222 + "8ed386d98b13d45730e6dc16313fe012af27d7be0e45215040bbfb07f2d35e34291fe4335a68175a" 223 + "46be99a15c1ccf673659157e1f52105de5a0a6f8c9d946740216eefe2a01a37b0ab144a44ff0d800" 224 + "be713b5b44acf4fcb1a60d5db977af4d77fa77bdb8594032b2f5bbdd49346b08e0e98ab1051b462e" 225 + "160c1bff62b927cd26c936948b723a")); 226 KAT_VECTORS.put("RSA/ECB/OAEPWithSHA-224AndMGF1Padding", new KatVector( 227 "1bae19434be6599d1987b1ed866dd6b684dcd908bd98d797250be545eafea46d05ebdf9018", 228 "0f18b4a1153c6f8821e18a4275e4b570d540c8ad86bfc99146e5475238a43ecbe63bc81368cd64b9a2" 229 + "ab3ccd586e6afaad054c9d7bdc986adf022ec86335d110c53ebd5f2f2bd49d48d6da9541312c9b1b" 230 + "cc299ca4f59475869e4ec2253c91b137eae274a245fc9ee6262f74754bbda55d8bd25bfa4c1698f3" 231 + "a22d2d8d7fc6e9fbb56d828e61912b3085d82cceaeb1d2da425871575e7ba31a3d47b1b7d7df0bda" 232 + "81d62c75a9887bbc528fc6bb51db09884bb513b4cc94ca4a5fe0b370ca548dcdf60eebbf61e7efe7" 233 + "630fc47256d6d617fc1c2c774405f385650898abea03502cfbdcb53579fd18d896490e67aecdb7c7" 234 + "b7b950dc7ddba5c64188494c1a177b")); 235 KAT_VECTORS.put("RSA/ECB/OAEPWithSHA-256AndMGF1Padding", new KatVector( 236 "332c2f2fc066fb29ec0928a52b5111ce6965546ce73927340c42d33b56b6ba547b77ac361ac0d13316" 237 + "345ca953840023d892fa4ff1aa32cc66d5aa88b79867", 238 "942c0ba1c67a34a7e116d9281b1df5084c66bc1458faf1b26d4f0f63a57307a9addcd3e5d2f3320071" 239 + "5a3d95ae84fb40a8dfe4cb0a28873fd5883ff8ee6efbfe38c460c755577b34fcf05bb2077afec7b2" 240 + "203799022be6a0903915e01e94abc51efe9c5548eb86bbbb4fd7f3bfc7b86f388128b6df1e6ce651" 241 + "230c6bc18bbf55b029f1e31da880c27d947ff97519df66a57ead6db791c4978f1d62edec0d89bb16" 242 + "83d237213f3f24271ddb8c4b50a82527954f0e49ae44d3acd8ddd3a57cfbfa456dd40675d5d75542" 243 + "31c6b79c7fb3500b1631be1d100e67d85ce423845fdc7c7f45e346a8ba573f5d11de9009069468dd" 244 + "8d517ad4adb1509dd5173ee1862d74")); 245 KAT_VECTORS.put("RSA/ECB/OAEPWithSHA-384AndMGF1Padding", new KatVector( 246 "f51f158cbad4dbab38403b839c724f09a480c49be29c0e72615539dbe57ec86143f31f19392f419b5b" 247 + "e4ba9e3c6f1e870d307a7cf1a9e2", 248 "944243f35f534e7a273e94986b6835a4f5cdc5bc4efb9970d4760986599a02f652a848fcae333ff25a" 249 + "64108c9b900aaf002688398ad9fc17c73be52726306af9c13540df9d1765336b6f09ba4cb8a54d72" 250 + "5a4e45854bfa3802cfb110a6d7f7054e6072440ec00da62828cb75fe2566ec5be79eb8a3d1fbe2c2" 251 + "4439c107e5018e445e201ad80725755543c00dec50bb464c6ca897600eb3cda51fcef8161ac13d75" 252 + "a3eb30d385a1e718a61ae1b5d47aadb966fc007becc84db397d0b3cd983121872f9975995153e869" 253 + "9e24554a3c5e885f0ed8cd03e916da5ed541f1598da9bd6209447301d00f086153da353deff9d045" 254 + "8976ff7570410f0bdcfb3f56b782f5")); 255 KAT_VECTORS.put("RSA/ECB/OAEPWithSHA-512AndMGF1Padding", new KatVector( 256 "d45f6ccc7e663957f234c237c1f09bf7791f6f5c1b9ef4fefb16e55ded0d96112e590f1bb08a60f85c" 257 + "2d0d2533f1d69792dfd8d647d880b18f87cfe32488c73613a3d535da7d776d90d9a4ba6a0311f456" 258 + "8511da49107c", 259 "5a037df3e5d6f3f703541e2db2aef7c69985e513bdff67c8ade6a09f50e27267bfb444f6c69b40a77a" 260 + "9136a27b29876af9d2bf4e7099863445d35b188d31f376b89fbd196059667ca657e10b9454c2b25f" 261 + "046fc9f7b42506e382e6b6fd99409cf97e865e65f8dce5d14a06b8aa8833c4bc72c8764467758f2d" 262 + "7960243161dce4ca8231e91bfcd3c933a80bc703ceab976224c876b1f550f91a6c2a0332d4377bd8" 263 + "dfe4b1283ab114e517b7b9e4a6e0bf166d5b506e7a3b7328078e12cb23b1d938760767dc9b3c3eb0" 264 + "848ddda101792aca9273ad414314c13fc511ffa0358a8f4c5f38edded3a2dc111fa62c80e6032c32" 265 + "ae04aeac7729f16a6310f1f6785c27")); 266 267 268 KAT_VECTORS.put("DESede/CBC/NoPadding", 269 new KatVector("eac1b7959e1e23c11dc4a0e233eedd99e5bf5dd391a5f107d006133a9af3e385", 270 new IvParameterSpec(HexEncoding.decode("ecd87bf9c49f37dc")), 271 "632511c46680d60883a228e62cd31244ad61b987e8df7901dae0eb220c839689")); 272 KAT_VECTORS.put("DESede/CBC/PKCS7Padding", 273 new KatVector("31323334353637383132333435363738", 274 new IvParameterSpec(HexEncoding.decode("DFCA366848DEA6BB")), 275 "e70bb5761d796d7b0eb40b5b60deb6a9726f72d97cf2ada4")); 276 KAT_VECTORS.put("DESede/ECB/NoPadding", 277 new KatVector("31323334353637383132333435363738", 278 "ade119f9e35ab3e9ade119f9e35ab3e9")); 279 KAT_VECTORS.put("DESede/ECB/PKCS7Padding", 280 new KatVector("31323334353637383132333435363738", 281 "ade119f9e35ab3e9ade119f9e35ab3e94bcb01bbc0d05526")); 282 } 283 284 private static final long DAY_IN_MILLIS = TestUtils.DAY_IN_MILLIS; 285 286 private static final byte[] AES128_KAT_KEY_BYTES = 287 HexEncoding.decode("7d9f11a0da111e9d8bdd14f04648ed91"); 288 289 private static final byte[] AES192_KAT_KEY_BYTES = 290 HexEncoding.decode("69ef2c44a48d3dc4d5744a281f7ebb5ca976c2202f91e10c"); 291 292 private static final byte[] AES256_KAT_KEY_BYTES = 293 HexEncoding.decode("cf601cc10aaf434d1f01747136aff222af7fb426d101901712214c3fea18125f"); 294 295 private static final byte[] DESede_KAT_KEY_BYTES = HexEncoding.decode( 296 "5EBE2294ECD0E0F08EAB7690D2A6EE6926AE5CC854E36B6B"); 297 getContext()298 private Context getContext() { 299 return InstrumentationRegistry.getInstrumentation().getTargetContext(); 300 } 301 302 private class DeviceLockSession extends ActivityManagerTestBase implements AutoCloseable { 303 304 private LockScreenSession mLockCredential; 305 DeviceLockSession()306 public DeviceLockSession() throws Exception { 307 setUp(); 308 mLockCredential = new LockScreenSession(); 309 mLockCredential.setLockCredential(); 310 } 311 performDeviceLock()312 public void performDeviceLock() { 313 mLockCredential.sleepDevice(); 314 KeyguardManager keyguardManager = (KeyguardManager)getContext().getSystemService(Context.KEYGUARD_SERVICE); 315 for (int i = 0; i < 25 && !keyguardManager.isDeviceLocked(); i++) { 316 SystemClock.sleep(200); 317 } 318 } 319 performDeviceUnlock()320 public void performDeviceUnlock() throws Exception { 321 mLockCredential.gotoKeyguard(); 322 UiDeviceUtils.pressUnlockButton(); 323 mLockCredential.enterAndConfirmLockCredential(); 324 launchHomeActivity(); 325 KeyguardManager keyguardManager = (KeyguardManager)getContext().getSystemService( 326 Context.KEYGUARD_SERVICE); 327 for (int i = 0; i < 25 && keyguardManager.isDeviceLocked(); i++) { 328 SystemClock.sleep(200); 329 } 330 assertFalse(keyguardManager.isDeviceLocked()); 331 } 332 333 @Override close()334 public void close() throws Exception { 335 mLockCredential.close(); 336 } 337 } 338 339 @Presubmit 340 @Test testAlgorithmList()341 public void testAlgorithmList() { 342 // Assert that Android Keystore Provider exposes exactly the expected Cipher 343 // transformations. We don't care whether the transformations are exposed via aliases, as 344 // long as canonical names of transformation are accepted. 345 // If the Provider exposes extraneous algorithms, it'll be caught because it'll have to 346 // expose at least one Service for such an algorithm, and this Service's algorithm will 347 // not be in the expected set. 348 349 Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME); 350 Set<Service> services = provider.getServices(); 351 Set<String> actualAlgsLowerCase = new HashSet<String>(); 352 Set<String> expectedAlgsLowerCase = new HashSet<String>( 353 Arrays.asList(TestUtils.toLowerCase(EXPECTED_ALGORITHMS))); 354 for (Service service : services) { 355 if ("Cipher".equalsIgnoreCase(service.getType())) { 356 String algLowerCase = service.getAlgorithm().toLowerCase(Locale.US); 357 actualAlgsLowerCase.add(algLowerCase); 358 } 359 } 360 361 TestUtils.assertContentsInAnyOrder(actualAlgsLowerCase, 362 expectedAlgsLowerCase.toArray(new String[0])); 363 } 364 365 @Test testAndroidKeyStoreKeysHandledByAndroidKeyStoreProviderWhenDecrypting()366 public void testAndroidKeyStoreKeysHandledByAndroidKeyStoreProviderWhenDecrypting() 367 throws Exception { 368 Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME); 369 assertNotNull(provider); 370 for (String algorithm : EXPECTED_ALGORITHMS) { 371 try { 372 ImportedKey key = importDefaultKatKey( 373 algorithm, 374 KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT, 375 false); 376 377 // Decryption may need additional parameters. Initializing a Cipher for encryption 378 // forces it to generate any such parameters. 379 Cipher cipher = Cipher.getInstance(algorithm, provider); 380 cipher.init(Cipher.ENCRYPT_MODE, key.getKeystoreBackedEncryptionKey()); 381 AlgorithmParameters params = cipher.getParameters(); 382 383 // Test DECRYPT_MODE 384 cipher = Cipher.getInstance(algorithm); 385 Key decryptionKey = key.getKeystoreBackedDecryptionKey(); 386 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, params); 387 assertSame(provider, cipher.getProvider()); 388 389 // Test UNWRAP_MODE 390 cipher = Cipher.getInstance(algorithm); 391 if (params != null) { 392 cipher.init(Cipher.UNWRAP_MODE, decryptionKey, params); 393 } else { 394 cipher.init(Cipher.UNWRAP_MODE, decryptionKey); 395 } 396 assertSame(provider, cipher.getProvider()); 397 } catch (Throwable e) { 398 throw new RuntimeException("Failed for " + algorithm, e); 399 } 400 } 401 } 402 403 @Test testAndroidKeyStorePublicKeysAcceptedByHighestPriorityProviderWhenEncrypting()404 public void testAndroidKeyStorePublicKeysAcceptedByHighestPriorityProviderWhenEncrypting() 405 throws Exception { 406 Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME); 407 assertNotNull(provider); 408 for (String algorithm : EXPECTED_ALGORITHMS) { 409 if (isSymmetric(algorithm)) { 410 continue; 411 } 412 try { 413 Key key = importDefaultKatKey( 414 algorithm, 415 KeyProperties.PURPOSE_ENCRYPT, 416 false).getKeystoreBackedEncryptionKey(); 417 418 Cipher cipher = Cipher.getInstance(algorithm); 419 cipher.init(Cipher.ENCRYPT_MODE, key); 420 421 cipher = Cipher.getInstance(algorithm); 422 cipher.init(Cipher.WRAP_MODE, key); 423 } catch (Throwable e) { 424 throw new RuntimeException("Failed for" + algorithm, e); 425 } 426 } 427 } 428 429 @Test testEmptyPlaintextEncryptsAndDecrypts()430 public void testEmptyPlaintextEncryptsAndDecrypts() 431 throws Exception { 432 Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME); 433 assertNotNull(provider); 434 final byte[] originalPlaintext = EmptyArray.BYTE; 435 for (String algorithm : EXPECTED_ALGORITHMS) { 436 for (ImportedKey key : importKatKeys( 437 algorithm, 438 KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT, 439 false)) { 440 try { 441 Key encryptionKey = key.getKeystoreBackedEncryptionKey(); 442 byte[] plaintext = truncatePlaintextIfNecessary( 443 algorithm, encryptionKey, originalPlaintext); 444 if (plaintext == null) { 445 // Key is too short to encrypt anything using this transformation 446 continue; 447 } 448 Cipher cipher = Cipher.getInstance(algorithm, provider); 449 cipher.init(Cipher.ENCRYPT_MODE, encryptionKey); 450 AlgorithmParameters params = cipher.getParameters(); 451 byte[] ciphertext = cipher.doFinal(plaintext); 452 byte[] expectedPlaintext = plaintext; 453 if ("RSA/ECB/NoPadding".equalsIgnoreCase(algorithm)) { 454 // RSA decryption without padding left-pads resulting plaintext with NUL 455 // bytes to the length of RSA modulus. 456 int modulusLengthBytes = (TestUtils.getKeySizeBits(encryptionKey) + 7) / 8; 457 expectedPlaintext = TestUtils.leftPadWithZeroBytes( 458 expectedPlaintext, modulusLengthBytes); 459 } 460 461 cipher = Cipher.getInstance(algorithm, provider); 462 Key decryptionKey = key.getKeystoreBackedDecryptionKey(); 463 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, params); 464 byte[] actualPlaintext = cipher.doFinal(ciphertext); 465 assertArrayEquals(expectedPlaintext, actualPlaintext); 466 } catch (Throwable e) { 467 throw new RuntimeException( 468 "Failed for " + algorithm + " with key " + key.getAlias(), 469 e); 470 } 471 } 472 } 473 } 474 475 /* 476 * This test performs a round trip en/decryption. It does so while the current thread 477 * is in interrupted state which cannot be signaled to the user of the Java Crypto 478 * API. 479 */ 480 @Test testEncryptsAndDecryptsInterrupted()481 public void testEncryptsAndDecryptsInterrupted() 482 throws Exception { 483 484 Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME); 485 assertNotNull(provider); 486 final byte[] originalPlaintext = EmptyArray.BYTE; 487 for (String algorithm : EXPECTED_ALGORITHMS) { 488 for (ImportedKey key : importKatKeys( 489 algorithm, 490 KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT, 491 false)) { 492 try { 493 Key encryptionKey = key.getKeystoreBackedEncryptionKey(); 494 byte[] plaintext = truncatePlaintextIfNecessary( 495 algorithm, encryptionKey, originalPlaintext); 496 if (plaintext == null) { 497 // Key is too short to encrypt anything using this transformation 498 continue; 499 } 500 Cipher cipher = Cipher.getInstance(algorithm, provider); 501 Thread.currentThread().interrupt(); 502 cipher.init(Cipher.ENCRYPT_MODE, encryptionKey); 503 AlgorithmParameters params = cipher.getParameters(); 504 byte[] ciphertext = cipher.doFinal(plaintext); 505 byte[] expectedPlaintext = plaintext; 506 if ("RSA/ECB/NoPadding".equalsIgnoreCase(algorithm)) { 507 // RSA decryption without padding left-pads resulting plaintext with NUL 508 // bytes to the length of RSA modulus. 509 int modulusLengthBytes = (TestUtils.getKeySizeBits(encryptionKey) + 7) / 8; 510 expectedPlaintext = TestUtils.leftPadWithZeroBytes( 511 expectedPlaintext, modulusLengthBytes); 512 } 513 514 cipher = Cipher.getInstance(algorithm, provider); 515 Key decryptionKey = key.getKeystoreBackedDecryptionKey(); 516 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, params); 517 byte[] actualPlaintext = cipher.doFinal(ciphertext); 518 assertTrue(Thread.currentThread().interrupted()); 519 assertArrayEquals(expectedPlaintext, actualPlaintext); 520 } catch (Throwable e) { 521 throw new RuntimeException( 522 "Failed for " + algorithm + " with key " + key.getAlias(), 523 e); 524 } 525 } 526 } 527 } 528 529 /* 530 * This test performs a round trip en/decryption using Cipher*Streams. 531 */ 532 @Test testEncryptsAndDecryptsUsingCipherStreams()533 public void testEncryptsAndDecryptsUsingCipherStreams() 534 throws Exception { 535 536 Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME); 537 assertNotNull(provider); 538 final byte[] originalPlaintext = new byte[1024]; 539 new Random().nextBytes(originalPlaintext); 540 for (String algorithm : EXPECTED_ALGORITHMS) { 541 for (ImportedKey key : importKatKeys( 542 algorithm, 543 KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT, 544 false)) { 545 try { 546 Key encryptionKey = key.getKeystoreBackedEncryptionKey(); 547 byte[] plaintext = truncatePlaintextIfNecessary( 548 algorithm, encryptionKey, originalPlaintext); 549 if (plaintext == null) { 550 // Key is too short to encrypt anything using this transformation 551 continue; 552 } 553 Cipher cipher = Cipher.getInstance(algorithm, provider); 554 cipher.init(Cipher.ENCRYPT_MODE, encryptionKey); 555 final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 556 final CipherOutputStream cipherOutputStream = 557 new CipherOutputStream(byteArrayOutputStream, cipher); 558 559 cipherOutputStream.write(plaintext); 560 cipherOutputStream.close(); 561 AlgorithmParameters params = cipher.getParameters(); 562 byte[] expectedPlaintext = plaintext; 563 if ("RSA/ECB/NoPadding".equalsIgnoreCase(algorithm)) { 564 // RSA decryption without padding left-pads resulting plaintext with NUL 565 // bytes to the length of RSA modulus. 566 int modulusLengthBytes = (TestUtils.getKeySizeBits(encryptionKey) + 7) / 8; 567 expectedPlaintext = TestUtils.leftPadWithZeroBytes( 568 expectedPlaintext, modulusLengthBytes); 569 } 570 571 byte[] ciphertext = byteArrayOutputStream.toByteArray(); 572 assertNotNull(ciphertext); 573 cipher = Cipher.getInstance(algorithm, provider); 574 Key decryptionKey = key.getKeystoreBackedDecryptionKey(); 575 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, params); 576 577 final ByteArrayInputStream byteArrayInputStream = 578 new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); 579 final CipherInputStream cipherInputStream = 580 new CipherInputStream(byteArrayInputStream, cipher); 581 byte[] actualPlaintext = new byte[plaintext.length * 2]; 582 int total = 0; 583 int count = 0; 584 while((count = cipherInputStream.read(actualPlaintext, total, 585 actualPlaintext.length - total)) != -1) { 586 total += count; 587 } 588 actualPlaintext = Arrays.copyOf(actualPlaintext, total); 589 cipherInputStream.close(); 590 assertTrue("expected(" + expectedPlaintext.length + "): " 591 + HexEncoding.encode(expectedPlaintext) 592 + "\nactual(" + actualPlaintext.length + "): " 593 + HexEncoding.encode(actualPlaintext), 594 Arrays.equals(expectedPlaintext, actualPlaintext)); 595 } catch (Throwable e) { 596 throw new RuntimeException( 597 "Failed for " + algorithm + " with key " + key.getAlias(), 598 e); 599 } 600 } 601 } 602 } 603 isDecryptValid(byte[] expectedPlaintext, byte[] ciphertext, Cipher cipher, AlgorithmParameters params, ImportedKey key)604 private boolean isDecryptValid(byte[] expectedPlaintext, byte[] ciphertext, Cipher cipher, 605 AlgorithmParameters params, ImportedKey key) { 606 try { 607 Key decryptionKey = key.getKeystoreBackedDecryptionKey(); 608 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, params); 609 byte[] actualPlaintext = cipher.doFinal(ciphertext); 610 assertArrayEquals(expectedPlaintext, actualPlaintext); 611 return true; 612 } catch (Throwable e) { 613 return false; 614 } 615 } 616 isLeanbackOnly()617 private boolean isLeanbackOnly() { 618 PackageManager pm = getContext().getPackageManager(); 619 return (pm != null && pm.hasSystemFeature("android.software.leanback_only")); 620 } 621 622 @Presubmit 623 @Test testKeyguardLockAndUnlock()624 public void testKeyguardLockAndUnlock() 625 throws Exception { 626 if (!TestUtils.hasSecureLockScreen(getContext())) { 627 return; 628 } 629 630 try (DeviceLockSession dl = new DeviceLockSession()) { 631 KeyguardManager keyguardManager = (KeyguardManager)getContext() 632 .getSystemService(Context.KEYGUARD_SERVICE); 633 634 dl.performDeviceLock(); 635 assertTrue(keyguardManager.isDeviceLocked()); 636 637 dl.performDeviceUnlock(); 638 assertFalse(keyguardManager.isDeviceLocked()); 639 } 640 } 641 642 @Test testEmptyPlaintextEncryptsAndDecryptsWhenUnlockedRequired()643 public void testEmptyPlaintextEncryptsAndDecryptsWhenUnlockedRequired() 644 throws Exception { 645 final boolean isUnlockedDeviceRequired = true; 646 final boolean isUserAuthRequired = false; 647 648 if (!TestUtils.hasSecureLockScreen(getContext())) { 649 return; 650 } 651 652 try (DeviceLockSession dl = new DeviceLockSession()) { 653 dl.performDeviceLock(); 654 KeyguardManager keyguardManager = (KeyguardManager)getContext() 655 .getSystemService(Context.KEYGUARD_SERVICE); 656 657 Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME); 658 assertNotNull(provider); 659 final byte[] originalPlaintext = EmptyArray.BYTE; 660 // Normally we would test all combinations of algorithms and key sizes, but the 661 // semi-manual locking and unlocking this requires takes way too long if we try to 662 // go through all of those. Other tests check all the key sizes, so we don't need to 663 // duplicate all that work. 664 for (String algorithm : BASIC_ALGORITHMS) { 665 for (boolean createWhileLocked : new boolean[]{false, true}) { 666 try { 667 if (createWhileLocked) { 668 dl.performDeviceLock(); 669 } else { 670 dl.performDeviceUnlock(); 671 } 672 // Test just a single key in the collection 673 ImportedKey key = importKatKeys( 674 algorithm, 675 KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT, 676 false, isUnlockedDeviceRequired, 677 isUserAuthRequired).iterator().next(); 678 if (createWhileLocked) { 679 dl.performDeviceUnlock(); 680 } 681 Key encryptionKey = key.getKeystoreBackedEncryptionKey(); 682 byte[] plaintext = truncatePlaintextIfNecessary( 683 algorithm, encryptionKey, originalPlaintext); 684 if (plaintext == null) { 685 // Key is too short to encrypt anything using this transformation 686 continue; 687 } 688 689 Cipher cipher = Cipher.getInstance(algorithm, provider); 690 cipher.init(Cipher.ENCRYPT_MODE, encryptionKey); 691 AlgorithmParameters params = cipher.getParameters(); 692 byte[] ciphertext = cipher.doFinal(plaintext); 693 byte[] expectedPlaintext = plaintext; 694 if ("RSA/ECB/NoPadding".equalsIgnoreCase(algorithm)) { 695 // RSA decryption without padding left-pads resulting plaintext 696 // with NUL bytes to the length of RSA modulus. 697 int modulusLengthBytes = (TestUtils.getKeySizeBits(encryptionKey) 698 + 7) / 8; 699 expectedPlaintext = TestUtils.leftPadWithZeroBytes( 700 expectedPlaintext, modulusLengthBytes); 701 } 702 703 dl.performDeviceLock(); 704 705 // Attempt to decrypt the data with the device locked. 706 cipher = Cipher.getInstance(algorithm, provider); 707 assertFalse( 708 isDecryptValid(expectedPlaintext, ciphertext, cipher, params, 709 key)); 710 711 // Then attempt to decrypt the data with the device unlocked 712 // This should succeed 713 dl.performDeviceUnlock(); 714 cipher = Cipher.getInstance(algorithm, provider); 715 assertTrue(isDecryptValid(expectedPlaintext, ciphertext, cipher, params, 716 key)); 717 718 // Ensure a second decryption also succeeds 719 cipher = Cipher.getInstance(algorithm, provider); 720 assertTrue(isDecryptValid(expectedPlaintext, ciphertext, cipher, params, 721 key)); 722 } catch (Throwable e) { 723 throw new RuntimeException( 724 "Failed on createWhileLocked " + createWhileLocked + " for " + 725 algorithm, 726 e); 727 } 728 } 729 } 730 } 731 } 732 733 @Test testCiphertextGeneratedByAndroidKeyStoreDecryptsByAndroidKeyStore()734 public void testCiphertextGeneratedByAndroidKeyStoreDecryptsByAndroidKeyStore() 735 throws Exception { 736 Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME); 737 assertNotNull(provider); 738 final byte[] originalPlaintext = "Very secret message goes here...".getBytes("US-ASCII"); 739 for (String algorithm : EXPECTED_ALGORITHMS) { 740 for (ImportedKey key : importKatKeys( 741 algorithm, 742 KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT, 743 false)) { 744 try { 745 Key encryptionKey = key.getKeystoreBackedEncryptionKey(); 746 byte[] plaintext = truncatePlaintextIfNecessary( 747 algorithm, encryptionKey, originalPlaintext); 748 if (plaintext == null) { 749 // Key is too short to encrypt anything using this transformation 750 continue; 751 } 752 Cipher cipher = Cipher.getInstance(algorithm, provider); 753 cipher.init(Cipher.ENCRYPT_MODE, encryptionKey); 754 AlgorithmParameters params = cipher.getParameters(); 755 byte[] ciphertext = cipher.doFinal(plaintext); 756 byte[] expectedPlaintext = plaintext; 757 if ("RSA/ECB/NoPadding".equalsIgnoreCase(algorithm)) { 758 // RSA decryption without padding left-pads resulting plaintext with NUL 759 // bytes to the length of RSA modulus. 760 int modulusLengthBytes = (TestUtils.getKeySizeBits(encryptionKey) + 7) / 8; 761 expectedPlaintext = TestUtils.leftPadWithZeroBytes( 762 expectedPlaintext, modulusLengthBytes); 763 } 764 765 cipher = Cipher.getInstance(algorithm, provider); 766 Key decryptionKey = key.getKeystoreBackedDecryptionKey(); 767 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, params); 768 byte[] actualPlaintext = cipher.doFinal(ciphertext); 769 assertArrayEquals(expectedPlaintext, actualPlaintext); 770 } catch (Throwable e) { 771 throw new RuntimeException( 772 "Failed for " + algorithm + " with key " + key.getAlias(), 773 e); 774 } 775 } 776 } 777 } 778 779 @Test testCiphertextGeneratedByHighestPriorityProviderDecryptsByAndroidKeyStore()780 public void testCiphertextGeneratedByHighestPriorityProviderDecryptsByAndroidKeyStore() 781 throws Exception { 782 Provider keystoreProvider = Security.getProvider(EXPECTED_PROVIDER_NAME); 783 assertNotNull(keystoreProvider); 784 byte[] originalPlaintext = "Very secret message goes here...".getBytes("UTF-8"); 785 for (String algorithm : EXPECTED_ALGORITHMS) { 786 for (ImportedKey key : importKatKeys( 787 algorithm, 788 KeyProperties.PURPOSE_DECRYPT, 789 false)) { 790 Provider encryptionProvider = null; 791 try { 792 Key encryptionKey = key.getOriginalEncryptionKey(); 793 byte[] plaintext = truncatePlaintextIfNecessary( 794 algorithm, encryptionKey, originalPlaintext); 795 if (plaintext == null) { 796 // Key is too short to encrypt anything using this transformation 797 continue; 798 } 799 800 Cipher cipher; 801 try { 802 cipher = Cipher.getInstance(algorithm); 803 cipher.init(Cipher.ENCRYPT_MODE, encryptionKey); 804 } catch (InvalidKeyException e) { 805 // No providers support encrypting using this algorithm and key. 806 continue; 807 } 808 encryptionProvider = cipher.getProvider(); 809 if (keystoreProvider == encryptionProvider) { 810 // This is covered by another test. 811 continue; 812 } 813 AlgorithmParameters params = cipher.getParameters(); 814 815 // TODO: Remove this workaround for Bug 22405492 once the issue is fixed. The 816 // issue is that Bouncy Castle incorrectly defaults the MGF1 digest to the 817 // digest specified in the transformation. RI and Android Keystore keep the MGF1 818 // digest defaulted at SHA-1. 819 if ((params != null) && ("OAEP".equalsIgnoreCase(params.getAlgorithm()))) { 820 OAEPParameterSpec spec = params.getParameterSpec(OAEPParameterSpec.class); 821 if (!"SHA-1".equalsIgnoreCase( 822 ((MGF1ParameterSpec) spec.getMGFParameters()) 823 .getDigestAlgorithm())) { 824 // Create a new instance of Cipher because Bouncy Castle's RSA Cipher 825 // caches AlgorithmParameters returned by Cipher.getParameters and does 826 // not invalidate the cache when reinitialized with different 827 // parameters. 828 cipher = Cipher.getInstance(algorithm, encryptionProvider); 829 cipher.init(Cipher.ENCRYPT_MODE, encryptionKey, new OAEPParameterSpec( 830 spec.getDigestAlgorithm(), 831 "MGF1", 832 MGF1ParameterSpec.SHA1, 833 PSource.PSpecified.DEFAULT)); 834 params = cipher.getParameters(); 835 OAEPParameterSpec newSpec = 836 params.getParameterSpec(OAEPParameterSpec.class); 837 assertEquals(spec.getDigestAlgorithm(), newSpec.getDigestAlgorithm()); 838 assertEquals( 839 "SHA-1", 840 ((MGF1ParameterSpec) newSpec.getMGFParameters()) 841 .getDigestAlgorithm()); 842 } 843 } 844 845 byte[] ciphertext = cipher.doFinal(plaintext); 846 byte[] expectedPlaintext = plaintext; 847 if ("RSA/ECB/NoPadding".equalsIgnoreCase(algorithm)) { 848 // RSA decryption without padding left-pads resulting plaintext with NUL 849 // bytes to the length of RSA modulus. 850 int modulusLengthBytes = (TestUtils.getKeySizeBits(encryptionKey) + 7) / 8; 851 expectedPlaintext = TestUtils.leftPadWithZeroBytes( 852 expectedPlaintext, modulusLengthBytes); 853 } 854 855 // TODO: Remove this workaround once Android Keystore AES-GCM supports IVs of 856 // sizes other than 12 bytes. For example, Bouncy Castle auto-generates 16-byte 857 // long IVs. 858 if ("AES/GCM/NoPadding".equalsIgnoreCase(algorithm)) { 859 byte[] iv = cipher.getIV(); 860 if ((iv != null) && (iv.length != 12)) { 861 // Android Keystore AES-GCM only supports 12-byte long IVs. 862 continue; 863 } 864 } 865 866 // TODO: Remove this workaround for Bug 22319986 once the issue is fixed. The issue 867 // is that Conscrypt and Bouncy Castle's AES/GCM/NoPadding implementations return 868 // AlgorithmParameters of algorithm "AES" from which it's impossible to obtain a 869 // GCMParameterSpec. They should be returning AlgorithmParameters of algorithm 870 // "GCM". 871 if (("AES/GCM/NoPadding".equalsIgnoreCase(algorithm)) 872 && (!"GCM".equalsIgnoreCase(params.getAlgorithm()))) { 873 params = AlgorithmParameters.getInstance("GCM"); 874 params.init(new GCMParameterSpec(128, cipher.getIV())); 875 } 876 877 cipher = Cipher.getInstance(algorithm, keystoreProvider); 878 Key decryptionKey = key.getKeystoreBackedDecryptionKey(); 879 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, params); 880 byte[] actualPlaintext = cipher.doFinal(ciphertext); 881 assertArrayEquals(expectedPlaintext, actualPlaintext); 882 } catch (Throwable e) { 883 throw new RuntimeException( 884 "Failed for " + algorithm + " with key " + key.getAlias() 885 + ", encryption provider: " + encryptionProvider, 886 e); 887 } 888 } 889 } 890 } 891 892 @Test testCiphertextGeneratedByAndroidKeyStoreDecryptsByHighestPriorityProvider()893 public void testCiphertextGeneratedByAndroidKeyStoreDecryptsByHighestPriorityProvider() 894 throws Exception { 895 Provider keystoreProvider = Security.getProvider(EXPECTED_PROVIDER_NAME); 896 assertNotNull(keystoreProvider); 897 byte[] originalPlaintext = "Very secret message goes here...".getBytes("UTF-8"); 898 for (String algorithm : EXPECTED_ALGORITHMS) { 899 for (ImportedKey key : importKatKeys( 900 algorithm, 901 KeyProperties.PURPOSE_ENCRYPT, 902 false)) { 903 Provider decryptionProvider = null; 904 try { 905 Key encryptionKey = key.getKeystoreBackedEncryptionKey(); 906 byte[] plaintext = truncatePlaintextIfNecessary( 907 algorithm, encryptionKey, originalPlaintext); 908 if (plaintext == null) { 909 // Key is too short to encrypt anything using this transformation 910 continue; 911 } 912 Cipher cipher = Cipher.getInstance(algorithm, keystoreProvider); 913 cipher.init(Cipher.ENCRYPT_MODE, encryptionKey); 914 AlgorithmParameters params = cipher.getParameters(); 915 916 byte[] ciphertext = cipher.doFinal(plaintext); 917 byte[] expectedPlaintext = plaintext; 918 if ("RSA/ECB/NoPadding".equalsIgnoreCase(algorithm)) { 919 // RSA decryption without padding left-pads resulting plaintext with NUL 920 // bytes to the length of RSA modulus. 921 int modulusLengthBytes = (TestUtils.getKeySizeBits(encryptionKey) + 7) / 8; 922 expectedPlaintext = TestUtils.leftPadWithZeroBytes( 923 expectedPlaintext, modulusLengthBytes); 924 } 925 926 Key decryptionKey = key.getOriginalDecryptionKey(); 927 try { 928 cipher = Cipher.getInstance(algorithm); 929 if (params != null) { 930 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, params); 931 } else { 932 cipher.init(Cipher.DECRYPT_MODE, decryptionKey); 933 } 934 } catch (InvalidKeyException e) { 935 // No providers support decrypting using this algorithm and key. 936 continue; 937 } 938 decryptionProvider = cipher.getProvider(); 939 if (keystoreProvider == decryptionProvider) { 940 // This is covered by another test. 941 continue; 942 } 943 byte[] actualPlaintext = cipher.doFinal(ciphertext); 944 assertArrayEquals(expectedPlaintext, actualPlaintext); 945 } catch (Throwable e) { 946 throw new RuntimeException( 947 "Failed for " + algorithm + " with key " + key.getAlias() 948 + ", decryption provider: " + decryptionProvider, 949 e); 950 } 951 } 952 } 953 } 954 955 @Test testMaxSizedPlaintextSupported()956 public void testMaxSizedPlaintextSupported() throws Exception { 957 Provider keystoreProvider = Security.getProvider(EXPECTED_PROVIDER_NAME); 958 assertNotNull(keystoreProvider); 959 for (String algorithm : EXPECTED_ALGORITHMS) { 960 if (isSymmetric(algorithm)) { 961 // No input length restrictions (except multiple of block size for some 962 // transformations). 963 continue; 964 } 965 for (ImportedKey key : importKatKeys( 966 algorithm, 967 KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT, 968 false)) { 969 int plaintextSizeBytes = -1; 970 Provider otherProvider = null; 971 try { 972 Key encryptionKey = key.getKeystoreBackedEncryptionKey(); 973 int maxSupportedPlaintextSizeBytes = 974 TestUtils.getMaxSupportedPlaintextInputSizeBytes( 975 algorithm, encryptionKey); 976 if (maxSupportedPlaintextSizeBytes < 0) { 977 // Key too short to encrypt anything using this transformation. 978 continue; 979 } else if (maxSupportedPlaintextSizeBytes == Integer.MAX_VALUE) { 980 // No input length restrictions. 981 continue; 982 } 983 byte[] plaintext = new byte[maxSupportedPlaintextSizeBytes]; 984 Arrays.fill(plaintext, (byte) 0xff); 985 plaintextSizeBytes = plaintext.length; 986 987 // Encrypt plaintext using Android Keystore Cipher 988 Cipher cipher = Cipher.getInstance(algorithm, keystoreProvider); 989 cipher.init(Cipher.ENCRYPT_MODE, encryptionKey); 990 AlgorithmParameters params = cipher.getParameters(); 991 byte[] ciphertext = cipher.doFinal(plaintext); 992 byte[] expectedPlaintext = plaintext; 993 if ("RSA/ECB/NoPadding".equalsIgnoreCase(algorithm)) { 994 // RSA decryption without padding left-pads resulting plaintext with NUL 995 // bytes to the length of RSA modulus. 996 int modulusLengthBytes = (TestUtils.getKeySizeBits(encryptionKey) + 7) / 8; 997 expectedPlaintext = TestUtils.leftPadWithZeroBytes( 998 expectedPlaintext, modulusLengthBytes); 999 } 1000 1001 // Check that ciphertext decrypts using Android Keystore Cipher 1002 cipher = Cipher.getInstance(algorithm, keystoreProvider); 1003 Key decryptionKey = key.getKeystoreBackedDecryptionKey(); 1004 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, params); 1005 byte[] actualPlaintext = cipher.doFinal(ciphertext); 1006 assertArrayEquals(expectedPlaintext, actualPlaintext); 1007 1008 // Check that ciphertext decrypts using the highest-priority provider. 1009 cipher = Cipher.getInstance(algorithm); 1010 decryptionKey = key.getOriginalDecryptionKey(); 1011 try { 1012 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, params); 1013 } catch (InvalidKeyException e) { 1014 // No other providers offer decryption using this transformation and key. 1015 continue; 1016 } 1017 otherProvider = cipher.getProvider(); 1018 if (otherProvider == keystoreProvider) { 1019 // This has already been tested above. 1020 continue; 1021 } 1022 actualPlaintext = cipher.doFinal(ciphertext); 1023 assertArrayEquals(expectedPlaintext, actualPlaintext); 1024 } catch (Throwable e) { 1025 throw new RuntimeException( 1026 "Failed for " + algorithm + " with key " + key.getAlias() 1027 + " and " + plaintextSizeBytes + " long plaintext" 1028 + ", other provider: " + otherProvider, 1029 e); 1030 } 1031 } 1032 } 1033 } 1034 1035 @Test testLargerThanMaxSizedPlaintextRejected()1036 public void testLargerThanMaxSizedPlaintextRejected() throws Exception { 1037 Provider keystoreProvider = Security.getProvider(EXPECTED_PROVIDER_NAME); 1038 assertNotNull(keystoreProvider); 1039 for (String algorithm : EXPECTED_ALGORITHMS) { 1040 if (isSymmetric(algorithm)) { 1041 // No input length restrictions (except multiple of block size for some 1042 // transformations). 1043 continue; 1044 } 1045 for (ImportedKey key : importKatKeys( 1046 algorithm, 1047 KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT, 1048 false)) { 1049 int plaintextSizeBytes = -1; 1050 Provider otherProvider = null; 1051 try { 1052 Key encryptionKey = key.getKeystoreBackedEncryptionKey(); 1053 int maxSupportedPlaintextSizeBytes = 1054 TestUtils.getMaxSupportedPlaintextInputSizeBytes( 1055 algorithm, encryptionKey); 1056 if (maxSupportedPlaintextSizeBytes < 0) { 1057 // Key too short to encrypt anything using this transformation. 1058 continue; 1059 } else if (maxSupportedPlaintextSizeBytes == Integer.MAX_VALUE) { 1060 // No input length restrictions. 1061 continue; 1062 } 1063 // Create plaintext which is one byte longer than maximum supported one. 1064 byte[] plaintext = new byte[maxSupportedPlaintextSizeBytes + 1]; 1065 Arrays.fill(plaintext, (byte) 0xff); 1066 plaintextSizeBytes = plaintext.length; 1067 1068 // Encrypting this plaintext using Android Keystore Cipher should fail. 1069 Cipher cipher = Cipher.getInstance(algorithm, keystoreProvider); 1070 cipher.init(Cipher.ENCRYPT_MODE, encryptionKey); 1071 try { 1072 byte[] ciphertext = cipher.doFinal(plaintext); 1073 fail("Unexpectedly produced ciphertext (" + ciphertext.length 1074 + " bytes): " + HexEncoding.encode(ciphertext) + " for " 1075 + plaintext.length + " byte long plaintext"); 1076 } catch (IllegalBlockSizeException | BadPaddingException | 1077 ArrayIndexOutOfBoundsException expected) {} 1078 1079 // Encrypting this plaintext using the highest-priority implementation should 1080 // fail. 1081 cipher = Cipher.getInstance(algorithm); 1082 encryptionKey = key.getOriginalEncryptionKey(); 1083 try { 1084 cipher.init(Cipher.ENCRYPT_MODE, encryptionKey); 1085 } catch (InvalidKeyException e) { 1086 // No other providers support this transformation with this key. 1087 continue; 1088 } 1089 otherProvider = cipher.getProvider(); 1090 if (otherProvider == keystoreProvider) { 1091 // This has already been tested above. 1092 continue; 1093 } 1094 try { 1095 byte[] ciphertext = cipher.doFinal(plaintext); 1096 fail(otherProvider.getName() + " unexpectedly produced ciphertext (" 1097 + ciphertext.length + " bytes): " 1098 + HexEncoding.encode(ciphertext) + " for " 1099 + plaintext.length + " byte long plaintext"); 1100 // TODO: Remove the catching of RuntimeException and BadPaddingException 1101 // workaround once the corresponding Bug 22567463 in Conscrypt is fixed. 1102 } catch (IllegalBlockSizeException | BadPaddingException | RuntimeException 1103 exception) {} 1104 } catch (Throwable e) { 1105 throw new RuntimeException( 1106 "Failed for " + algorithm + " with key " + key.getAlias() 1107 + " and " + plaintextSizeBytes + " byte long plaintext" 1108 + ", other provider: " + otherProvider, 1109 e); 1110 } 1111 } 1112 } 1113 } 1114 1115 @Test testKat()1116 public void testKat() throws Exception { 1117 Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME); 1118 assertNotNull(provider); 1119 for (String algorithm : EXPECTED_ALGORITHMS) { 1120 try { 1121 ImportedKey key = importDefaultKatKey(algorithm, 1122 KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT, 1123 true); 1124 KatVector testVector = KAT_VECTORS.get(algorithm); 1125 assertNotNull(testVector); 1126 Cipher cipher = Cipher.getInstance(algorithm, provider); 1127 Key decryptionKey = key.getKeystoreBackedDecryptionKey(); 1128 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, testVector.params); 1129 byte[] actualPlaintext = cipher.doFinal(testVector.ciphertext); 1130 byte[] expectedPlaintext = testVector.plaintext; 1131 if ("RSA/ECB/NoPadding".equalsIgnoreCase(algorithm)) { 1132 // RSA decryption without padding left-pads resulting plaintext with NUL bytes 1133 // to the length of RSA modulus. 1134 int modulusLengthBytes = (TestUtils.getKeySizeBits(decryptionKey) + 7) / 8; 1135 expectedPlaintext = TestUtils.leftPadWithZeroBytes( 1136 expectedPlaintext, modulusLengthBytes); 1137 } 1138 assertArrayEquals(expectedPlaintext, actualPlaintext); 1139 if (!isRandomizedEncryption(algorithm)) { 1140 // Deterministic encryption: ciphertext depends only on plaintext and input 1141 // parameters. Assert that encrypting the plaintext results in the same 1142 // ciphertext as in the test vector. 1143 Key encryptionKey = key.getKeystoreBackedEncryptionKey(); 1144 cipher = Cipher.getInstance(algorithm, provider); 1145 cipher.init(Cipher.ENCRYPT_MODE, encryptionKey, testVector.params); 1146 byte[] actualCiphertext = cipher.doFinal(testVector.plaintext); 1147 assertArrayEquals(testVector.ciphertext, actualCiphertext); 1148 } 1149 } catch (Throwable e) { 1150 throw new RuntimeException("Failed for " + algorithm, e); 1151 } 1152 } 1153 } 1154 1155 @Test 1156 @ApiTest(apis = {"javax.crypto.Cipher#init"}) testKatBasicWithDifferentProviders()1157 public void testKatBasicWithDifferentProviders() throws Exception { 1158 List<String> keymasterNonSupportedAlgos = Arrays.asList(new String[]{ 1159 "RSA/ECB/OAEPWithSHA-224AndMGF1Padding", 1160 "RSA/ECB/OAEPWithSHA-256AndMGF1Padding", 1161 "RSA/ECB/OAEPWithSHA-384AndMGF1Padding", 1162 "RSA/ECB/OAEPWithSHA-512AndMGF1Padding" 1163 }); 1164 int kmVersion = TestUtils.getFeatureVersionKeystore(getContext()); 1165 for (String algorithm : EXPECTED_ALGORITHMS) { 1166 if (kmVersion < Attestation.KM_VERSION_KEYMINT_3 1167 && keymasterNonSupportedAlgos.contains(algorithm)) { 1168 // Skipping algorithms which are not supported in older KeyMaster. 1169 // This functionality has to support through software emulation. 1170 android.util.Log.d("CipherTest", 1171 " Skipping " + algorithm + " because it is not supported in KM version " 1172 + kmVersion); 1173 continue; 1174 } 1175 ImportedKey key = importDefaultKatKey(algorithm, 1176 KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT, 1177 false); 1178 KatVector testVector = KAT_VECTORS.get(algorithm); 1179 Cipher cipher = Cipher.getInstance(algorithm); 1180 Key encryptionKey = key.getOriginalEncryptionKey(); 1181 // Highest-priority provider for algorithm will be selected for original key. 1182 cipher.init(Cipher.ENCRYPT_MODE, encryptionKey); 1183 // Preserve algorithm parameters used for encryption, same parameters need to use 1184 // for decryption. 1185 AlgorithmParameters algorithmParameters = cipher.getParameters(); 1186 byte[] cipherText = 1187 cipher.doFinal(testVector.plaintext); 1188 Key decryptionKey = key.getKeystoreBackedDecryptionKey(); 1189 cipher = Cipher.getInstance(algorithm); 1190 // AndroidKeyStore provider will be selected for Android keystore backed key. 1191 cipher.init(Cipher.DECRYPT_MODE, decryptionKey, algorithmParameters); 1192 byte[] plainText = cipher.doFinal(cipherText); 1193 byte[] expectedPlaintext = testVector.plaintext; 1194 if ("RSA/ECB/NoPadding".equalsIgnoreCase(algorithm)) { 1195 // RSA decryption without padding left-pads resulting plaintext with NUL bytes 1196 // to the length of RSA modulus. 1197 int modulusLengthBytes = (TestUtils.getKeySizeBits(decryptionKey) + 7) / 8; 1198 expectedPlaintext = TestUtils.leftPadWithZeroBytes( 1199 expectedPlaintext, modulusLengthBytes); 1200 } 1201 assertArrayEquals(plainText, expectedPlaintext); 1202 } 1203 } 1204 isRandomizedEncryption(String transformation)1205 private static boolean isRandomizedEncryption(String transformation) { 1206 String transformationUpperCase = transformation.toUpperCase(Locale.US); 1207 return (transformationUpperCase.endsWith("/PKCS1PADDING")) 1208 || (transformationUpperCase.contains("OAEP")); 1209 } 1210 1211 @Test testCanCreateAuthBoundKeyWhenScreenLocked()1212 public void testCanCreateAuthBoundKeyWhenScreenLocked() throws Exception { 1213 final boolean isUnlockedDeviceRequired = false; 1214 final boolean isUserAuthRequired = true; 1215 1216 if (!TestUtils.hasSecureLockScreen(getContext())) { 1217 return; 1218 } 1219 1220 try (DeviceLockSession dl = new DeviceLockSession()) { 1221 KeyguardManager keyguardManager = (KeyguardManager)getContext().getSystemService(Context.KEYGUARD_SERVICE); 1222 1223 dl.performDeviceLock(); 1224 assertTrue(keyguardManager.isDeviceLocked()); 1225 1226 Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME); 1227 assertNotNull(provider); 1228 1229 for (String algorithm : EXPECTED_ALGORITHMS) { 1230 for (ImportedKey key : importKatKeys(algorithm, 1231 KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT, 1232 false, isUnlockedDeviceRequired, isUserAuthRequired)) { 1233 assertNotNull(key); 1234 } 1235 } 1236 } 1237 } 1238 1239 @Test testCannotCreateAuthBoundKeyWhenDevicePinNotSet()1240 public void testCannotCreateAuthBoundKeyWhenDevicePinNotSet() throws Exception { 1241 final boolean isUserAuthRequired = true; 1242 final boolean isUnlockedDeviceRequired = false; 1243 1244 if (isLeanbackOnly()) { 1245 return; 1246 } 1247 1248 KeyguardManager keyguardManager = (KeyguardManager)getContext().getSystemService(Context.KEYGUARD_SERVICE); 1249 assertFalse(keyguardManager.isDeviceLocked()); 1250 1251 for (String algorithm : EXPECTED_ALGORITHMS) { 1252 try { 1253 importKatKeys(algorithm, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT, 1254 false, isUnlockedDeviceRequired, isUserAuthRequired); 1255 fail("Importing auth bound keys to an insecure device should fail"); 1256 } catch (KeyStoreException e) { 1257 // Expected behavior 1258 assertThat(e.getCause()).isInstanceOf(IllegalStateException.class); 1259 } 1260 } 1261 } 1262 1263 @Test testInitDecryptFailsWhenNotAuthorizedToDecrypt()1264 public void testInitDecryptFailsWhenNotAuthorizedToDecrypt() throws Exception { 1265 for (String transformation : EXPECTED_ALGORITHMS) { 1266 try { 1267 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1268 transformation, 1269 KeyProperties.PURPOSE_DECRYPT); 1270 assertInitDecryptSucceeds(transformation, good); 1271 assertInitDecryptThrowsInvalidKeyException(transformation, 1272 TestUtils.buildUpon(good, KeyProperties.PURPOSE_ENCRYPT).build()); 1273 } catch (Throwable e) { 1274 throw new RuntimeException("Failed for " + transformation, e); 1275 } 1276 } 1277 } 1278 1279 @Test testInitEncryptSymmetricFailsWhenNotAuthorizedToEncrypt()1280 public void testInitEncryptSymmetricFailsWhenNotAuthorizedToEncrypt() throws Exception { 1281 for (String transformation : EXPECTED_ALGORITHMS) { 1282 if (!isSymmetric(transformation)) { 1283 continue; 1284 } 1285 1286 try { 1287 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1288 transformation, 1289 KeyProperties.PURPOSE_ENCRYPT); 1290 assertInitEncryptSucceeds(transformation, good); 1291 assertInitEncryptThrowsInvalidKeyException(transformation, 1292 TestUtils.buildUpon(good, KeyProperties.PURPOSE_DECRYPT).build()); 1293 } catch (Throwable e) { 1294 throw new RuntimeException("Failed for " + transformation, e); 1295 } 1296 } 1297 } 1298 1299 @Test testInitEncryptAsymmetricIgnoresAuthorizedPurposes()1300 public void testInitEncryptAsymmetricIgnoresAuthorizedPurposes() throws Exception { 1301 for (String transformation : EXPECTED_ALGORITHMS) { 1302 if (isSymmetric(transformation)) { 1303 continue; 1304 } 1305 1306 try { 1307 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1308 transformation, 1309 KeyProperties.PURPOSE_ENCRYPT); 1310 assertInitEncryptSucceeds(transformation, good); 1311 assertInitEncryptSucceeds(transformation, 1312 TestUtils.buildUpon(good, 0).build()); 1313 } catch (Throwable e) { 1314 throw new RuntimeException("Failed for " + transformation, e); 1315 } 1316 } 1317 } 1318 1319 @Test testInitDecryptFailsWhenBlockModeNotAuthorized()1320 public void testInitDecryptFailsWhenBlockModeNotAuthorized() throws Exception { 1321 for (String transformation : EXPECTED_ALGORITHMS) { 1322 if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase( 1323 TestUtils.getCipherKeyAlgorithm(transformation))) { 1324 // Block modes do not apply 1325 continue; 1326 } 1327 1328 String goodBlockMode = TestUtils.getCipherBlockMode(transformation); 1329 String badBlockMode = KeyProperties.BLOCK_MODE_CBC.equalsIgnoreCase(goodBlockMode) 1330 ? KeyProperties.BLOCK_MODE_CTR : KeyProperties.BLOCK_MODE_CBC; 1331 1332 try { 1333 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1334 transformation, 1335 KeyProperties.PURPOSE_DECRYPT); 1336 assertInitDecryptSucceeds(transformation, good); 1337 assertInitDecryptThrowsInvalidKeyException(transformation, 1338 TestUtils.buildUpon(good).setBlockModes(badBlockMode).build()); 1339 } catch (Throwable e) { 1340 throw new RuntimeException( 1341 "Failed for " + transformation + " when authorized only for " 1342 + badBlockMode, 1343 e); 1344 } 1345 } 1346 } 1347 1348 @Test testInitEncryptSymmetricFailsWhenBlockModeNotAuthorized()1349 public void testInitEncryptSymmetricFailsWhenBlockModeNotAuthorized() throws Exception { 1350 for (String transformation : EXPECTED_ALGORITHMS) { 1351 if (!isSymmetric(transformation)) { 1352 continue; 1353 } 1354 1355 if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase( 1356 TestUtils.getCipherKeyAlgorithm(transformation))) { 1357 // Block modes do not apply 1358 continue; 1359 } 1360 1361 String goodBlockMode = TestUtils.getCipherBlockMode(transformation); 1362 String badBlockMode = KeyProperties.BLOCK_MODE_CBC.equalsIgnoreCase(goodBlockMode) 1363 ? KeyProperties.BLOCK_MODE_CTR : KeyProperties.BLOCK_MODE_CBC; 1364 1365 try { 1366 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1367 transformation, 1368 KeyProperties.PURPOSE_ENCRYPT); 1369 1370 assertInitEncryptSucceeds(transformation, good); 1371 assertInitEncryptThrowsInvalidKeyException(transformation, 1372 TestUtils.buildUpon(good).setBlockModes(badBlockMode).build()); 1373 } catch (Throwable e) { 1374 throw new RuntimeException( 1375 "Failed for " + transformation + " when authorized only for " 1376 + badBlockMode, 1377 e); 1378 } 1379 } 1380 } 1381 1382 @Test testInitEncryptAsymmetricIgnoresAuthorizedBlockModes()1383 public void testInitEncryptAsymmetricIgnoresAuthorizedBlockModes() throws Exception { 1384 for (String transformation : EXPECTED_ALGORITHMS) { 1385 if (isSymmetric(transformation)) { 1386 continue; 1387 } 1388 1389 try { 1390 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1391 transformation, 1392 KeyProperties.PURPOSE_ENCRYPT); 1393 1394 assertInitEncryptSucceeds(transformation, good); 1395 assertInitEncryptSucceeds(transformation, 1396 TestUtils.buildUpon(good).setBlockModes().build()); 1397 } catch (Throwable e) { 1398 throw new RuntimeException("Failed for " + transformation, e); 1399 } 1400 } 1401 } 1402 1403 @Test testInitDecryptFailsWhenDigestNotAuthorized()1404 public void testInitDecryptFailsWhenDigestNotAuthorized() throws Exception { 1405 for (String transformation : EXPECTED_ALGORITHMS) { 1406 String impliedDigest = TestUtils.getCipherDigest(transformation); 1407 if (impliedDigest == null) { 1408 // No digest used by this transformation 1409 continue; 1410 } 1411 1412 String badDigest = KeyProperties.DIGEST_SHA256.equalsIgnoreCase(impliedDigest) 1413 ? KeyProperties.DIGEST_SHA512 : KeyProperties.DIGEST_SHA256; 1414 try { 1415 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1416 transformation, 1417 KeyProperties.PURPOSE_DECRYPT); 1418 1419 assertInitDecryptSucceeds(transformation, good); 1420 assertInitDecryptThrowsInvalidKeyException(transformation, 1421 TestUtils.buildUpon(good).setDigests(badDigest).build()); 1422 1423 if (!KeyProperties.DIGEST_NONE.equalsIgnoreCase(impliedDigest)) { 1424 // Check that authorized digest NONE does not mean ANY digest is authorized. 1425 badDigest = KeyProperties.DIGEST_NONE; 1426 assertInitDecryptThrowsInvalidKeyException(transformation, 1427 TestUtils.buildUpon(good).setDigests(badDigest).build()); 1428 } 1429 } catch (Throwable e) { 1430 throw new RuntimeException( 1431 "Failed for " + transformation + " when authorized only for " + badDigest, 1432 e); 1433 } 1434 } 1435 } 1436 1437 @Test testInitEncryptSymmetricFailsWhenDigestNotAuthorized()1438 public void testInitEncryptSymmetricFailsWhenDigestNotAuthorized() throws Exception { 1439 for (String transformation : EXPECTED_ALGORITHMS) { 1440 if (!isSymmetric(transformation)) { 1441 continue; 1442 } 1443 1444 String impliedDigest = TestUtils.getCipherDigest(transformation); 1445 if (impliedDigest == null) { 1446 // No digest used by this transformation 1447 continue; 1448 } 1449 1450 String badDigest = KeyProperties.DIGEST_SHA256.equalsIgnoreCase(impliedDigest) 1451 ? KeyProperties.DIGEST_SHA512 : KeyProperties.DIGEST_SHA256; 1452 1453 try { 1454 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1455 transformation, 1456 KeyProperties.PURPOSE_ENCRYPT); 1457 assertInitEncryptSucceeds(transformation, good); 1458 assertInitEncryptThrowsInvalidKeyException(transformation, 1459 TestUtils.buildUpon(good).setDigests(badDigest).build()); 1460 1461 if (!KeyProperties.DIGEST_NONE.equalsIgnoreCase(impliedDigest)) { 1462 // Check that authorized digest NONE does not mean ANY digest is authorized. 1463 badDigest = KeyProperties.DIGEST_NONE; 1464 assertInitEncryptThrowsInvalidKeyException(transformation, 1465 TestUtils.buildUpon(good).setDigests(badDigest).build()); 1466 } 1467 } catch (Throwable e) { 1468 throw new RuntimeException( 1469 "Failed for " + transformation + " when authorized only for " + badDigest, 1470 e); 1471 } 1472 } 1473 } 1474 1475 @Test testInitEncryptAsymmetricIgnoresAuthorizedDigests()1476 public void testInitEncryptAsymmetricIgnoresAuthorizedDigests() throws Exception { 1477 for (String transformation : EXPECTED_ALGORITHMS) { 1478 if (isSymmetric(transformation)) { 1479 continue; 1480 } 1481 try { 1482 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1483 transformation, 1484 KeyProperties.PURPOSE_ENCRYPT); 1485 assertInitEncryptSucceeds(transformation, good); 1486 assertInitEncryptSucceeds(transformation, 1487 TestUtils.buildUpon(good).setDigests().build()); 1488 } catch (Throwable e) { 1489 throw new RuntimeException("Failed for " + transformation, e); 1490 } 1491 } 1492 } 1493 1494 @Test testInitDecryptFailsWhenPaddingSchemeNotAuthorized()1495 public void testInitDecryptFailsWhenPaddingSchemeNotAuthorized() throws Exception { 1496 for (String transformation : EXPECTED_ALGORITHMS) { 1497 String impliedEncryptionPadding = TestUtils.getCipherEncryptionPadding(transformation); 1498 String badEncryptionPadding; 1499 if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase( 1500 TestUtils.getCipherKeyAlgorithm(transformation))) { 1501 badEncryptionPadding = 1502 KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1.equalsIgnoreCase( 1503 impliedEncryptionPadding) 1504 ? KeyProperties.ENCRYPTION_PADDING_RSA_OAEP 1505 : KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1; 1506 } else { 1507 badEncryptionPadding = KeyProperties.ENCRYPTION_PADDING_PKCS7.equalsIgnoreCase( 1508 impliedEncryptionPadding) 1509 ? KeyProperties.ENCRYPTION_PADDING_NONE 1510 : KeyProperties.ENCRYPTION_PADDING_PKCS7; 1511 } 1512 try { 1513 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1514 transformation, 1515 KeyProperties.PURPOSE_DECRYPT); 1516 1517 assertInitDecryptSucceeds(transformation, good); 1518 assertInitDecryptThrowsInvalidKeyException(transformation, 1519 TestUtils.buildUpon(good) 1520 .setEncryptionPaddings(badEncryptionPadding) 1521 .build()); 1522 1523 if (!KeyProperties.ENCRYPTION_PADDING_NONE.equalsIgnoreCase( 1524 impliedEncryptionPadding)) { 1525 // Check that authorized padding NONE does not mean ANY padding is authorized. 1526 badEncryptionPadding = KeyProperties.ENCRYPTION_PADDING_NONE; 1527 assertInitDecryptThrowsInvalidKeyException(transformation, 1528 TestUtils.buildUpon(good) 1529 .setEncryptionPaddings(badEncryptionPadding) 1530 .build()); 1531 } 1532 } catch (Throwable e) { 1533 throw new RuntimeException( 1534 "Failed for " + transformation + " when authorized only for " 1535 + badEncryptionPadding, 1536 e); 1537 } 1538 } 1539 } 1540 1541 @Test testInitEncryptSymmetricFailsWhenPaddingSchemeNotAuthorized()1542 public void testInitEncryptSymmetricFailsWhenPaddingSchemeNotAuthorized() throws Exception { 1543 for (String transformation : EXPECTED_ALGORITHMS) { 1544 if (!isSymmetric(transformation)) { 1545 continue; 1546 } 1547 String impliedEncryptionPadding = TestUtils.getCipherEncryptionPadding(transformation); 1548 String badEncryptionPadding = KeyProperties.ENCRYPTION_PADDING_PKCS7.equalsIgnoreCase( 1549 impliedEncryptionPadding) 1550 ? KeyProperties.ENCRYPTION_PADDING_NONE 1551 : KeyProperties.ENCRYPTION_PADDING_PKCS7; 1552 try { 1553 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1554 transformation, 1555 KeyProperties.PURPOSE_ENCRYPT); 1556 1557 assertInitEncryptSucceeds(transformation, good); 1558 assertInitEncryptThrowsInvalidKeyException(transformation, 1559 TestUtils.buildUpon(good) 1560 .setEncryptionPaddings(badEncryptionPadding) 1561 .build()); 1562 1563 if (!KeyProperties.ENCRYPTION_PADDING_NONE.equalsIgnoreCase( 1564 impliedEncryptionPadding)) { 1565 // Check that authorized padding NONE does not mean ANY padding is authorized. 1566 badEncryptionPadding = KeyProperties.ENCRYPTION_PADDING_NONE; 1567 assertInitEncryptThrowsInvalidKeyException(transformation, 1568 TestUtils.buildUpon(good) 1569 .setEncryptionPaddings(badEncryptionPadding) 1570 .build()); 1571 } 1572 } catch (Throwable e) { 1573 throw new RuntimeException( 1574 "Failed for " + transformation + " when authorized only for " 1575 + badEncryptionPadding, 1576 e); 1577 } 1578 } 1579 } 1580 1581 @Test testInitEncryptAsymmetricIgnoresAuthorizedPaddingSchemes()1582 public void testInitEncryptAsymmetricIgnoresAuthorizedPaddingSchemes() throws Exception { 1583 for (String transformation : EXPECTED_ALGORITHMS) { 1584 if (isSymmetric(transformation)) { 1585 continue; 1586 } 1587 try { 1588 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1589 transformation, 1590 KeyProperties.PURPOSE_ENCRYPT); 1591 1592 assertInitEncryptSucceeds(transformation, good); 1593 assertInitEncryptSucceeds(transformation, 1594 TestUtils.buildUpon(good) 1595 .setEncryptionPaddings() 1596 .setSignaturePaddings() 1597 .build()); 1598 } catch (Throwable e) { 1599 throw new RuntimeException("Failed for " + transformation, e); 1600 } 1601 } 1602 } 1603 1604 @Test testInitDecryptFailsWhenKeyNotYetValid()1605 public void testInitDecryptFailsWhenKeyNotYetValid() throws Exception { 1606 Date badStartDate = new Date(System.currentTimeMillis() + DAY_IN_MILLIS); 1607 for (String transformation : EXPECTED_ALGORITHMS) { 1608 try { 1609 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1610 transformation, 1611 KeyProperties.PURPOSE_DECRYPT); 1612 1613 assertInitDecryptSucceeds(transformation, good); 1614 assertInitDecryptThrowsInvalidKeyException(transformation, 1615 TestUtils.buildUpon(good).setKeyValidityStart(badStartDate).build()); 1616 } catch (Throwable e) { 1617 throw new RuntimeException("Failed for " + transformation, e); 1618 } 1619 } 1620 } 1621 1622 @Test testInitEncryptSymmetricFailsWhenKeyNotYetValid()1623 public void testInitEncryptSymmetricFailsWhenKeyNotYetValid() throws Exception { 1624 Date badStartDate = new Date(System.currentTimeMillis() + DAY_IN_MILLIS); 1625 for (String transformation : EXPECTED_ALGORITHMS) { 1626 if (!isSymmetric(transformation)) { 1627 continue; 1628 } 1629 try { 1630 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1631 transformation, 1632 KeyProperties.PURPOSE_ENCRYPT); 1633 1634 assertInitEncryptSucceeds(transformation, good); 1635 assertInitEncryptThrowsInvalidKeyException(transformation, 1636 TestUtils.buildUpon(good).setKeyValidityStart(badStartDate).build()); 1637 } catch (Throwable e) { 1638 throw new RuntimeException("Failed for " + transformation, e); 1639 } 1640 } 1641 } 1642 1643 @Test testInitEncryptAsymmetricIgnoresThatKeyNotYetValid()1644 public void testInitEncryptAsymmetricIgnoresThatKeyNotYetValid() throws Exception { 1645 Date badStartDate = new Date(System.currentTimeMillis() + DAY_IN_MILLIS); 1646 for (String transformation : EXPECTED_ALGORITHMS) { 1647 if (isSymmetric(transformation)) { 1648 continue; 1649 } 1650 try { 1651 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1652 transformation, 1653 KeyProperties.PURPOSE_ENCRYPT); 1654 1655 assertInitEncryptSucceeds(transformation, good); 1656 assertInitEncryptSucceeds(transformation, 1657 TestUtils.buildUpon(good).setKeyValidityStart(badStartDate).build()); 1658 } catch (Throwable e) { 1659 throw new RuntimeException("Failed for " + transformation, e); 1660 } 1661 } 1662 } 1663 1664 @Test testInitDecryptFailsWhenKeyNoLongerValidForConsumption()1665 public void testInitDecryptFailsWhenKeyNoLongerValidForConsumption() throws Exception { 1666 Date badEndDate = new Date(System.currentTimeMillis() - DAY_IN_MILLIS); 1667 for (String transformation : EXPECTED_ALGORITHMS) { 1668 try { 1669 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1670 transformation, 1671 KeyProperties.PURPOSE_DECRYPT); 1672 1673 assertInitDecryptSucceeds(transformation, good); 1674 assertInitDecryptThrowsInvalidKeyException(transformation, 1675 TestUtils.buildUpon(good) 1676 .setKeyValidityForConsumptionEnd(badEndDate) 1677 .build()); 1678 } catch (Throwable e) { 1679 throw new RuntimeException("Failed for " + transformation, e); 1680 } 1681 } 1682 } 1683 1684 @Test testInitDecryptIgnoresThatKeyNoLongerValidForOrigination()1685 public void testInitDecryptIgnoresThatKeyNoLongerValidForOrigination() throws Exception { 1686 Date badEndDate = new Date(System.currentTimeMillis() - DAY_IN_MILLIS); 1687 for (String transformation : EXPECTED_ALGORITHMS) { 1688 try { 1689 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1690 transformation, 1691 KeyProperties.PURPOSE_DECRYPT); 1692 1693 assertInitDecryptSucceeds(transformation, good); 1694 assertInitDecryptSucceeds(transformation, 1695 TestUtils.buildUpon(good) 1696 .setKeyValidityForOriginationEnd(badEndDate) 1697 .build()); 1698 } catch (Throwable e) { 1699 throw new RuntimeException("Failed for " + transformation, e); 1700 } 1701 } 1702 } 1703 1704 @Test testInitEncryptSymmetricFailsWhenKeyNoLongerValidForOrigination()1705 public void testInitEncryptSymmetricFailsWhenKeyNoLongerValidForOrigination() throws Exception { 1706 Date badEndDate = new Date(System.currentTimeMillis() - DAY_IN_MILLIS); 1707 for (String transformation : EXPECTED_ALGORITHMS) { 1708 if (!isSymmetric(transformation)) { 1709 continue; 1710 } 1711 try { 1712 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1713 transformation, 1714 KeyProperties.PURPOSE_ENCRYPT); 1715 1716 assertInitEncryptSucceeds(transformation, good); 1717 assertInitEncryptThrowsInvalidKeyException(transformation, 1718 TestUtils.buildUpon(good) 1719 .setKeyValidityForOriginationEnd(badEndDate) 1720 .build()); 1721 } catch (Throwable e) { 1722 throw new RuntimeException("Failed for " + transformation, e); 1723 } 1724 } 1725 } 1726 1727 @Test testInitEncryptSymmetricIgnoresThatKeyNoLongerValidForConsumption()1728 public void testInitEncryptSymmetricIgnoresThatKeyNoLongerValidForConsumption() 1729 throws Exception { 1730 Date badEndDate = new Date(System.currentTimeMillis() - DAY_IN_MILLIS); 1731 for (String transformation : EXPECTED_ALGORITHMS) { 1732 if (!isSymmetric(transformation)) { 1733 continue; 1734 } 1735 try { 1736 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1737 transformation, 1738 KeyProperties.PURPOSE_ENCRYPT); 1739 1740 assertInitEncryptSucceeds(transformation, good); 1741 assertInitEncryptSucceeds(transformation, 1742 TestUtils.buildUpon(good) 1743 .setKeyValidityForConsumptionEnd(badEndDate) 1744 .build()); 1745 } catch (Throwable e) { 1746 throw new RuntimeException("Failed for " + transformation, e); 1747 } 1748 } 1749 } 1750 1751 @Test testInitEncryptAsymmetricIgnoresThatKeyNoLongerValid()1752 public void testInitEncryptAsymmetricIgnoresThatKeyNoLongerValid() throws Exception { 1753 Date badEndDate = new Date(System.currentTimeMillis() - DAY_IN_MILLIS); 1754 for (String transformation : EXPECTED_ALGORITHMS) { 1755 if (isSymmetric(transformation)) { 1756 continue; 1757 } 1758 try { 1759 KeyProtection good = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1760 transformation, 1761 KeyProperties.PURPOSE_ENCRYPT); 1762 1763 assertInitEncryptSucceeds(transformation, good); 1764 assertInitEncryptSucceeds(transformation, 1765 TestUtils.buildUpon(good) 1766 .setKeyValidityForOriginationEnd(badEndDate) 1767 .build()); 1768 assertInitEncryptSucceeds(transformation, 1769 TestUtils.buildUpon(good) 1770 .setKeyValidityForConsumptionEnd(badEndDate) 1771 .build()); 1772 } catch (Throwable e) { 1773 throw new RuntimeException("Failed for " + transformation, e); 1774 } 1775 } 1776 } 1777 getWorkingDecryptionParameterSpec(String transformation)1778 private AlgorithmParameterSpec getWorkingDecryptionParameterSpec(String transformation) { 1779 String keyAlgorithm = TestUtils.getCipherKeyAlgorithm(transformation); 1780 if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) { 1781 return null; 1782 } else if (KeyProperties.KEY_ALGORITHM_AES.equalsIgnoreCase(keyAlgorithm)) { 1783 String blockMode = TestUtils.getCipherBlockMode(transformation); 1784 if (KeyProperties.BLOCK_MODE_ECB.equalsIgnoreCase(blockMode)) { 1785 return null; 1786 } else if ((KeyProperties.BLOCK_MODE_CBC.equalsIgnoreCase(blockMode)) 1787 || (KeyProperties.BLOCK_MODE_CTR.equalsIgnoreCase(blockMode))) { 1788 return new IvParameterSpec( 1789 new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}); 1790 } else if (KeyProperties.BLOCK_MODE_GCM.equalsIgnoreCase(blockMode)) { 1791 return new GCMParameterSpec( 1792 128, 1793 new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); 1794 } else { 1795 throw new IllegalArgumentException("Unsupported block mode: " + blockMode); 1796 } 1797 } else if (KeyProperties.KEY_ALGORITHM_3DES.equalsIgnoreCase(keyAlgorithm)) { 1798 String blockMode = TestUtils.getCipherBlockMode(transformation); 1799 if (KeyProperties.BLOCK_MODE_ECB.equalsIgnoreCase(blockMode)) { 1800 return null; 1801 } else if (KeyProperties.BLOCK_MODE_CBC.equalsIgnoreCase(blockMode)) { 1802 return new IvParameterSpec( 1803 new byte[]{1, 2, 3, 4, 5, 6, 7, 8}); 1804 } else { 1805 throw new IllegalArgumentException("Unsupported block mode: " + blockMode); 1806 } 1807 } else { 1808 throw new IllegalArgumentException("Unsupported key algorithm: " + keyAlgorithm); 1809 } 1810 } 1811 assertInitDecryptSucceeds(String transformation, KeyProtection importParams)1812 private void assertInitDecryptSucceeds(String transformation, KeyProtection importParams) 1813 throws Exception { 1814 Cipher cipher = Cipher.getInstance(transformation, EXPECTED_PROVIDER_NAME); 1815 Key key = 1816 importDefaultKatKey(transformation, importParams).getKeystoreBackedDecryptionKey(); 1817 AlgorithmParameterSpec params = getWorkingDecryptionParameterSpec(transformation); 1818 cipher.init(Cipher.DECRYPT_MODE, key, params); 1819 } 1820 assertInitDecryptThrowsInvalidKeyException( String transformation, KeyProtection importParams)1821 private void assertInitDecryptThrowsInvalidKeyException( 1822 String transformation, KeyProtection importParams) throws Exception { 1823 Cipher cipher = Cipher.getInstance(transformation, EXPECTED_PROVIDER_NAME); 1824 Key key = 1825 importDefaultKatKey(transformation, importParams).getKeystoreBackedDecryptionKey(); 1826 AlgorithmParameterSpec params = getWorkingDecryptionParameterSpec(transformation); 1827 try { 1828 cipher.init(Cipher.DECRYPT_MODE, key, params); 1829 fail("InvalidKeyException should have been thrown"); 1830 } catch (InvalidKeyException | RuntimeException expected) {} 1831 } 1832 assertInitEncryptSucceeds(String transformation, KeyProtection importParams)1833 private void assertInitEncryptSucceeds(String transformation, KeyProtection importParams) 1834 throws Exception { 1835 Cipher cipher = Cipher.getInstance(transformation, EXPECTED_PROVIDER_NAME); 1836 Key key = 1837 importDefaultKatKey(transformation, importParams).getKeystoreBackedEncryptionKey(); 1838 cipher.init(Cipher.ENCRYPT_MODE, key); 1839 } 1840 assertInitEncryptThrowsInvalidKeyException( String transformation, KeyProtection importParams)1841 private void assertInitEncryptThrowsInvalidKeyException( 1842 String transformation, KeyProtection importParams) throws Exception { 1843 Cipher cipher = Cipher.getInstance(transformation, EXPECTED_PROVIDER_NAME); 1844 Key key = 1845 importDefaultKatKey(transformation, importParams).getKeystoreBackedEncryptionKey(); 1846 try { 1847 cipher.init(Cipher.ENCRYPT_MODE, key); 1848 fail("InvalidKeyException should have been thrown"); 1849 } catch (InvalidKeyException expected) {} 1850 } 1851 importDefaultKatKey( String transformation, KeyProtection importParams)1852 private ImportedKey importDefaultKatKey( 1853 String transformation, KeyProtection importParams) 1854 throws Exception { 1855 String keyAlgorithm = TestUtils.getCipherKeyAlgorithm(transformation); 1856 if (KeyProperties.KEY_ALGORITHM_AES.equalsIgnoreCase(keyAlgorithm)) { 1857 return TestUtils.importIntoAndroidKeyStore( 1858 "testAES", 1859 new SecretKeySpec(AES128_KAT_KEY_BYTES, "AES"), 1860 importParams); 1861 } else if (KeyProperties.KEY_ALGORITHM_3DES.equalsIgnoreCase(keyAlgorithm)) { 1862 return TestUtils.importIntoAndroidKeyStore( 1863 "test3DES", 1864 new SecretKeySpec(DESede_KAT_KEY_BYTES, "DESede"), 1865 importParams); 1866 } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) { 1867 return TestUtils.importIntoAndroidKeyStore( 1868 "testRSA", 1869 getContext(), 1870 R.raw.rsa_key2_pkcs8, 1871 R.raw.rsa_key2_cert, 1872 importParams); 1873 } else { 1874 throw new IllegalArgumentException("Unsupported key algorithm: " + keyAlgorithm); 1875 } 1876 } 1877 importDefaultKatKey( String transformation, int purposes, boolean ivProvidedWhenEncrypting)1878 private ImportedKey importDefaultKatKey( 1879 String transformation, int purposes, boolean ivProvidedWhenEncrypting) 1880 throws Exception { 1881 KeyProtection importParams = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1882 transformation, purposes, ivProvidedWhenEncrypting); 1883 return importDefaultKatKey(transformation, importParams); 1884 } 1885 importKatKeys( String transformation, int purposes, boolean ivProvidedWhenEncrypting)1886 private Collection<ImportedKey> importKatKeys( 1887 String transformation, int purposes, boolean ivProvidedWhenEncrypting) 1888 throws Exception { 1889 return importKatKeys(transformation, purposes, ivProvidedWhenEncrypting, false, false); 1890 } 1891 importKatKeys( String transformation, int purposes, boolean ivProvidedWhenEncrypting, boolean isUnlockedDeviceRequired, boolean isUserAuthRequired)1892 private Collection<ImportedKey> importKatKeys( 1893 String transformation, int purposes, boolean ivProvidedWhenEncrypting, 1894 boolean isUnlockedDeviceRequired, boolean isUserAuthRequired) throws Exception { 1895 KeyProtection importParams = TestUtils.getMinimalWorkingImportParametersForCipheringWith( 1896 transformation, purposes, ivProvidedWhenEncrypting, isUnlockedDeviceRequired, 1897 isUserAuthRequired); 1898 String keyAlgorithm = TestUtils.getCipherKeyAlgorithm(transformation); 1899 if (KeyProperties.KEY_ALGORITHM_AES.equalsIgnoreCase(keyAlgorithm)) { 1900 return Arrays.asList( 1901 TestUtils.importIntoAndroidKeyStore( 1902 "testAES128", 1903 new SecretKeySpec(AES128_KAT_KEY_BYTES, "AES"), 1904 importParams), 1905 TestUtils.importIntoAndroidKeyStore( 1906 "testAES192", 1907 new SecretKeySpec(AES192_KAT_KEY_BYTES, "AES"), 1908 importParams), 1909 TestUtils.importIntoAndroidKeyStore( 1910 "testAES256", 1911 new SecretKeySpec(AES256_KAT_KEY_BYTES, "AES"), 1912 importParams) 1913 ); 1914 } else if (KeyProperties.KEY_ALGORITHM_3DES.equalsIgnoreCase(keyAlgorithm)) { 1915 return Arrays.asList(TestUtils.importIntoAndroidKeyStore( 1916 "test3DES", 1917 new SecretKeySpec(DESede_KAT_KEY_BYTES, "DESede"), 1918 importParams) 1919 ); 1920 } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) { 1921 return RSASignatureTest.importKatKeyPairs(getContext(), importParams); 1922 } else { 1923 throw new IllegalArgumentException("Unsupported key algorithm: " + keyAlgorithm); 1924 } 1925 } 1926 isSymmetric(String transformation)1927 private static boolean isSymmetric(String transformation) { 1928 return TestUtils.isCipherSymmetric(transformation); 1929 } 1930 truncatePlaintextIfNecessary( String transformation, Key encryptionKey, byte[] plaintext)1931 private static byte[] truncatePlaintextIfNecessary( 1932 String transformation, Key encryptionKey, byte[] plaintext) { 1933 int maxSupportedPlaintextSizeBytes = 1934 TestUtils.getMaxSupportedPlaintextInputSizeBytes( 1935 transformation, encryptionKey); 1936 if (plaintext.length <= maxSupportedPlaintextSizeBytes) { 1937 // No need to truncate 1938 return plaintext; 1939 } else if (maxSupportedPlaintextSizeBytes < 0) { 1940 // Key too short to encrypt anything at all using this transformation 1941 return null; 1942 } else { 1943 // Truncate plaintext to exercise this transformation with this key 1944 return Arrays.copyOf(plaintext, maxSupportedPlaintextSizeBytes); 1945 } 1946 } 1947 } 1948