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