• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Licensed under the Apache License, Version 2.0 (the "License");
3  * you may not use this file except in compliance with the License.
4  * You may obtain a copy of the License at
5  *
6  *   http://www.apache.org/licenses/LICENSE-2.0
7  *
8  * Unless required by applicable law or agreed to in writing, software
9  * distributed under the License is distributed on an "AS IS" BASIS,
10  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  * See the License for the specific language governing permissions and
12  * limitations under the License.
13  */
14 package com.google.security.wycheproof;
15 
16 import static org.junit.Assert.assertEquals;
17 import static org.junit.Assert.assertTrue;
18 import static org.junit.Assume.assumeTrue;
19 
20 import com.google.gson.JsonElement;
21 import com.google.gson.JsonObject;
22 import java.math.BigInteger;
23 import java.security.AlgorithmParameters;
24 import java.security.GeneralSecurityException;
25 import java.security.KeyFactory;
26 import java.security.KeyStore;
27 import java.security.NoSuchAlgorithmException;
28 import java.security.PrivateKey;
29 import java.security.PublicKey;
30 import java.security.spec.AlgorithmParameterSpec;
31 import java.security.spec.MGF1ParameterSpec;
32 import java.security.spec.PKCS8EncodedKeySpec;
33 import java.security.spec.RSAPublicKeySpec;
34 import java.security.spec.X509EncodedKeySpec;
35 import javax.crypto.Cipher;
36 import javax.crypto.spec.OAEPParameterSpec;
37 import javax.crypto.spec.PSource;
38 import org.junit.After;
39 import org.junit.Test;
40 import org.junit.Ignore;
41 import android.security.Flags;
42 import android.security.keystore.KeyProtection;
43 import android.security.keystore.KeyProperties;
44 import android.keystore.cts.util.KeyStoreUtil;
45 import android.keystore.cts.util.TestUtils;
46 import android.text.TextUtils;
47 import android.util.Log;
48 
49 /**
50  * Checks implementations of RSA-OAEP.
51  */
52 public class RsaOaepTest {
53   private static final String TAG = "RsaOaepTest";
54   private static final String EXPECTED_PROVIDER_NAME = TestUtil.EXPECTED_CRYPTO_OP_PROVIDER_NAME;
55   private static final String KEY_ALIAS_1 = "TestKey";
56 
57   @After
tearDown()58   public void tearDown() throws Exception {
59     KeyStoreUtil.cleanUpKeyStore();
60   }
61 
saveKeyPairToKeystoreAndReturnPrivateKey(PublicKey pubKey, PrivateKey privKey, String digest, String mgfDigest, boolean isStrongBox)62   private static PrivateKey saveKeyPairToKeystoreAndReturnPrivateKey(PublicKey pubKey,
63         PrivateKey privKey, String digest, String mgfDigest, boolean isStrongBox)
64           throws Exception {
65     KeyProtection.Builder keyProtection = new KeyProtection.Builder(KeyProperties.PURPOSE_SIGN |
66             KeyProperties.PURPOSE_VERIFY |
67             KeyProperties.PURPOSE_ENCRYPT |
68             KeyProperties.PURPOSE_DECRYPT)
69             .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
70                     KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
71             .setIsStrongBoxBacked(isStrongBox);
72     if (Flags.mgf1DigestSetterV2()) {
73       keyProtection.setDigests(digest);
74       keyProtection.setMgf1Digests(mgfDigest);
75     } else {
76       if (digest.equalsIgnoreCase(mgfDigest)) {
77         keyProtection.setDigests(digest);
78       } else {
79         keyProtection.setDigests(digest, mgfDigest);
80       }
81     }
82     return (PrivateKey) KeyStoreUtil.saveKeysToKeystore(KEY_ALIAS_1, pubKey, privKey,
83             keyProtection.build()).getKey(KEY_ALIAS_1, null);
84   }
85 
86   /**
87    * A list of algorithm names for RSA-OAEP.
88    *
89    * The standard algorithm names for RSA-OAEP are defined in
90    * https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html
91    */
92   static String[] OaepAlgorithmNames = {
93       "RSA/None/OAEPPadding",
94       "RSA/None/OAEPwithSHA-1andMGF1Padding",
95       "RSA/None/OAEPwithSHA-224andMGF1Padding",
96       "RSA/None/OAEPwithSHA-256andMGF1Padding",
97       "RSA/None/OAEPwithSHA-384andMGF1Padding",
98       "RSA/None/OAEPwithSHA-512andMGF1Padding",
99   };
100 
printParameters(AlgorithmParameterSpec params)101   protected static void printParameters(AlgorithmParameterSpec params) {
102     if (params instanceof OAEPParameterSpec) {
103       OAEPParameterSpec oaepParams = (OAEPParameterSpec) params;
104       Log.d(TAG, "OAEPParameterSpec");
105       Log.d(TAG, "digestAlgorithm:" + oaepParams.getDigestAlgorithm());
106       Log.d(TAG, "mgfAlgorithm:" + oaepParams.getMGFAlgorithm());
107       printParameters(oaepParams.getMGFParameters());
108     } else if (params instanceof MGF1ParameterSpec) {
109       MGF1ParameterSpec mgf1Params = (MGF1ParameterSpec) params;
110       Log.d(TAG, "MGF1ParameterSpec");
111       Log.d(TAG, "digestAlgorithm:" + mgf1Params.getDigestAlgorithm());
112     } else {
113       Log.d(TAG, params.toString());
114     }
115   }
116 
117   /**
118    * This is not a real test. The JCE algorithm names only specify one hash algorithm. But OAEP
119    * uses two hases. One hash algorithm is used to hash the labels. The other hash algorithm is
120    * used for the mask generation function.
121    *
122    * <p>Different provider use different default values for the hash function that is not specified
123    * in the algorithm name. Jdk uses mgfsha1 as default. BouncyCastle and Conscrypt use the same
124    * hash for labels and mgf. Every provider allows to specify all the parameters using
125    * an OAEPParameterSpec instance.
126    *
127    * <p>This test simply tries a number of algorithm names for RSA-OAEP and prints the OAEP
128    * parameters for the case where no OAEPParameterSpec is used.
129    */
130   // TODO(bleichen): jdk11 will also add parameters to the RSA keys. This will need more tests.
131   @Test
testDefaults()132   public void testDefaults() throws Exception {
133     String pubKey =
134         "30820122300d06092a864886f70d01010105000382010f003082010a02820101"
135             + "00bdf90898577911c71c4d9520c5f75108548e8dfd389afdbf9c997769b8594e"
136             + "7dc51c6a1b88d1670ec4bb03fa550ba6a13d02c430bfe88ae4e2075163017f4d"
137             + "8926ce2e46e068e88962f38112fc2dbd033e84e648d4a816c0f5bd89cadba0b4"
138             + "d6cac01832103061cbb704ebacd895def6cff9d988c5395f2169a6807207333d"
139             + "569150d7f569f7ebf4718ddbfa2cdbde4d82a9d5d8caeb467f71bfc0099b0625"
140             + "a59d2bad12e3ff48f2fd50867b89f5f876ce6c126ced25f28b1996ee21142235"
141             + "fb3aef9fe58d9e4ef6e4922711a3bbcd8adcfe868481fd1aa9c13e5c658f5172"
142             + "617204314665092b4d8dca1b05dc7f4ecd7578b61edeb949275be8751a5a1fab"
143             + "c30203010001";
144     KeyFactory kf;
145     kf = KeyFactory.getInstance("RSA");
146     X509EncodedKeySpec x509keySpec = new X509EncodedKeySpec(TestUtil.hexToBytes(pubKey));
147     PublicKey key = kf.generatePublic(x509keySpec);
148     for (String oaepName : OaepAlgorithmNames) {
149         Cipher c = Cipher.getInstance(oaepName, EXPECTED_PROVIDER_NAME);
150         c.init(Cipher.ENCRYPT_MODE, key);
151         Log.d(TAG, "Algorithm " + oaepName + " uses the following defaults");
152         AlgorithmParameters params = c.getParameters();
153         printParameters(params.getParameterSpec(OAEPParameterSpec.class));
154     }
155   }
156 
157   /** Convenience mehtod to get a String from a JsonObject */
getString(JsonObject object, String name)158   protected static String getString(JsonObject object, String name) throws Exception {
159     return object.get(name).getAsString();
160   }
161 
162   /** Convenience method to get a byte array from a JsonObject */
getBytes(JsonObject object, String name)163   protected static byte[] getBytes(JsonObject object, String name) throws Exception {
164     return JsonUtil.asByteArray(object.get(name));
165   }
166 
167   /**
168    * Get a PublicKey from a JsonObject.
169    *
170    * <p>object contains the key in multiple formats: "key" : elements of the public key "keyDer":
171    * the key in ASN encoding encoded hexadecimal "keyPem": the key in Pem format encoded hexadecimal
172    * The test can use the format that is most convenient.
173    */
174   // This is a false positive, since errorprone cannot track values passed into a method.
175   @SuppressWarnings("InsecureCryptoUsage")
getPrivateKey(JsonObject object, boolean isStrongBox)176   protected static PrivateKey getPrivateKey(JsonObject object, boolean isStrongBox)
177           throws Exception {
178     KeyFactory kf;
179     kf = KeyFactory.getInstance("RSA");
180     byte[] encoded = TestUtil.hexToBytes(getString(object, "privateKeyPkcs8"));
181     PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
182     PrivateKey intermediateKey = kf.generatePrivate(keySpec);
183     BigInteger modulus = new BigInteger(TestUtil.hexToBytes(object.get("n").getAsString()));
184     BigInteger exponent = new BigInteger(TestUtil.hexToBytes(object.get("e").getAsString()));
185     PublicKey pubKey = kf.generatePublic(new RSAPublicKeySpec(modulus, exponent));
186     String digest = getString(object, "sha");
187     String mgfDigest = getString(object, "mgfSha");
188     int keysize = object.get("keysize").getAsInt();
189     if (!KeyStoreUtil.isSupportedDigest(digest, isStrongBox)
190           || !KeyStoreUtil.isSupportedMgfDigest(mgfDigest, isStrongBox)
191           || !KeyStoreUtil.isSupportedRsaKeySize(keysize, isStrongBox)) {
192       throw new UnsupportedKeyParametersException();
193     }
194     return saveKeyPairToKeystoreAndReturnPrivateKey(pubKey, intermediateKey, digest, mgfDigest,
195             isStrongBox);
196   }
197 
getOaepAlgorithmName(JsonObject group)198   protected static String getOaepAlgorithmName(JsonObject group) throws Exception {
199     String mgf = getString(group, "mgf");
200     String mgfSha = getString(group, "mgfSha");
201     return "RSA/ECB/OAEPwith" + mgfSha + "and" + mgf + "Padding";
202   }
203 
getOaepParameters(JsonObject group, JsonObject test, boolean isStrongBox)204   protected static OAEPParameterSpec getOaepParameters(JsonObject group,
205     JsonObject test, boolean isStrongBox) throws Exception {
206     String sha = getString(group, "sha");
207     String mgf = getString(group, "mgf");
208     String mgfSha = getString(group, "mgfSha");
209     // mgfDigest other than SHA-1 are supported from KeyMint V1 and above but some implementations
210     // of keymint V1 and V2 (notably the C++ reference implementation) does not include MGF_DIGEST
211     // tag in key characteriestics hence issue b/287532460 introduced. So non-default MGF_DIGEST is
212     // tested on Keymint V3 and above.
213     if (!mgfSha.equalsIgnoreCase("SHA-1")) {
214       assumeTrue("This test is valid for KeyMint version 3 and above.",
215               TestUtils.hasKeystoreVersion(isStrongBox, KeyStoreUtil.KM_VERSION_KEYMINT_3));
216     }
217     PSource p = PSource.PSpecified.DEFAULT;
218     if (test.has("label") && !TextUtils.isEmpty(getString(test, "label"))) {
219       // p = new PSource.PSpecified(getBytes(test, "label"));
220       throw new UnsupportedKeyParametersException();
221     }
222     return new OAEPParameterSpec(sha, mgf, new MGF1ParameterSpec(mgfSha), p);
223   }
224 
225   /**
226    * Tests the signature verification with test vectors in a given JSON file.
227    *
228    * <p> Example format for test vectors
229    * { "algorithm" : "RSA-OAEP",
230    *   "schema" : "rsaes_oaep_decrypt_schema.json",
231    *   "generatorVersion" : "0.7",
232    *   ...
233    *   "testGroups" : [
234    *     {
235    *       "d" : "...",
236    *       "e" : "10001",
237    *       "n" : "...",
238    *       "keysize" : 2048,
239    *       "sha" : "SHA-256",
240    *       "mgf" : "MGF1",
241    *       "mgfSha" : "SHA-256",
242    *       "privateKeyPem" : "-----BEGIN RSA PRIVATE KEY-----\n...",
243    *       "privateKeyPkcs8" : "...",
244    *       "type" : "RSAES",
245    *       "tests" : [
246    *         {
247    *           "tcId" : 1,
248    *           "comment" : "",
249    *           "msg" : "30313233343030",
250    *           "ct" : "...",
251    *           "label" : "",
252    *           "result" : "valid",
253    *           "flags" : [],
254    *         },
255    *        ...
256    *
257    * @param filename the filename of the test vectors
258    * @param allowSkippingKeys if true then keys that cannot be constructed will not fail the test.
259    *        Most of the tests below are using allowSkippingKeys == false. The reason for doing this
260    *        is that providers have distinctive defaults. E.g., no OAEPParameterSpec is given then
261    *        BouncyCastle and Conscrypt use the same hash function for hashing the label and for the
262    *        mask generation function, while jdk uses MGF1SHA1. This is unfortunate and probably
263    *        difficult to fix. Hence, the tests below simply require that providers support each
264    *        others default parameters under the assumption that the OAEPParameterSpec is fully
265    *        specified.
266    **/
testOaep(String filename, boolean allowSkippingKeys)267   public void testOaep(String filename, boolean allowSkippingKeys)
268           throws Exception {
269     testOaep(filename, allowSkippingKeys, false);
270   }
271 
272   private static class UnsupportedKeyParametersException extends Exception { }
273 
testOaep(String filename, boolean allowSkippingKeys, boolean isStrongBox)274   public void testOaep(String filename, boolean allowSkippingKeys, boolean isStrongBox)
275       throws Exception {
276     if (isStrongBox) {
277       KeyStoreUtil.assumeStrongBox();
278     }
279     JsonObject test = JsonUtil.getTestVectors(this.getClass(), filename);
280 
281     // Compares the expected and actual JSON schema of the test vector file.
282     // Mismatched JSON schemas will likely lead to a test failure.
283     String generatorVersion = getString(test, "generatorVersion");
284     String expectedSchema = "rsaes_oaep_decrypt_schema.json";
285     String actualSchema = getString(test, "schema");
286     assertTrue(
287           "Expecting test vectors with schema "
288               + expectedSchema
289               + " found vectors with schema "
290               + actualSchema
291               + " generatorVersion:"
292               + generatorVersion,
293           expectedSchema.equals(actualSchema));
294 
295     int numTests = test.get("numberOfTests").getAsInt();
296     int cntTests = 0;
297     int errors = 0;
298     int skippedKeys = 0;
299     for (JsonElement g : test.getAsJsonArray("testGroups")) {
300       JsonObject group = g.getAsJsonObject();
301       PrivateKey key = null;
302       try {
303         key = getPrivateKey(group, isStrongBox);
304       } catch (UnsupportedKeyParametersException e) {
305         skippedKeys++;
306         if (!allowSkippingKeys) {
307           throw e;
308         } else {
309           continue;
310         }
311       }
312       String algorithm = getOaepAlgorithmName(group);
313       Cipher decrypter = Cipher.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
314       for (JsonElement t : group.getAsJsonArray("tests")) {
315         cntTests++;
316         JsonObject testcase = t.getAsJsonObject();
317         int tcid = testcase.get("tcId").getAsInt();
318         String messageHex = TestUtil.bytesToHex(getBytes(testcase, "msg"));
319         OAEPParameterSpec params;
320         try {
321           params = getOaepParameters(group, testcase, isStrongBox);
322         } catch (UnsupportedKeyParametersException e) {
323           // TODO This try catch block should be removed once issue b/229183581 is fixed.
324           continue;
325         }
326         byte[] ciphertext = getBytes(testcase, "ct");
327         String ciphertextHex = TestUtil.bytesToHex(ciphertext);
328         String result = getString(testcase, "result");
329         byte[] decrypted = null;
330         try {
331           decrypter.init(Cipher.DECRYPT_MODE, key, params);
332           decrypted = decrypter.doFinal(ciphertext);
333         } catch (GeneralSecurityException ex) {
334           decrypted = null;
335         } catch (Exception ex) {
336           // Other exceptions (i.e. unchecked exceptions) are considered as error
337           // since a third party should never be able to cause such exceptions.
338           Log.e(TAG, String.format("Decryption throws %s. filename:%s tcId:%d ct:%s\n",
339                             ex.toString(), filename, tcid, ciphertextHex));
340           decrypted = null;
341           // TODO(bleichen): BouncyCastle throws some non-conforming exceptions.
342           //   For the moment we do not count this as a problem to avoid that
343           //   more serious bugs remain hidden.
344           // errors++;
345         }
346         if (decrypted == null && result.equals("valid")) {
347             Log.e(TAG,
348                 String.format("Valid ciphertext not decrypted. filename:%s tcId:%d ct:%s\n",
349                 filename, tcid, ciphertextHex));
350           errors++;
351         } else if (decrypted != null) {
352           String decryptedHex = TestUtil.bytesToHex(decrypted);
353           if (result.equals("invalid")) {
354             Log.e(TAG,
355                 String.format("Invalid ciphertext decrypted. filename:%s tcId:%d expected:%s" +
356                               " decrypted:%s\n", filename, tcid, messageHex, decryptedHex));
357              errors++;
358           } else if (!decryptedHex.equals(messageHex)) {
359             Log.e(TAG,
360                 String.format("Incorrect decryption. filename:%s tcId:%d expected:%s" +
361                               " decrypted:%s\n", filename, tcid, messageHex, decryptedHex));
362              errors++;
363           }
364         }
365       }
366     }
367     assertEquals(0, errors);
368     if (skippedKeys > 0) {
369       Log.d(TAG, "RSAES-OAEP: file:" + filename + " skipped key:" + skippedKeys);
370       assertTrue(allowSkippingKeys);
371     } else {
372       assertEquals(numTests, cntTests);
373     }
374   }
375 
376   @Test
testRsaOaep2048Sha1Mgf1Sha1()377   public void testRsaOaep2048Sha1Mgf1Sha1() throws Exception {
378     // b/244609904#comment64
379     KeyStoreUtil.assumeKeyMintV1OrNewer(false);
380    testOaep("rsa_oaep_2048_sha1_mgf1sha1_test.json", false);
381   }
382 
383   @Test
testRsaOaep2048Sha1Mgf1Sha1_StrongBox()384   public void testRsaOaep2048Sha1Mgf1Sha1_StrongBox() throws Exception {
385     testOaep("rsa_oaep_2048_sha1_mgf1sha1_test.json", true, true);
386   }
387 
388   @Test
testRsaOaep2048Sha224Mgf1Sha1()389   public void testRsaOaep2048Sha224Mgf1Sha1() throws Exception {
390    testOaep("rsa_oaep_2048_sha224_mgf1sha1_test.json", false);
391   }
392 
393   @Test
testRsaOaep2048Sha224Mgf1Sha224()394   public void testRsaOaep2048Sha224Mgf1Sha224() throws Exception {
395    testOaep("rsa_oaep_2048_sha224_mgf1sha224_test.json", false);
396   }
397 
398   @Test
testRsaOaep2048Sha256Mgf1Sha1()399   public void testRsaOaep2048Sha256Mgf1Sha1() throws Exception {
400     testOaep("rsa_oaep_2048_sha256_mgf1sha1_test.json", false);
401   }
402   @Test
testRsaOaep2048Sha256Mgf1Sha1_StrongBox()403   public void testRsaOaep2048Sha256Mgf1Sha1_StrongBox() throws Exception {
404     testOaep("rsa_oaep_2048_sha256_mgf1sha1_test.json", false, true);
405   }
406 
407   @Test
testRsaOaep2048Sha256Mgf1Sha256()408   public void testRsaOaep2048Sha256Mgf1Sha256() throws Exception {
409     testOaep("rsa_oaep_2048_sha256_mgf1sha256_test.json", false);
410   }
411   @Test
testRsaOaep2048Sha256Mgf1Sha256_StrongBox()412   public void testRsaOaep2048Sha256Mgf1Sha256_StrongBox() throws Exception {
413     testOaep("rsa_oaep_2048_sha256_mgf1sha256_test.json", false, true);
414   }
415 
416   @Test
testRsaOaep2048Sha384Mgf1Sha1()417   public void testRsaOaep2048Sha384Mgf1Sha1() throws Exception {
418    testOaep("rsa_oaep_2048_sha384_mgf1sha1_test.json", false);
419   }
420 
421   @Test
testRsaOaep2048Sha384Mgf1Sha384()422   public void testRsaOaep2048Sha384Mgf1Sha384() throws Exception {
423    testOaep("rsa_oaep_2048_sha384_mgf1sha384_test.json", false);
424   }
425 
426   @Test
testRsaOaep2048Sha512Mgf1Sha1()427   public void testRsaOaep2048Sha512Mgf1Sha1() throws Exception {
428    testOaep("rsa_oaep_2048_sha512_mgf1sha1_test.json", false);
429   }
430 
431   @Test
testRsaOaep2048Sha512Mgf1Sha512()432   public void testRsaOaep2048Sha512Mgf1Sha512() throws Exception {
433    testOaep("rsa_oaep_2048_sha512_mgf1sha512_test.json", false);
434   }
435 
436   @Test
testRsaOaep3072Sha256Mgf1Sha1()437   public void testRsaOaep3072Sha256Mgf1Sha1() throws Exception {
438     // b/244609904#comment64
439     KeyStoreUtil.assumeKeyMintV1OrNewer(false);
440    testOaep("rsa_oaep_3072_sha256_mgf1sha1_test.json", false);
441   }
442 
443   @Test
testRsaOaep3072Sha256Mgf1Sha256()444   public void testRsaOaep3072Sha256Mgf1Sha256() throws Exception {
445    testOaep("rsa_oaep_3072_sha256_mgf1sha256_test.json", false);
446   }
447 
448   @Test
testRsaOaep3072Sha512Mgf1Sha1()449   public void testRsaOaep3072Sha512Mgf1Sha1() throws Exception {
450    testOaep("rsa_oaep_3072_sha512_mgf1sha1_test.json", false);
451   }
452 
453   @Test
testRsaOaep3072Sha512Mgf1Sha512()454   public void testRsaOaep3072Sha512Mgf1Sha512() throws Exception {
455    testOaep("rsa_oaep_3072_sha512_mgf1sha512_test.json", false);
456   }
457 
458   @Test
testRsaOaep4096Sha256Mgf1Sha1()459   public void testRsaOaep4096Sha256Mgf1Sha1() throws Exception {
460     // b/244609904#comment64
461     KeyStoreUtil.assumeKeyMintV1OrNewer(false);
462    testOaep("rsa_oaep_4096_sha256_mgf1sha1_test.json", false);
463   }
464 
465   @Test
testRsaOaep4096Sha256Mgf1Sha256()466   public void testRsaOaep4096Sha256Mgf1Sha256() throws Exception {
467    testOaep("rsa_oaep_4096_sha256_mgf1sha256_test.json", false);
468   }
469 
470   @Test
testRsaOaep4096Sha512Mgf1Sha1()471   public void testRsaOaep4096Sha512Mgf1Sha1() throws Exception {
472    testOaep("rsa_oaep_4096_sha512_mgf1sha1_test.json", false);
473   }
474 
475   @Test
testRsaOaep4096Sha512Mgf1Sha512()476   public void testRsaOaep4096Sha512Mgf1Sha512() throws Exception {
477    testOaep("rsa_oaep_4096_sha512_mgf1sha512_test.json", false);
478   }
479 
480   @Test
testRsaOaepMisc()481   public void testRsaOaepMisc() throws Exception {
482     testOaep("rsa_oaep_misc_test.json", true);
483   }
484   @Test
testRsaOaepMisc_StrongBox()485   public void testRsaOaepMisc_StrongBox() throws Exception {
486     testOaep("rsa_oaep_misc_test.json", true, true);
487   }
488 }
489 
490