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