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