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