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