| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package libcore.javax.crypto; |
| |
| import com.android.org.bouncycastle.asn1.x509.KeyUsage; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.PrintStream; |
| import java.math.BigInteger; |
| import java.nio.ByteBuffer; |
| import java.nio.charset.StandardCharsets; |
| import java.security.AlgorithmParameters; |
| import java.security.InvalidAlgorithmParameterException; |
| import java.security.InvalidKeyException; |
| import java.security.Key; |
| import java.security.KeyFactory; |
| import java.security.KeyPairGenerator; |
| import java.security.PrivateKey; |
| import java.security.Provider; |
| import java.security.PublicKey; |
| import java.security.SecureRandom; |
| import java.security.Security; |
| import java.security.cert.Certificate; |
| import java.security.spec.AlgorithmParameterSpec; |
| import java.security.spec.RSAPrivateKeySpec; |
| import java.security.spec.RSAPublicKeySpec; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.Set; |
| import javax.crypto.AEADBadTagException; |
| import javax.crypto.BadPaddingException; |
| import javax.crypto.Cipher; |
| import javax.crypto.IllegalBlockSizeException; |
| import javax.crypto.KeyGenerator; |
| import javax.crypto.SecretKey; |
| import javax.crypto.SecretKeyFactory; |
| import javax.crypto.ShortBufferException; |
| import javax.crypto.spec.GCMParameterSpec; |
| import javax.crypto.spec.IvParameterSpec; |
| import javax.crypto.spec.PBEKeySpec; |
| import javax.crypto.spec.PBEParameterSpec; |
| import javax.crypto.spec.SecretKeySpec; |
| import junit.framework.TestCase; |
| import libcore.java.security.StandardNames; |
| import libcore.java.security.TestKeyStore; |
| |
| public final class CipherTest extends TestCase { |
| |
| /** GCM tag size used for tests. */ |
| private static final int GCM_TAG_SIZE_BITS = 96; |
| |
| private static final String[] RSA_PROVIDERS = ((StandardNames.IS_RI) |
| ? new String[] { "SunJCE" } |
| : new String[] { "BC" , "AndroidOpenSSL" }); |
| |
| private static final String[] AES_PROVIDERS = ((StandardNames.IS_RI) |
| ? new String[] { "SunJCE" } |
| : new String[] { "BC", "AndroidOpenSSL" }); |
| |
| private static boolean isSupported(String algorithm, String provider) { |
| if (algorithm.equals("RC2")) { |
| return false; |
| } |
| if (algorithm.equals("PBEWITHMD5ANDRC2")) { |
| return false; |
| } |
| if (algorithm.startsWith("PBEWITHSHA1ANDRC2")) { |
| return false; |
| } |
| if (algorithm.equals("PBEWITHSHAAND40BITRC2-CBC")) { |
| return false; |
| } |
| if (algorithm.equals("PBEWITHSHAAND128BITRC2-CBC")) { |
| return false; |
| } |
| if (algorithm.equals("PBEWITHSHAANDTWOFISH-CBC")) { |
| return false; |
| } |
| if (!IS_UNLIMITED) { |
| if (algorithm.equals("PBEWITHMD5ANDTRIPLEDES")) { |
| return false; |
| } |
| } |
| // stream modes CFB, CTR, CTS, OFB with PKCS5Padding or PKCS7Padding don't really make sense |
| if (!provider.equals("AndroidOpenSSL") && |
| (algorithm.equals("AES/CFB/PKCS5PADDING") |
| || algorithm.equals("AES/CFB/PKCS7PADDING") |
| || algorithm.equals("AES/CTR/PKCS5PADDING") |
| || algorithm.equals("AES/CTR/PKCS7PADDING") |
| || algorithm.equals("AES/CTS/PKCS5PADDING") |
| || algorithm.equals("AES/CTS/PKCS7PADDING") |
| || algorithm.equals("AES/OFB/PKCS5PADDING") |
| || algorithm.equals("AES/OFB/PKCS7PADDING"))) { |
| return false; |
| } |
| return true; |
| } |
| |
| private static boolean isSupportedForWrapping(String algorithm) { |
| if (isOnlyWrappingAlgorithm(algorithm)) { |
| return true; |
| } |
| // http://b/9097343 RSA with NoPadding won't work since |
| // leading zeroes in the underlying key material are lost. |
| if (algorithm.equals("RSA/ECB/NOPADDING")) { |
| return false; |
| } |
| // AESWRAP should be used instead, fails with BC and SunJCE otherwise. |
| if (algorithm.startsWith("AES") || algorithm.startsWith("DESEDE")) { |
| return false; |
| } |
| return true; |
| } |
| |
| private synchronized static int getEncryptMode(String algorithm) throws Exception { |
| if (isOnlyWrappingAlgorithm(algorithm)) { |
| return Cipher.WRAP_MODE; |
| } |
| return Cipher.ENCRYPT_MODE; |
| } |
| |
| private synchronized static int getDecryptMode(String algorithm) throws Exception { |
| if (isOnlyWrappingAlgorithm(algorithm)) { |
| return Cipher.UNWRAP_MODE; |
| } |
| return Cipher.DECRYPT_MODE; |
| } |
| |
| private static String getBaseAlgorithm(String algorithm) { |
| if (algorithm.equals("AESWRAP")) { |
| return "AES"; |
| } |
| if (algorithm.startsWith("AES/")) { |
| return "AES"; |
| } |
| if (algorithm.equals("GCM")) { |
| return "AES"; |
| } |
| if (algorithm.startsWith("DESEDE/")) { |
| return "DESEDE"; |
| } |
| if (algorithm.equals("PBEWITHMD5AND128BITAES-CBC-OPENSSL")) { |
| return "AES"; |
| } |
| if (algorithm.equals("PBEWITHMD5AND192BITAES-CBC-OPENSSL")) { |
| return "AES"; |
| } |
| if (algorithm.equals("PBEWITHMD5AND256BITAES-CBC-OPENSSL")) { |
| return "AES"; |
| } |
| if (algorithm.equals("PBEWITHSHA256AND128BITAES-CBC-BC")) { |
| return "AES"; |
| } |
| if (algorithm.equals("PBEWITHSHA256AND192BITAES-CBC-BC")) { |
| return "AES"; |
| } |
| if (algorithm.equals("PBEWITHSHA256AND256BITAES-CBC-BC")) { |
| return "AES"; |
| } |
| if (algorithm.equals("PBEWITHSHAAND128BITAES-CBC-BC")) { |
| return "AES"; |
| } |
| if (algorithm.equals("PBEWITHSHAAND192BITAES-CBC-BC")) { |
| return "AES"; |
| } |
| if (algorithm.equals("PBEWITHSHAAND256BITAES-CBC-BC")) { |
| return "AES"; |
| } |
| if (algorithm.equals("PBEWITHMD5ANDDES")) { |
| return "DES"; |
| } |
| if (algorithm.equals("PBEWITHSHA1ANDDES")) { |
| return "DES"; |
| } |
| if (algorithm.equals("DESEDEWRAP")) { |
| return "DESEDE"; |
| } |
| if (algorithm.equals("PBEWITHSHAAND2-KEYTRIPLEDES-CBC")) { |
| return "DESEDE"; |
| } |
| if (algorithm.equals("PBEWITHSHAAND3-KEYTRIPLEDES-CBC")) { |
| return "DESEDE"; |
| } |
| if (algorithm.equals("PBEWITHMD5ANDTRIPLEDES")) { |
| return "DESEDE"; |
| } |
| if (algorithm.equals("PBEWITHSHA1ANDDESEDE")) { |
| return "DESEDE"; |
| } |
| if (algorithm.equals("RSA/ECB/NOPADDING")) { |
| return "RSA"; |
| } |
| if (algorithm.equals("RSA/ECB/PKCS1PADDING")) { |
| return "RSA"; |
| } |
| if (algorithm.equals("PBEWITHSHAAND40BITRC4")) { |
| return "ARC4"; |
| } |
| if (algorithm.equals("PBEWITHSHAAND128BITRC4")) { |
| return "ARC4"; |
| } |
| return algorithm; |
| } |
| |
| private static boolean isAsymmetric(String algorithm) { |
| return getBaseAlgorithm(algorithm).equals("RSA"); |
| } |
| |
| private static boolean isOnlyWrappingAlgorithm(String algorithm) { |
| return algorithm.endsWith("WRAP"); |
| } |
| |
| private static boolean isPBE(String algorithm) { |
| return algorithm.startsWith("PBE"); |
| } |
| |
| private static boolean isAEAD(String algorithm) { |
| return "GCM".equals(algorithm) || algorithm.contains("/GCM/"); |
| } |
| |
| private static boolean isStreamMode(String algorithm) { |
| return algorithm.contains("/CTR/") || algorithm.contains("/OFB") |
| || algorithm.contains("/CFB"); |
| } |
| |
| private static Map<String, Key> ENCRYPT_KEYS = new HashMap<String, Key>(); |
| private synchronized static Key getEncryptKey(String algorithm) throws Exception { |
| Key key = ENCRYPT_KEYS.get(algorithm); |
| if (key != null) { |
| return key; |
| } |
| if (algorithm.startsWith("RSA")) { |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus, |
| RSA_2048_privateExponent); |
| key = kf.generatePrivate(keySpec); |
| } else if (isPBE(algorithm)) { |
| SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm); |
| key = skf.generateSecret(new PBEKeySpec("secret".toCharArray())); |
| } else { |
| KeyGenerator kg = KeyGenerator.getInstance(getBaseAlgorithm(algorithm)); |
| key = kg.generateKey(); |
| } |
| ENCRYPT_KEYS.put(algorithm, key); |
| return key; |
| } |
| |
| private static Map<String, Key> DECRYPT_KEYS = new HashMap<String, Key>(); |
| private synchronized static Key getDecryptKey(String algorithm) throws Exception { |
| Key key = DECRYPT_KEYS.get(algorithm); |
| if (key != null) { |
| return key; |
| } |
| if (algorithm.startsWith("RSA")) { |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, |
| RSA_2048_publicExponent); |
| key = kf.generatePublic(keySpec); |
| } else { |
| assertFalse(algorithm, isAsymmetric(algorithm)); |
| key = getEncryptKey(algorithm); |
| } |
| DECRYPT_KEYS.put(algorithm, key); |
| return key; |
| } |
| |
| private static Map<String, Integer> EXPECTED_BLOCK_SIZE = new HashMap<String, Integer>(); |
| static { |
| setExpectedBlockSize("AES", 16); |
| setExpectedBlockSize("AES/CBC/PKCS5PADDING", 16); |
| setExpectedBlockSize("AES/CBC/PKCS7PADDING", 16); |
| setExpectedBlockSize("AES/CBC/NOPADDING", 16); |
| setExpectedBlockSize("AES/CFB/PKCS5PADDING", 16); |
| setExpectedBlockSize("AES/CFB/PKCS7PADDING", 16); |
| setExpectedBlockSize("AES/CFB/NOPADDING", 16); |
| setExpectedBlockSize("AES/CTR/PKCS5PADDING", 16); |
| setExpectedBlockSize("AES/CTR/PKCS7PADDING", 16); |
| setExpectedBlockSize("AES/CTR/NOPADDING", 16); |
| setExpectedBlockSize("AES/CTS/PKCS5PADDING", 16); |
| setExpectedBlockSize("AES/CTS/PKCS7PADDING", 16); |
| setExpectedBlockSize("AES/CTS/NOPADDING", 16); |
| setExpectedBlockSize("AES/ECB/PKCS5PADDING", 16); |
| setExpectedBlockSize("AES/ECB/PKCS7PADDING", 16); |
| setExpectedBlockSize("AES/ECB/NOPADDING", 16); |
| setExpectedBlockSize("AES/GCM/NOPADDING", 16); |
| setExpectedBlockSize("AES/OFB/PKCS5PADDING", 16); |
| setExpectedBlockSize("AES/OFB/PKCS7PADDING", 16); |
| setExpectedBlockSize("AES/OFB/NOPADDING", 16); |
| setExpectedBlockSize("PBEWITHMD5AND128BITAES-CBC-OPENSSL", 16); |
| setExpectedBlockSize("PBEWITHMD5AND192BITAES-CBC-OPENSSL", 16); |
| setExpectedBlockSize("PBEWITHMD5AND256BITAES-CBC-OPENSSL", 16); |
| setExpectedBlockSize("PBEWITHSHA256AND128BITAES-CBC-BC", 16); |
| setExpectedBlockSize("PBEWITHSHA256AND192BITAES-CBC-BC", 16); |
| setExpectedBlockSize("PBEWITHSHA256AND256BITAES-CBC-BC", 16); |
| setExpectedBlockSize("PBEWITHSHAAND128BITAES-CBC-BC", 16); |
| setExpectedBlockSize("PBEWITHSHAAND192BITAES-CBC-BC", 16); |
| setExpectedBlockSize("PBEWITHSHAAND256BITAES-CBC-BC", 16); |
| |
| if (StandardNames.IS_RI) { |
| setExpectedBlockSize("AESWRAP", 16); |
| } else { |
| setExpectedBlockSize("AESWRAP", 0); |
| } |
| |
| setExpectedBlockSize("ARC4", 0); |
| setExpectedBlockSize("ARCFOUR", 0); |
| setExpectedBlockSize("PBEWITHSHAAND40BITRC4", 0); |
| setExpectedBlockSize("PBEWITHSHAAND128BITRC4", 0); |
| |
| setExpectedBlockSize("BLOWFISH", 8); |
| |
| setExpectedBlockSize("DES", 8); |
| setExpectedBlockSize("PBEWITHMD5ANDDES", 8); |
| setExpectedBlockSize("PBEWITHSHA1ANDDES", 8); |
| |
| setExpectedBlockSize("DESEDE", 8); |
| setExpectedBlockSize("DESEDE/CBC/PKCS5PADDING", 8); |
| setExpectedBlockSize("DESEDE/CBC/PKCS7PADDING", 8); |
| setExpectedBlockSize("DESEDE/CBC/NOPADDING", 8); |
| setExpectedBlockSize("DESEDE/CFB/PKCS5PADDING", 8); |
| setExpectedBlockSize("DESEDE/CFB/PKCS7PADDING", 8); |
| setExpectedBlockSize("DESEDE/CFB/NOPADDING", 8); |
| setExpectedBlockSize("DESEDE/CTR/PKCS5PADDING", 8); |
| setExpectedBlockSize("DESEDE/CTR/PKCS7PADDING", 8); |
| setExpectedBlockSize("DESEDE/CTR/NOPADDING", 8); |
| setExpectedBlockSize("DESEDE/CTS/PKCS5PADDING", 8); |
| setExpectedBlockSize("DESEDE/CTS/PKCS7PADDING", 8); |
| setExpectedBlockSize("DESEDE/CTS/NOPADDING", 8); |
| setExpectedBlockSize("DESEDE/ECB/PKCS5PADDING", 8); |
| setExpectedBlockSize("DESEDE/ECB/PKCS7PADDING", 8); |
| setExpectedBlockSize("DESEDE/ECB/NOPADDING", 8); |
| setExpectedBlockSize("DESEDE/OFB/PKCS5PADDING", 8); |
| setExpectedBlockSize("DESEDE/OFB/PKCS7PADDING", 8); |
| setExpectedBlockSize("DESEDE/OFB/NOPADDING", 8); |
| setExpectedBlockSize("PBEWITHSHAAND2-KEYTRIPLEDES-CBC", 8); |
| setExpectedBlockSize("PBEWITHSHAAND3-KEYTRIPLEDES-CBC", 8); |
| setExpectedBlockSize("PBEWITHMD5ANDTRIPLEDES", 8); |
| setExpectedBlockSize("PBEWITHSHA1ANDDESEDE", 8); |
| |
| |
| if (StandardNames.IS_RI) { |
| setExpectedBlockSize("DESEDEWRAP", 8); |
| } else { |
| setExpectedBlockSize("DESEDEWRAP", 0); |
| } |
| |
| if (StandardNames.IS_RI) { |
| setExpectedBlockSize("RSA", 0); |
| setExpectedBlockSize("RSA/ECB/NoPadding", 0); |
| setExpectedBlockSize("RSA/ECB/PKCS1Padding", 0); |
| } else { |
| setExpectedBlockSize("RSA", Cipher.ENCRYPT_MODE, 256); |
| setExpectedBlockSize("RSA/ECB/NoPadding", Cipher.ENCRYPT_MODE, 256); |
| setExpectedBlockSize("RSA/ECB/PKCS1Padding", Cipher.ENCRYPT_MODE, 245); |
| |
| // BC strips the leading 0 for us even when NoPadding is specified |
| setExpectedBlockSize("RSA", Cipher.ENCRYPT_MODE, "BC", 255); |
| setExpectedBlockSize("RSA/ECB/NoPadding", Cipher.ENCRYPT_MODE, "BC", 255); |
| |
| setExpectedBlockSize("RSA", Cipher.DECRYPT_MODE, 256); |
| setExpectedBlockSize("RSA/ECB/NoPadding", Cipher.DECRYPT_MODE, 256); |
| setExpectedBlockSize("RSA/ECB/PKCS1Padding", Cipher.DECRYPT_MODE, 256); |
| } |
| } |
| |
| private static String modeKey(String algorithm, int mode) { |
| return algorithm + ":" + mode; |
| } |
| |
| private static String modeProviderKey(String algorithm, int mode, String provider) { |
| return algorithm + ":" + mode + ":" + provider; |
| } |
| |
| private static void setExpectedSize(Map<String, Integer> map, |
| String algorithm, int value) { |
| algorithm = algorithm.toUpperCase(Locale.US); |
| map.put(algorithm, value); |
| } |
| |
| private static void setExpectedSize(Map<String, Integer> map, |
| String algorithm, int mode, int value) { |
| setExpectedSize(map, modeKey(algorithm, mode), value); |
| } |
| |
| private static void setExpectedSize(Map<String, Integer> map, |
| String algorithm, int mode, String provider, int value) { |
| setExpectedSize(map, modeProviderKey(algorithm, mode, provider), value); |
| } |
| |
| private static int getExpectedSize(Map<String, Integer> map, String algorithm, int mode, String provider) { |
| algorithm = algorithm.toUpperCase(Locale.US); |
| provider = provider.toUpperCase(Locale.US); |
| Integer expected = map.get(modeProviderKey(algorithm, mode, provider)); |
| if (expected != null) { |
| return expected; |
| } |
| expected = map.get(modeKey(algorithm, mode)); |
| if (expected != null) { |
| return expected; |
| } |
| expected = map.get(algorithm); |
| assertNotNull("Algorithm " + algorithm + " with mode " + mode + " and provider " + provider |
| + " not found in " + map, expected); |
| return expected; |
| } |
| |
| private static void setExpectedBlockSize(String algorithm, int value) { |
| setExpectedSize(EXPECTED_BLOCK_SIZE, algorithm, value); |
| } |
| |
| private static void setExpectedBlockSize(String algorithm, int mode, int value) { |
| setExpectedSize(EXPECTED_BLOCK_SIZE, algorithm, mode, value); |
| } |
| |
| private static void setExpectedBlockSize(String algorithm, int mode, String provider, int value) { |
| setExpectedSize(EXPECTED_BLOCK_SIZE, algorithm, mode, provider, value); |
| } |
| |
| private static int getExpectedBlockSize(String algorithm, int mode, String provider) { |
| return getExpectedSize(EXPECTED_BLOCK_SIZE, algorithm, mode, provider); |
| } |
| |
| private static Map<String, Integer> EXPECTED_OUTPUT_SIZE = new HashMap<String, Integer>(); |
| static { |
| setExpectedOutputSize("AES/CBC/NOPADDING", 0); |
| setExpectedOutputSize("AES/CFB/NOPADDING", 0); |
| setExpectedOutputSize("AES/CTR/NOPADDING", 0); |
| setExpectedOutputSize("AES/CTS/NOPADDING", 0); |
| setExpectedOutputSize("AES/ECB/NOPADDING", 0); |
| setExpectedOutputSize("AES/OFB/NOPADDING", 0); |
| |
| setExpectedOutputSize("AES", Cipher.ENCRYPT_MODE, 16); |
| setExpectedOutputSize("AES/CBC/PKCS5PADDING", Cipher.ENCRYPT_MODE, 16); |
| setExpectedOutputSize("AES/CBC/PKCS7PADDING", Cipher.ENCRYPT_MODE, 16); |
| setExpectedOutputSize("AES/CFB/PKCS5PADDING", Cipher.ENCRYPT_MODE, 16); |
| setExpectedOutputSize("AES/CFB/PKCS7PADDING", Cipher.ENCRYPT_MODE, 16); |
| setExpectedOutputSize("AES/CTR/PKCS5PADDING", Cipher.ENCRYPT_MODE, 16); |
| setExpectedOutputSize("AES/CTR/PKCS7PADDING", Cipher.ENCRYPT_MODE, 16); |
| setExpectedOutputSize("AES/CTS/PKCS5PADDING", Cipher.ENCRYPT_MODE, 16); |
| setExpectedOutputSize("AES/CTS/PKCS7PADDING", Cipher.ENCRYPT_MODE, 16); |
| setExpectedOutputSize("AES/ECB/PKCS5PADDING", Cipher.ENCRYPT_MODE, 16); |
| setExpectedOutputSize("AES/ECB/PKCS7PADDING", Cipher.ENCRYPT_MODE, 16); |
| setExpectedOutputSize("AES/GCM/NOPADDING", Cipher.ENCRYPT_MODE, GCM_TAG_SIZE_BITS / 8); |
| setExpectedOutputSize("AES/OFB/PKCS5PADDING", Cipher.ENCRYPT_MODE, 16); |
| setExpectedOutputSize("AES/OFB/PKCS7PADDING", Cipher.ENCRYPT_MODE, 16); |
| setExpectedOutputSize("PBEWITHMD5AND128BITAES-CBC-OPENSSL", 16); |
| setExpectedOutputSize("PBEWITHMD5AND192BITAES-CBC-OPENSSL", 16); |
| setExpectedOutputSize("PBEWITHMD5AND256BITAES-CBC-OPENSSL", 16); |
| setExpectedOutputSize("PBEWITHSHA256AND128BITAES-CBC-BC", 16); |
| setExpectedOutputSize("PBEWITHSHA256AND192BITAES-CBC-BC", 16); |
| setExpectedOutputSize("PBEWITHSHA256AND256BITAES-CBC-BC", 16); |
| setExpectedOutputSize("PBEWITHSHAAND128BITAES-CBC-BC", 16); |
| setExpectedOutputSize("PBEWITHSHAAND192BITAES-CBC-BC", 16); |
| setExpectedOutputSize("PBEWITHSHAAND256BITAES-CBC-BC", 16); |
| // AndroidOpenSSL returns zero for the non-block ciphers |
| setExpectedOutputSize("AES/CFB/PKCS5PADDING", Cipher.ENCRYPT_MODE, "AndroidOpenSSL", 0); |
| setExpectedOutputSize("AES/CFB/PKCS7PADDING", Cipher.ENCRYPT_MODE, "AndroidOpenSSL", 0); |
| setExpectedOutputSize("AES/CTR/PKCS5PADDING", Cipher.ENCRYPT_MODE, "AndroidOpenSSL", 0); |
| setExpectedOutputSize("AES/CTR/PKCS7PADDING", Cipher.ENCRYPT_MODE, "AndroidOpenSSL", 0); |
| setExpectedOutputSize("AES/CTS/PKCS5PADDING", Cipher.ENCRYPT_MODE, "AndroidOpenSSL", 0); |
| setExpectedOutputSize("AES/CTS/PKCS7PADDING", Cipher.ENCRYPT_MODE, "AndroidOpenSSL", 0); |
| setExpectedOutputSize("AES/OFB/PKCS5PADDING", Cipher.ENCRYPT_MODE, "AndroidOpenSSL", 0); |
| setExpectedOutputSize("AES/OFB/PKCS7PADDING", Cipher.ENCRYPT_MODE, "AndroidOpenSSL", 0); |
| |
| setExpectedOutputSize("AES", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("AES/CBC/PKCS5PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("AES/CBC/PKCS7PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("AES/CFB/PKCS5PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("AES/CFB/PKCS7PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("AES/CTR/PKCS5PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("AES/CTR/PKCS7PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("AES/CTS/PKCS5PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("AES/CTS/PKCS7PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("AES/ECB/PKCS5PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("AES/ECB/PKCS7PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("AES/GCM/NOPADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("AES/OFB/PKCS5PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("AES/OFB/PKCS7PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("PBEWITHMD5AND128BITAES-CBC-OPENSSL", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("PBEWITHMD5AND192BITAES-CBC-OPENSSL", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("PBEWITHMD5AND256BITAES-CBC-OPENSSL", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("PBEWITHSHA256AND128BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("PBEWITHSHA256AND192BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("PBEWITHSHA256AND256BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("PBEWITHSHAAND128BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("PBEWITHSHAAND192BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("PBEWITHSHAAND256BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("DESEDE/CBC/PKCS5PADDING", Cipher.DECRYPT_MODE, "AndroidOpenSSL", 0); |
| setExpectedOutputSize("DESEDE/CBC/PKCS7PADDING", Cipher.DECRYPT_MODE, "AndroidOpenSSL", 0); |
| |
| if (StandardNames.IS_RI) { |
| setExpectedOutputSize("AESWRAP", Cipher.WRAP_MODE, 8); |
| setExpectedOutputSize("AESWRAP", Cipher.UNWRAP_MODE, 0); |
| } else { |
| setExpectedOutputSize("AESWRAP", -1); |
| } |
| |
| setExpectedOutputSize("ARC4", 0); |
| setExpectedOutputSize("ARCFOUR", 0); |
| setExpectedOutputSize("PBEWITHSHAAND40BITRC4", 0); |
| setExpectedOutputSize("PBEWITHSHAAND128BITRC4", 0); |
| |
| setExpectedOutputSize("BLOWFISH", Cipher.ENCRYPT_MODE, 8); |
| setExpectedOutputSize("BLOWFISH", Cipher.DECRYPT_MODE, 0); |
| |
| setExpectedOutputSize("DES", Cipher.ENCRYPT_MODE, 8); |
| setExpectedOutputSize("PBEWITHMD5ANDDES", Cipher.ENCRYPT_MODE, 8); |
| setExpectedOutputSize("PBEWITHSHA1ANDDES", Cipher.ENCRYPT_MODE, 8); |
| |
| setExpectedOutputSize("DES", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("PBEWITHMD5ANDDES", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("PBEWITHSHA1ANDDES", Cipher.DECRYPT_MODE, 0); |
| |
| setExpectedOutputSize("DESEDE/CBC/NOPADDING", 0); |
| setExpectedOutputSize("DESEDE/CFB/NOPADDING", 0); |
| setExpectedOutputSize("DESEDE/CTR/NOPADDING", 0); |
| setExpectedOutputSize("DESEDE/CTS/NOPADDING", 0); |
| setExpectedOutputSize("DESEDE/ECB/NOPADDING", 0); |
| setExpectedOutputSize("DESEDE/OFB/NOPADDING", 0); |
| |
| setExpectedOutputSize("DESEDE", Cipher.ENCRYPT_MODE, 8); |
| setExpectedOutputSize("DESEDE/CBC/PKCS5PADDING", Cipher.ENCRYPT_MODE, 8); |
| setExpectedOutputSize("DESEDE/CBC/PKCS7PADDING", Cipher.ENCRYPT_MODE, 8); |
| setExpectedOutputSize("DESEDE/CFB/PKCS5PADDING", Cipher.ENCRYPT_MODE, 8); |
| setExpectedOutputSize("DESEDE/CFB/PKCS7PADDING", Cipher.ENCRYPT_MODE, 8); |
| setExpectedOutputSize("DESEDE/CTR/PKCS5PADDING", Cipher.ENCRYPT_MODE, 8); |
| setExpectedOutputSize("DESEDE/CTR/PKCS7PADDING", Cipher.ENCRYPT_MODE, 8); |
| setExpectedOutputSize("DESEDE/CTS/PKCS5PADDING", Cipher.ENCRYPT_MODE, 8); |
| setExpectedOutputSize("DESEDE/CTS/PKCS7PADDING", Cipher.ENCRYPT_MODE, 8); |
| setExpectedOutputSize("DESEDE/ECB/PKCS5PADDING", Cipher.ENCRYPT_MODE, 8); |
| setExpectedOutputSize("DESEDE/ECB/PKCS7PADDING", Cipher.ENCRYPT_MODE, 8); |
| setExpectedOutputSize("DESEDE/OFB/PKCS5PADDING", Cipher.ENCRYPT_MODE, 8); |
| setExpectedOutputSize("DESEDE/OFB/PKCS7PADDING", Cipher.ENCRYPT_MODE, 8); |
| setExpectedOutputSize("PBEWITHSHAAND2-KEYTRIPLEDES-CBC", Cipher.ENCRYPT_MODE, 8); |
| setExpectedOutputSize("PBEWITHSHAAND3-KEYTRIPLEDES-CBC", Cipher.ENCRYPT_MODE, 8); |
| setExpectedOutputSize("PBEWITHMD5ANDTRIPLEDES", Cipher.ENCRYPT_MODE, 8); |
| setExpectedOutputSize("PBEWITHSHA1ANDDESEDE", Cipher.ENCRYPT_MODE, 8); |
| |
| setExpectedOutputSize("DESEDE", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("DESEDE/CBC/PKCS5PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("DESEDE/CBC/PKCS7PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("DESEDE/CFB/PKCS5PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("DESEDE/CFB/PKCS7PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("DESEDE/CTR/PKCS5PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("DESEDE/CTR/PKCS7PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("DESEDE/CTS/PKCS5PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("DESEDE/CTS/PKCS7PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("DESEDE/ECB/PKCS5PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("DESEDE/ECB/PKCS7PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("DESEDE/OFB/PKCS5PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("DESEDE/OFB/PKCS7PADDING", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("PBEWITHSHAAND2-KEYTRIPLEDES-CBC", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("PBEWITHSHAAND3-KEYTRIPLEDES-CBC", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("PBEWITHMD5ANDTRIPLEDES", Cipher.DECRYPT_MODE, 0); |
| setExpectedOutputSize("PBEWITHSHA1ANDDESEDE", Cipher.DECRYPT_MODE, 0); |
| |
| if (StandardNames.IS_RI) { |
| setExpectedOutputSize("DESEDEWRAP", Cipher.WRAP_MODE, 16); |
| setExpectedOutputSize("DESEDEWRAP", Cipher.UNWRAP_MODE, 0); |
| } else { |
| setExpectedOutputSize("DESEDEWRAP", -1); |
| } |
| |
| setExpectedOutputSize("RSA", Cipher.ENCRYPT_MODE, 256); |
| setExpectedOutputSize("RSA/ECB/NoPadding", Cipher.ENCRYPT_MODE, 256); |
| setExpectedOutputSize("RSA/ECB/PKCS1Padding", Cipher.ENCRYPT_MODE, 256); |
| |
| setExpectedOutputSize("RSA", Cipher.DECRYPT_MODE, 256); |
| setExpectedOutputSize("RSA/ECB/NoPadding", Cipher.DECRYPT_MODE, 256); |
| setExpectedOutputSize("RSA/ECB/PKCS1Padding", Cipher.DECRYPT_MODE, 245); |
| |
| // SunJCE returns the full for size even when PKCS1Padding is specified |
| setExpectedOutputSize("RSA/ECB/PKCS1Padding", Cipher.DECRYPT_MODE, "SunJCE", 256); |
| |
| // BC strips the leading 0 for us even when NoPadding is specified |
| setExpectedOutputSize("RSA", Cipher.DECRYPT_MODE, "BC", 255); |
| setExpectedOutputSize("RSA/ECB/NoPadding", Cipher.DECRYPT_MODE, "BC", 255); |
| } |
| |
| private static void setExpectedOutputSize(String algorithm, int value) { |
| setExpectedSize(EXPECTED_OUTPUT_SIZE, algorithm, value); |
| } |
| |
| private static void setExpectedOutputSize(String algorithm, int mode, int value) { |
| setExpectedSize(EXPECTED_OUTPUT_SIZE, algorithm, mode, value); |
| } |
| |
| private static void setExpectedOutputSize(String algorithm, int mode, String provider, int value) { |
| setExpectedSize(EXPECTED_OUTPUT_SIZE, algorithm, mode, provider, value); |
| } |
| |
| private static int getExpectedOutputSize(String algorithm, int mode, String provider) { |
| return getExpectedSize(EXPECTED_OUTPUT_SIZE, algorithm, mode, provider); |
| } |
| |
| private static byte[] ORIGINAL_PLAIN_TEXT = new byte[] { 0x0a, 0x0b, 0x0c }; |
| private static byte[] SIXTEEN_BYTE_BLOCK_PLAIN_TEXT = new byte[] { 0x0a, 0x0b, 0x0c, 0x00, |
| 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00 }; |
| private static byte[] EIGHT_BYTE_BLOCK_PLAIN_TEXT = new byte[] { 0x0a, 0x0b, 0x0c, 0x00, |
| 0x00, 0x00, 0x00, 0x00 }; |
| private static byte[] PKCS1_BLOCK_TYPE_00_PADDED_PLAIN_TEXT = new byte[] { |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0a, 0x0b, 0x0c |
| }; |
| private static byte[] PKCS1_BLOCK_TYPE_01_PADDED_PLAIN_TEXT = new byte[] { |
| (byte) 0x00, (byte) 0x01, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x0a, (byte) 0x0b, (byte) 0x0c |
| }; |
| private static byte[] PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT = new byte[] { |
| (byte) 0x00, (byte) 0x02, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, |
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x0a, (byte) 0x0b, (byte) 0x0c |
| }; |
| |
| |
| private static byte[] getActualPlainText(String algorithm) { |
| // Block mode AES with NoPadding needs to match underlying block size |
| if (algorithm.equals("AES") |
| || algorithm.equals("AES/CBC/NOPADDING") |
| || algorithm.equals("AES/CTS/NOPADDING") |
| || algorithm.equals("AES/ECB/NOPADDING")) { |
| return SIXTEEN_BYTE_BLOCK_PLAIN_TEXT; |
| } |
| if (algorithm.equals("DESEDE") |
| || algorithm.equals("DESEDE/CBC/NOPADDING") |
| || algorithm.equals("DESEDE/ECB/NOPADDING")) { |
| return EIGHT_BYTE_BLOCK_PLAIN_TEXT; |
| } |
| return ORIGINAL_PLAIN_TEXT; |
| } |
| |
| private static byte[] getExpectedPlainText(String algorithm, String provider) { |
| // Block mode AES with NoPadding needs to match underlying block size |
| if (algorithm.equals("AES") |
| || algorithm.equals("AES/CBC/NOPADDING") |
| || algorithm.equals("AES/CTS/NOPADDING") |
| || algorithm.equals("AES/ECB/NOPADDING")) { |
| return SIXTEEN_BYTE_BLOCK_PLAIN_TEXT; |
| } |
| if (algorithm.equals("DESEDE") |
| || algorithm.equals("DESEDE/CBC/NOPADDING") |
| || algorithm.equals("DESEDE/ECB/NOPADDING")) { |
| return EIGHT_BYTE_BLOCK_PLAIN_TEXT; |
| } |
| // BC strips the leading 0 for us even when NoPadding is specified |
| if (!provider.equals("BC") && algorithm.equals("RSA/ECB/NOPADDING")) { |
| return PKCS1_BLOCK_TYPE_00_PADDED_PLAIN_TEXT; |
| } |
| return ORIGINAL_PLAIN_TEXT; |
| } |
| |
| private static AlgorithmParameterSpec getEncryptAlgorithmParameterSpec(String algorithm) { |
| if (isPBE(algorithm)) { |
| final byte[] salt = new byte[8]; |
| new SecureRandom().nextBytes(salt); |
| return new PBEParameterSpec(salt, 1024); |
| } |
| if (algorithm.equals("AES/GCM/NOPADDING")) { |
| final byte[] iv = new byte[12]; |
| new SecureRandom().nextBytes(iv); |
| return new GCMParameterSpec(GCM_TAG_SIZE_BITS, iv); |
| } |
| if (algorithm.equals("AES/CBC/NOPADDING") |
| || algorithm.equals("AES/CBC/PKCS5PADDING") |
| || algorithm.equals("AES/CBC/PKCS7PADDING") |
| || algorithm.equals("AES/CFB/NOPADDING") |
| || algorithm.equals("AES/CTR/NOPADDING") |
| || algorithm.equals("AES/CTS/NOPADDING") |
| || algorithm.equals("AES/OFB/NOPADDING")) { |
| final byte[] iv = new byte[16]; |
| new SecureRandom().nextBytes(iv); |
| return new IvParameterSpec(iv); |
| } |
| if (algorithm.equals("DESEDE/CBC/NOPADDING") |
| || algorithm.equals("DESEDE/CBC/PKCS5PADDING") |
| || algorithm.equals("DESEDE/CBC/PKCS7PADDING") |
| || algorithm.equals("DESEDE/CFB/NOPADDING") |
| || algorithm.equals("DESEDE/CTR/NOPADDING") |
| || algorithm.equals("DESEDE/CTS/NOPADDING") |
| || algorithm.equals("DESEDE/OFB/NOPADDING")) { |
| final byte[] iv = new byte[8]; |
| new SecureRandom().nextBytes(iv); |
| return new IvParameterSpec(iv); |
| } |
| return null; |
| } |
| |
| private static AlgorithmParameterSpec getDecryptAlgorithmParameterSpec(AlgorithmParameterSpec encryptSpec, |
| Cipher encryptCipher) { |
| String algorithm = encryptCipher.getAlgorithm().toUpperCase(Locale.US); |
| if (isPBE(algorithm)) { |
| return encryptSpec; |
| } |
| if (isOnlyWrappingAlgorithm(algorithm)) { |
| return null; |
| } |
| byte[] iv = encryptCipher.getIV(); |
| if (iv != null) { |
| if ("AES/GCM/NOPADDING".equals(algorithm)) { |
| return new GCMParameterSpec(GCM_TAG_SIZE_BITS, iv); |
| } |
| return new IvParameterSpec(iv); |
| } |
| return null; |
| } |
| |
| /* |
| * This must be below everything else to make sure the other static blocks |
| * have run first. |
| */ |
| private static final boolean IS_UNLIMITED; |
| static { |
| boolean is_unlimited; |
| if (StandardNames.IS_RI) { |
| try { |
| String algorithm = "PBEWITHMD5ANDTRIPLEDES"; |
| Cipher.getInstance(algorithm).init(getEncryptMode(algorithm), |
| getEncryptKey(algorithm), |
| getEncryptAlgorithmParameterSpec(algorithm)); |
| is_unlimited = true; |
| } catch (Exception e) { |
| is_unlimited = false; |
| System.out.println("WARNING: Some tests disabled due to lack of " |
| + "'Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files'"); |
| } |
| } else { |
| is_unlimited = true; |
| } |
| IS_UNLIMITED = is_unlimited; |
| } |
| |
| private static abstract class MockProvider extends Provider { |
| public MockProvider(String name) { |
| super(name, 1.0, "Mock provider used for testing"); |
| setup(); |
| } |
| |
| public abstract void setup(); |
| } |
| |
| public void testCipher_getInstance_SuppliedProviderNotRegistered_Success() throws Exception { |
| Provider mockProvider = new MockProvider("MockProvider") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName()); |
| } |
| }; |
| |
| { |
| Cipher c = Cipher.getInstance("FOO", mockProvider); |
| c.init(Cipher.ENCRYPT_MODE, new MockKey()); |
| assertEquals(mockProvider, c.getProvider()); |
| } |
| } |
| |
| public void testCipher_getInstance_DoesNotSupportKeyClass_Success() throws Exception { |
| Provider mockProvider = new MockProvider("MockProvider") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName()); |
| put("Cipher.FOO SupportedKeyClasses", "None"); |
| } |
| }; |
| |
| Security.addProvider(mockProvider); |
| try { |
| Cipher c = Cipher.getInstance("FOO", mockProvider); |
| c.init(Cipher.ENCRYPT_MODE, new MockKey()); |
| assertEquals(mockProvider, c.getProvider()); |
| } finally { |
| Security.removeProvider(mockProvider.getName()); |
| } |
| } |
| |
| public void testCipher_getInstance_SuppliedProviderNotRegistered_MultipartTransform_Success() |
| throws Exception { |
| Provider mockProvider = new MockProvider("MockProvider") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName()); |
| } |
| }; |
| |
| { |
| Cipher c = Cipher.getInstance("FOO/FOO/FOO", mockProvider); |
| c.init(Cipher.ENCRYPT_MODE, new MockKey()); |
| assertEquals(mockProvider, c.getProvider()); |
| } |
| } |
| |
| public void testCipher_getInstance_OnlyUsesSpecifiedProvider_SameNameAndClass_Success() |
| throws Exception { |
| Provider mockProvider = new MockProvider("MockProvider") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName()); |
| } |
| }; |
| |
| Security.addProvider(mockProvider); |
| try { |
| { |
| Provider mockProvider2 = new MockProvider("MockProvider") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName()); |
| } |
| }; |
| Cipher c = Cipher.getInstance("FOO", mockProvider2); |
| assertEquals(mockProvider2, c.getProvider()); |
| } |
| } finally { |
| Security.removeProvider(mockProvider.getName()); |
| } |
| } |
| |
| public void testCipher_getInstance_DelayedInitialization_KeyType() throws Exception { |
| Provider mockProviderSpecific = new MockProvider("MockProviderSpecific") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.SpecificKeyTypes.class.getName()); |
| put("Cipher.FOO SupportedKeyClasses", MockKey.class.getName()); |
| } |
| }; |
| Provider mockProviderSpecific2 = new MockProvider("MockProviderSpecific2") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.SpecificKeyTypes2.class.getName()); |
| put("Cipher.FOO SupportedKeyClasses", MockKey2.class.getName()); |
| } |
| }; |
| Provider mockProviderAll = new MockProvider("MockProviderAll") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName()); |
| } |
| }; |
| |
| Security.addProvider(mockProviderSpecific); |
| Security.addProvider(mockProviderSpecific2); |
| Security.addProvider(mockProviderAll); |
| |
| try { |
| { |
| System.out.println(Arrays.deepToString(Security.getProviders("Cipher.FOO"))); |
| Cipher c = Cipher.getInstance("FOO"); |
| c.init(Cipher.ENCRYPT_MODE, new MockKey()); |
| assertEquals(mockProviderSpecific, c.getProvider()); |
| |
| try { |
| c.init(Cipher.ENCRYPT_MODE, new MockKey2()); |
| assertEquals(mockProviderSpecific2, c.getProvider()); |
| if (StandardNames.IS_RI) { |
| fail("RI was broken before; fix tests now that it works!"); |
| } |
| } catch (InvalidKeyException e) { |
| if (!StandardNames.IS_RI) { |
| fail("Non-RI should select the right provider"); |
| } |
| } |
| } |
| |
| { |
| Cipher c = Cipher.getInstance("FOO"); |
| c.init(Cipher.ENCRYPT_MODE, new Key() { |
| @Override |
| public String getAlgorithm() { |
| throw new UnsupportedOperationException("not implemented"); |
| } |
| |
| @Override |
| public String getFormat() { |
| throw new UnsupportedOperationException("not implemented"); |
| } |
| |
| @Override |
| public byte[] getEncoded() { |
| throw new UnsupportedOperationException("not implemented"); |
| } |
| }); |
| assertEquals(mockProviderAll, c.getProvider()); |
| } |
| |
| { |
| Cipher c = Cipher.getInstance("FOO"); |
| assertEquals(mockProviderSpecific, c.getProvider()); |
| } |
| } finally { |
| Security.removeProvider(mockProviderSpecific.getName()); |
| Security.removeProvider(mockProviderSpecific2.getName()); |
| Security.removeProvider(mockProviderAll.getName()); |
| } |
| } |
| |
| public void testCipher_getInstance_CorrectPriority_AlgorithmOnlyFirst() throws Exception { |
| Provider mockProviderOnlyAlgorithm = new MockProvider("MockProviderOnlyAlgorithm") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName()); |
| } |
| }; |
| Provider mockProviderFullTransformSpecified = new MockProvider("MockProviderFull") { |
| public void setup() { |
| put("Cipher.FOO/FOO/FOO", MockCipherSpi.AllKeyTypes.class.getName()); |
| } |
| }; |
| |
| Security.addProvider(mockProviderOnlyAlgorithm); |
| Security.addProvider(mockProviderFullTransformSpecified); |
| try { |
| Cipher c = Cipher.getInstance("FOO/FOO/FOO"); |
| assertEquals(mockProviderOnlyAlgorithm, c.getProvider()); |
| } finally { |
| Security.removeProvider(mockProviderOnlyAlgorithm.getName()); |
| Security.removeProvider(mockProviderFullTransformSpecified.getName()); |
| } |
| } |
| |
| public void testCipher_getInstance_CorrectPriority_FullTransformFirst() throws Exception { |
| Provider mockProviderOnlyAlgorithm = new MockProvider("MockProviderOnlyAlgorithm") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName()); |
| } |
| }; |
| Provider mockProviderFullTransformSpecified = new MockProvider("MockProviderFull") { |
| public void setup() { |
| put("Cipher.FOO/FOO/FOO", MockCipherSpi.AllKeyTypes.class.getName()); |
| } |
| }; |
| |
| Security.addProvider(mockProviderFullTransformSpecified); |
| Security.addProvider(mockProviderOnlyAlgorithm); |
| try { |
| Cipher c = Cipher.getInstance("FOO/FOO/FOO"); |
| assertEquals(mockProviderFullTransformSpecified, c.getProvider()); |
| } finally { |
| Security.removeProvider(mockProviderOnlyAlgorithm.getName()); |
| Security.removeProvider(mockProviderFullTransformSpecified.getName()); |
| } |
| } |
| |
| public void testCipher_getInstance_CorrectPriority_AliasedAlgorithmFirst() throws Exception { |
| Provider mockProviderAliasedAlgorithm = new MockProvider("MockProviderAliasedAlgorithm") { |
| public void setup() { |
| put("Cipher.BAR", MockCipherSpi.AllKeyTypes.class.getName()); |
| put("Alg.Alias.Cipher.FOO", "BAR"); |
| } |
| }; |
| Provider mockProviderAlgorithmOnly = new MockProvider("MockProviderAlgorithmOnly") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName()); |
| } |
| }; |
| |
| Security.addProvider(mockProviderAliasedAlgorithm); |
| Security.addProvider(mockProviderAlgorithmOnly); |
| try { |
| Cipher c = Cipher.getInstance("FOO/FOO/FOO"); |
| assertEquals(mockProviderAliasedAlgorithm, c.getProvider()); |
| } finally { |
| Security.removeProvider(mockProviderAliasedAlgorithm.getName()); |
| Security.removeProvider(mockProviderAlgorithmOnly.getName()); |
| } |
| } |
| |
| public void testCipher_getInstance_WrongType_Failure() throws Exception { |
| Provider mockProviderInvalid = new MockProvider("MockProviderInvalid") { |
| public void setup() { |
| put("Cipher.FOO", Object.class.getName()); |
| } |
| }; |
| |
| Security.addProvider(mockProviderInvalid); |
| try { |
| Cipher c = Cipher.getInstance("FOO"); |
| c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(new byte[16], "FOO")); |
| fail("Should not find any matching providers; found: " + c); |
| } catch (ClassCastException expected) { |
| } finally { |
| Security.removeProvider(mockProviderInvalid.getName()); |
| } |
| } |
| |
| public void testCipher_init_CallsInitWithParams_AlgorithmParameterSpec() throws Exception { |
| Provider mockProviderRejects = new MockProvider("MockProviderRejects") { |
| public void setup() { |
| put("Cipher.FOO", |
| MockCipherSpi.MustInitWithAlgorithmParameterSpec_RejectsAll.class.getName()); |
| put("Cipher.FOO SupportedKeyClasses", MockKey.class.getName()); |
| } |
| }; |
| Provider mockProviderAccepts = new MockProvider("MockProviderAccepts") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName()); |
| put("Cipher.FOO SupportedKeyClasses", MockKey.class.getName()); |
| } |
| }; |
| |
| Security.addProvider(mockProviderRejects); |
| Security.addProvider(mockProviderAccepts); |
| try { |
| Cipher c = Cipher.getInstance("FOO"); |
| c.init(Cipher.ENCRYPT_MODE, new MockKey(), new IvParameterSpec(new byte[12])); |
| assertEquals(mockProviderAccepts, c.getProvider()); |
| } finally { |
| Security.removeProvider(mockProviderRejects.getName()); |
| Security.removeProvider(mockProviderAccepts.getName()); |
| } |
| } |
| |
| public void testCipher_init_CallsInitWithParams_AlgorithmParameters() throws Exception { |
| Provider mockProviderRejects = new MockProvider("MockProviderRejects") { |
| public void setup() { |
| put("Cipher.FOO", |
| MockCipherSpi.MustInitWithAlgorithmParameters_RejectsAll.class.getName()); |
| put("Cipher.FOO SupportedKeyClasses", MockKey.class.getName()); |
| } |
| }; |
| Provider mockProviderAccepts = new MockProvider("MockProviderAccepts") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName()); |
| put("Cipher.FOO SupportedKeyClasses", MockKey.class.getName()); |
| } |
| }; |
| |
| Security.addProvider(mockProviderRejects); |
| Security.addProvider(mockProviderAccepts); |
| try { |
| Cipher c = Cipher.getInstance("FOO"); |
| c.init(Cipher.ENCRYPT_MODE, new MockKey(), AlgorithmParameters.getInstance("AES")); |
| assertEquals(mockProviderAccepts, c.getProvider()); |
| } finally { |
| Security.removeProvider(mockProviderRejects.getName()); |
| Security.removeProvider(mockProviderAccepts.getName()); |
| } |
| } |
| |
| public void testCipher_init_CallsInitIgnoresRuntimeException() throws Exception { |
| Provider mockProviderRejects = new MockProvider("MockProviderRejects") { |
| public void setup() { |
| put("Cipher.FOO", |
| MockCipherSpi.MustInitWithAlgorithmParameters_ThrowsNull.class.getName()); |
| put("Cipher.FOO SupportedKeyClasses", MockKey.class.getName()); |
| } |
| }; |
| Provider mockProviderAccepts = new MockProvider("MockProviderAccepts") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName()); |
| put("Cipher.FOO SupportedKeyClasses", MockKey.class.getName()); |
| } |
| }; |
| |
| Security.addProvider(mockProviderRejects); |
| Security.addProvider(mockProviderAccepts); |
| try { |
| Cipher c = Cipher.getInstance("FOO"); |
| c.init(Cipher.ENCRYPT_MODE, new MockKey(), AlgorithmParameters.getInstance("AES")); |
| assertEquals(mockProviderAccepts, c.getProvider()); |
| } finally { |
| Security.removeProvider(mockProviderRejects.getName()); |
| Security.removeProvider(mockProviderAccepts.getName()); |
| } |
| } |
| |
| public void testCipher_init_CallsInitWithMode() throws Exception { |
| Provider mockProviderOnlyEncrypt = new MockProvider("MockProviderOnlyEncrypt") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.MustInitForEncryptModeOrRejects.class.getName()); |
| put("Cipher.FOO SupportedKeyClasses", MockKey.class.getName()); |
| } |
| }; |
| Provider mockProviderAcceptsAll = new MockProvider("MockProviderAcceptsAll") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName()); |
| put("Cipher.FOO SupportedKeyClasses", MockKey.class.getName()); |
| } |
| }; |
| |
| Security.addProvider(mockProviderOnlyEncrypt); |
| Security.addProvider(mockProviderAcceptsAll); |
| try { |
| { |
| Cipher c = Cipher.getInstance("FOO"); |
| c.init(Cipher.DECRYPT_MODE, new MockKey(), AlgorithmParameters.getInstance("AES")); |
| assertEquals(mockProviderAcceptsAll, c.getProvider()); |
| } |
| |
| { |
| Cipher c = Cipher.getInstance("FOO"); |
| c.init(Cipher.ENCRYPT_MODE, new MockKey(), AlgorithmParameters.getInstance("AES")); |
| assertEquals(mockProviderOnlyEncrypt, c.getProvider()); |
| } |
| } finally { |
| Security.removeProvider(mockProviderOnlyEncrypt.getName()); |
| Security.removeProvider(mockProviderAcceptsAll.getName()); |
| } |
| } |
| |
| public void test_getInstance() throws Exception { |
| final ByteArrayOutputStream errBuffer = new ByteArrayOutputStream(); |
| PrintStream out = new PrintStream(errBuffer); |
| |
| Set<String> seenBaseCipherNames = new HashSet<String>(); |
| Set<String> seenCiphersWithModeAndPadding = new HashSet<String>(); |
| |
| Provider[] providers = Security.getProviders(); |
| for (Provider provider : providers) { |
| Set<Provider.Service> services = provider.getServices(); |
| for (Provider.Service service : services) { |
| String type = service.getType(); |
| if (!type.equals("Cipher")) { |
| continue; |
| } |
| |
| String algorithm = service.getAlgorithm(); |
| |
| /* |
| * Any specific modes and paddings aren't tested directly here, |
| * but we need to make sure we see the bare algorithm from some |
| * provider. We will test each mode specifically when we get the |
| * base cipher. |
| */ |
| final int firstSlash = algorithm.indexOf('/'); |
| if (firstSlash == -1) { |
| seenBaseCipherNames.add(algorithm); |
| } else { |
| final String baseCipherName = algorithm.substring(0, firstSlash); |
| if (!seenBaseCipherNames.contains(baseCipherName)) { |
| seenCiphersWithModeAndPadding.add(baseCipherName); |
| } |
| if (!"AndroidOpenSSL".equals(provider.getName())) { |
| continue; |
| } |
| } |
| |
| try { |
| test_Cipher_Algorithm(provider, algorithm); |
| } catch (Throwable e) { |
| out.append("Error encountered checking " + algorithm |
| + " with provider " + provider.getName() + "\n"); |
| e.printStackTrace(out); |
| } |
| |
| Set<String> modes = StandardNames.getModesForCipher(algorithm); |
| if (modes != null) { |
| for (String mode : modes) { |
| Set<String> paddings = StandardNames.getPaddingsForCipher(algorithm); |
| if (paddings != null) { |
| for (String padding : paddings) { |
| final String algorithmName = algorithm + "/" + mode + "/" + padding; |
| try { |
| test_Cipher_Algorithm(provider, algorithmName); |
| } catch (Throwable e) { |
| out.append("Error encountered checking " + algorithmName |
| + " with provider " + provider.getName() + "\n"); |
| e.printStackTrace(out); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| seenCiphersWithModeAndPadding.removeAll(seenBaseCipherNames); |
| assertEquals("Ciphers seen with mode and padding but not base cipher", |
| Collections.EMPTY_SET, seenCiphersWithModeAndPadding); |
| |
| out.flush(); |
| if (errBuffer.size() > 0) { |
| throw new Exception("Errors encountered:\n\n" + errBuffer.toString() + "\n\n"); |
| } |
| } |
| |
| private void test_Cipher_Algorithm(Provider provider, String algorithm) throws Exception { |
| if (algorithm.equals("RSA") && provider.getName().equals("BC")) { |
| // http://b/9097343 BC's Cipher.RSA defaults to NoPadding |
| // which makes it fail the key wrapping test if the |
| // generated AES key to wrap starts with a leading |
| // zero. For the purposes of the test, use the same |
| // default behavior as the RI. Real code really should |
| // specify the exact mode and padding they need and not |
| // rely on defaults. http://b/9097343 |
| algorithm = "RSA/ECB/PKCS1Padding"; |
| } |
| |
| // Cipher.getInstance(String) |
| Cipher c1 = Cipher.getInstance(algorithm); |
| if (provider.equals(c1.getProvider())) { |
| assertEquals(algorithm, c1.getAlgorithm()); |
| test_Cipher(c1); |
| } |
| |
| // Cipher.getInstance(String, Provider) |
| Cipher c2 = Cipher.getInstance(algorithm, provider); |
| assertEquals(algorithm, c2.getAlgorithm()); |
| assertEquals(provider, c2.getProvider()); |
| test_Cipher(c2); |
| |
| // Cipher.getInstance(String, String) |
| Cipher c3 = Cipher.getInstance(algorithm, provider.getName()); |
| assertEquals(algorithm, c3.getAlgorithm()); |
| assertEquals(provider, c3.getProvider()); |
| test_Cipher(c3); |
| } |
| |
| private void test_Cipher(Cipher c) throws Exception { |
| String algorithm = c.getAlgorithm().toUpperCase(Locale.US); |
| String providerName = c.getProvider().getName(); |
| if (!isSupported(algorithm, providerName)) { |
| return; |
| } |
| String cipherID = algorithm + ":" + providerName; |
| |
| try { |
| c.getOutputSize(0); |
| } catch (IllegalStateException expected) { |
| } |
| |
| // TODO: test keys from different factories (e.g. OpenSSLRSAPrivateKey vs JCERSAPrivateKey) |
| Key encryptKey = getEncryptKey(algorithm); |
| |
| final AlgorithmParameterSpec encryptSpec = getEncryptAlgorithmParameterSpec(algorithm); |
| int encryptMode = getEncryptMode(algorithm); |
| |
| // Bouncycastle doesn't return a default PBEParameterSpec |
| if (isPBE(algorithm) && !"BC".equals(providerName)) { |
| assertNotNull(cipherID + " getParameters()", c.getParameters()); |
| assertNotNull(c.getParameters().getParameterSpec(PBEParameterSpec.class)); |
| } else { |
| assertNull(cipherID + " getParameters()", c.getParameters()); |
| } |
| try { |
| assertNull(cipherID + " getIV()", c.getIV()); |
| } catch (NullPointerException e) { |
| // Bouncycastle apparently has a bug here with AESWRAP, et al. |
| if (!("BC".equals(providerName) && isOnlyWrappingAlgorithm(algorithm))) { |
| throw e; |
| } |
| } |
| |
| test_Cipher_init_NullParameters(c, encryptMode, encryptKey); |
| |
| c.init(encryptMode, encryptKey, encryptSpec); |
| assertEquals(cipherID + " getBlockSize() encryptMode", |
| getExpectedBlockSize(algorithm, encryptMode, providerName), c.getBlockSize()); |
| assertTrue(cipherID + " getOutputSize(0) encryptMode", |
| getExpectedOutputSize(algorithm, encryptMode, providerName) <= c.getOutputSize(0)); |
| if ((algorithm.endsWith("/PKCS5PADDING") || algorithm.endsWith("/PKCS7PADDING")) |
| && isStreamMode(algorithm)) { |
| assertEquals(getExpectedOutputSize(algorithm, encryptMode, providerName), |
| c.doFinal(new byte[1]).length); |
| } |
| |
| if (isPBE(algorithm)) { |
| if (algorithm.endsWith("RC4")) { |
| assertNull(cipherID + " getIV()", c.getIV()); |
| } else { |
| assertNotNull(cipherID + " getIV()", c.getIV()); |
| } |
| } else if (encryptSpec instanceof IvParameterSpec) { |
| assertEquals(cipherID + " getIV()", |
| Arrays.toString(((IvParameterSpec) encryptSpec).getIV()), |
| Arrays.toString(c.getIV())); |
| } else if (encryptSpec instanceof GCMParameterSpec) { |
| assertNotNull(c.getIV()); |
| assertEquals(cipherID + " getIV()", |
| Arrays.toString(((GCMParameterSpec) encryptSpec).getIV()), |
| Arrays.toString(c.getIV())); |
| } else { |
| try { |
| assertNull(cipherID + " getIV()", c.getIV()); |
| } catch (NullPointerException e) { |
| // Bouncycastle apparently has a bug here with AESWRAP, et al. |
| if (!("BC".equals(providerName) && isOnlyWrappingAlgorithm(algorithm))) { |
| throw e; |
| } |
| } |
| } |
| |
| AlgorithmParameters encParams = c.getParameters(); |
| if (encryptSpec == null) { |
| assertNull(cipherID + " getParameters()", encParams); |
| } else if (encryptSpec instanceof GCMParameterSpec) { |
| GCMParameterSpec gcmDecryptSpec = (GCMParameterSpec) encParams |
| .getParameterSpec(GCMParameterSpec.class); |
| assertEquals(cipherID + " getIV()", |
| Arrays.toString(((GCMParameterSpec) encryptSpec).getIV()), |
| Arrays.toString(gcmDecryptSpec.getIV())); |
| assertEquals(cipherID + " getTLen()", ((GCMParameterSpec) encryptSpec).getTLen(), |
| gcmDecryptSpec.getTLen()); |
| } else if (encryptSpec instanceof IvParameterSpec) { |
| IvParameterSpec ivDecryptSpec = (IvParameterSpec) encParams |
| .getParameterSpec(IvParameterSpec.class); |
| assertEquals(cipherID + " getIV()", |
| Arrays.toString(((IvParameterSpec) encryptSpec).getIV()), |
| Arrays.toString(ivDecryptSpec.getIV())); |
| } else if (encryptSpec instanceof PBEParameterSpec) { |
| // Bouncycastle seems to be undecided about whether it returns this |
| // or not |
| if (!"BC".equals(providerName)) { |
| assertNotNull(cipherID + " getParameters()", encParams); |
| } |
| } |
| |
| final AlgorithmParameterSpec decryptSpec = getDecryptAlgorithmParameterSpec(encryptSpec, c); |
| int decryptMode = getDecryptMode(algorithm); |
| |
| test_Cipher_init_Decrypt_NullParameters(c, decryptMode, encryptKey, decryptSpec != null); |
| |
| c.init(decryptMode, encryptKey, decryptSpec); |
| assertEquals(cipherID + " getBlockSize() decryptMode", |
| getExpectedBlockSize(algorithm, decryptMode, providerName), c.getBlockSize()); |
| assertEquals(cipherID + " getOutputSize(0) decryptMode", |
| getExpectedOutputSize(algorithm, decryptMode, providerName), c.getOutputSize(0)); |
| |
| if (isPBE(algorithm)) { |
| if (algorithm.endsWith("RC4")) { |
| assertNull(cipherID + " getIV()", c.getIV()); |
| } else { |
| assertNotNull(cipherID + " getIV()", c.getIV()); |
| } |
| } else if (decryptSpec instanceof IvParameterSpec) { |
| assertEquals(cipherID + " getIV()", |
| Arrays.toString(((IvParameterSpec) decryptSpec).getIV()), |
| Arrays.toString(c.getIV())); |
| } else if (decryptSpec instanceof GCMParameterSpec) { |
| assertNotNull(c.getIV()); |
| assertEquals(cipherID + " getIV()", |
| Arrays.toString(((GCMParameterSpec) decryptSpec).getIV()), |
| Arrays.toString(c.getIV())); |
| } else { |
| try { |
| assertNull(cipherID + " getIV()", c.getIV()); |
| } catch (NullPointerException e) { |
| // Bouncycastle apparently has a bug here with AESWRAP, et al. |
| if (!("BC".equals(providerName) && isOnlyWrappingAlgorithm(algorithm))) { |
| throw e; |
| } |
| } |
| } |
| |
| AlgorithmParameters decParams = c.getParameters(); |
| if (decryptSpec == null) { |
| assertNull(cipherID + " getParameters()", decParams); |
| } else if (decryptSpec instanceof GCMParameterSpec) { |
| GCMParameterSpec gcmDecryptSpec = (GCMParameterSpec) decParams |
| .getParameterSpec(GCMParameterSpec.class); |
| assertEquals(cipherID + " getIV()", |
| Arrays.toString(((GCMParameterSpec) decryptSpec).getIV()), |
| Arrays.toString(gcmDecryptSpec.getIV())); |
| assertEquals(cipherID + " getTLen()", ((GCMParameterSpec) decryptSpec).getTLen(), |
| gcmDecryptSpec.getTLen()); |
| } else if (decryptSpec instanceof IvParameterSpec) { |
| IvParameterSpec ivDecryptSpec = (IvParameterSpec) decParams |
| .getParameterSpec(IvParameterSpec.class); |
| assertEquals(cipherID + " getIV()", |
| Arrays.toString(((IvParameterSpec) decryptSpec).getIV()), |
| Arrays.toString(ivDecryptSpec.getIV())); |
| } else if (decryptSpec instanceof PBEParameterSpec) { |
| // Bouncycastle seems to be undecided about whether it returns this or not |
| if (!"BC".equals(providerName)) { |
| assertNotNull(cipherID + " getParameters()", decParams); |
| } |
| } |
| |
| assertNull(cipherID, c.getExemptionMechanism()); |
| |
| // Test wrapping a key. Every cipher should be able to wrap. Except those that can't. |
| /* Bouncycastle is broken for wrapping because getIV() fails. */ |
| if (isSupportedForWrapping(algorithm) |
| && !algorithm.equals("AES/GCM/NOPADDING") && !providerName.equals("BC")) { |
| // Generate a small SecretKey for AES. |
| KeyGenerator kg = KeyGenerator.getInstance("AES"); |
| kg.init(128); |
| SecretKey sk = kg.generateKey(); |
| |
| // Wrap it |
| c.init(Cipher.WRAP_MODE, encryptKey, encryptSpec); |
| byte[] cipherText = c.wrap(sk); |
| |
| // Unwrap it |
| c.init(Cipher.UNWRAP_MODE, getDecryptKey(algorithm), decryptSpec); |
| Key decryptedKey = c.unwrap(cipherText, sk.getAlgorithm(), Cipher.SECRET_KEY); |
| |
| assertEquals(cipherID |
| + " sk.getAlgorithm()=" + sk.getAlgorithm() |
| + " decryptedKey.getAlgorithm()=" + decryptedKey.getAlgorithm() |
| + " encryptKey.getEncoded()=" + Arrays.toString(sk.getEncoded()) |
| + " decryptedKey.getEncoded()=" + Arrays.toString(decryptedKey.getEncoded()), |
| sk, decryptedKey); |
| } |
| |
| if (!isOnlyWrappingAlgorithm(algorithm)) { |
| c.init(Cipher.ENCRYPT_MODE, encryptKey, encryptSpec); |
| if (isAEAD(algorithm)) { |
| c.updateAAD(new byte[24]); |
| } |
| byte[] cipherText = c.doFinal(getActualPlainText(algorithm)); |
| if (isAEAD(algorithm)) { |
| c.updateAAD(new byte[24]); |
| } |
| byte[] cipherText2 = c.doFinal(getActualPlainText(algorithm)); |
| assertEquals(cipherID, |
| Arrays.toString(cipherText), |
| Arrays.toString(cipherText2)); |
| c.init(Cipher.DECRYPT_MODE, getDecryptKey(algorithm), decryptSpec); |
| if (isAEAD(algorithm)) { |
| c.updateAAD(new byte[24]); |
| } |
| byte[] decryptedPlainText = c.doFinal(cipherText); |
| assertEquals(cipherID, |
| Arrays.toString(getExpectedPlainText(algorithm, providerName)), |
| Arrays.toString(decryptedPlainText)); |
| if (isAEAD(algorithm)) { |
| c.updateAAD(new byte[24]); |
| } |
| byte[] decryptedPlainText2 = c.doFinal(cipherText); |
| assertEquals(cipherID, |
| Arrays.toString(decryptedPlainText), |
| Arrays.toString(decryptedPlainText2)); |
| } |
| } |
| |
| /** |
| * Try various .init(...) calls with null parameters to make sure it is |
| * handled. |
| */ |
| private void test_Cipher_init_NullParameters(Cipher c, int encryptMode, Key encryptKey) |
| throws Exception { |
| try { |
| c.init(encryptMode, encryptKey, (AlgorithmParameterSpec) null); |
| } catch (InvalidAlgorithmParameterException e) { |
| if (!isPBE(c.getAlgorithm())) { |
| throw e; |
| } |
| } |
| |
| try { |
| c.init(encryptMode, encryptKey, (AlgorithmParameterSpec) null, (SecureRandom) null); |
| } catch (InvalidAlgorithmParameterException e) { |
| if (!isPBE(c.getAlgorithm())) { |
| throw e; |
| } |
| } |
| |
| try { |
| c.init(encryptMode, encryptKey, (AlgorithmParameters) null); |
| } catch (InvalidAlgorithmParameterException e) { |
| if (!isPBE(c.getAlgorithm())) { |
| throw e; |
| } |
| } |
| |
| try { |
| c.init(encryptMode, encryptKey, (AlgorithmParameters) null, (SecureRandom) null); |
| } catch (InvalidAlgorithmParameterException e) { |
| if (!isPBE(c.getAlgorithm())) { |
| throw e; |
| } |
| } |
| } |
| |
| private void test_Cipher_init_Decrypt_NullParameters(Cipher c, int decryptMode, Key encryptKey, |
| boolean needsParameters) throws Exception { |
| try { |
| c.init(decryptMode, encryptKey, (AlgorithmParameterSpec) null); |
| if (needsParameters) { |
| fail("Should throw InvalidAlgorithmParameterException with null parameters"); |
| } |
| } catch (InvalidAlgorithmParameterException e) { |
| if (!needsParameters) { |
| throw e; |
| } |
| } |
| |
| try { |
| c.init(decryptMode, encryptKey, (AlgorithmParameterSpec) null, (SecureRandom) null); |
| if (needsParameters) { |
| fail("Should throw InvalidAlgorithmParameterException with null parameters"); |
| } |
| } catch (InvalidAlgorithmParameterException e) { |
| if (!needsParameters) { |
| throw e; |
| } |
| } |
| |
| try { |
| c.init(decryptMode, encryptKey, (AlgorithmParameters) null); |
| if (needsParameters) { |
| fail("Should throw InvalidAlgorithmParameterException with null parameters"); |
| } |
| } catch (InvalidAlgorithmParameterException e) { |
| if (!needsParameters) { |
| throw e; |
| } |
| } |
| |
| try { |
| c.init(decryptMode, encryptKey, (AlgorithmParameters) null, (SecureRandom) null); |
| if (needsParameters) { |
| fail("Should throw InvalidAlgorithmParameterException with null parameters"); |
| } |
| } catch (InvalidAlgorithmParameterException e) { |
| if (!needsParameters) { |
| throw e; |
| } |
| } |
| } |
| |
| public void testInputPKCS1Padding() throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testInputPKCS1Padding(provider); |
| } |
| } |
| |
| private void testInputPKCS1Padding(String provider) throws Exception { |
| testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_01_PADDED_PLAIN_TEXT, getEncryptKey("RSA"), getDecryptKey("RSA")); |
| try { |
| testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT, getEncryptKey("RSA"), getDecryptKey("RSA")); |
| fail(); |
| } catch (BadPaddingException expected) { |
| } |
| try { |
| testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_01_PADDED_PLAIN_TEXT, getDecryptKey("RSA"), getEncryptKey("RSA")); |
| fail(); |
| } catch (BadPaddingException expected) { |
| } |
| testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT, getDecryptKey("RSA"), getEncryptKey("RSA")); |
| } |
| |
| private void testInputPKCS1Padding(String provider, byte[] prePaddedPlainText, Key encryptKey, Key decryptKey) throws Exception { |
| Cipher encryptCipher = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| encryptCipher.init(Cipher.ENCRYPT_MODE, encryptKey); |
| byte[] cipherText = encryptCipher.doFinal(prePaddedPlainText); |
| encryptCipher.update(prePaddedPlainText); |
| encryptCipher.init(Cipher.ENCRYPT_MODE, encryptKey); |
| byte[] cipherText2 = encryptCipher.doFinal(prePaddedPlainText); |
| assertEquals(Arrays.toString(cipherText), |
| Arrays.toString(cipherText2)); |
| |
| Cipher decryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider); |
| decryptCipher.init(Cipher.DECRYPT_MODE, decryptKey); |
| byte[] plainText = decryptCipher.doFinal(cipherText); |
| assertEquals(Arrays.toString(ORIGINAL_PLAIN_TEXT), |
| Arrays.toString(plainText)); |
| decryptCipher.update(prePaddedPlainText); |
| decryptCipher.init(Cipher.DECRYPT_MODE, decryptKey); |
| byte[] plainText2 = decryptCipher.doFinal(cipherText); |
| assertEquals(Arrays.toString(plainText), |
| Arrays.toString(plainText2)); |
| } |
| |
| public void testOutputPKCS1Padding() throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testOutputPKCS1Padding(provider); |
| } |
| } |
| |
| private void testOutputPKCS1Padding(String provider) throws Exception { |
| testOutputPKCS1Padding(provider, (byte) 1, getEncryptKey("RSA"), getDecryptKey("RSA")); |
| testOutputPKCS1Padding(provider, (byte) 2, getDecryptKey("RSA"), getEncryptKey("RSA")); |
| } |
| |
| private void testOutputPKCS1Padding(String provider, byte expectedBlockType, Key encryptKey, Key decryptKey) throws Exception { |
| Cipher encryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider); |
| encryptCipher.init(Cipher.ENCRYPT_MODE, encryptKey); |
| byte[] cipherText = encryptCipher.doFinal(ORIGINAL_PLAIN_TEXT); |
| Cipher decryptCipher = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| decryptCipher.init(Cipher.DECRYPT_MODE, decryptKey); |
| byte[] plainText = decryptCipher.doFinal(cipherText); |
| assertPadding(provider, expectedBlockType, ORIGINAL_PLAIN_TEXT, plainText); |
| } |
| |
| private void assertPadding(String provider, byte expectedBlockType, byte[] expectedData, byte[] actualDataWithPadding) { |
| assertNotNull(provider, actualDataWithPadding); |
| int expectedOutputSize = getExpectedOutputSize("RSA", Cipher.DECRYPT_MODE, provider); |
| assertEquals(provider, expectedOutputSize, actualDataWithPadding.length); |
| int expectedBlockTypeOffset; |
| if (provider.equals("BC")) { |
| // BC strips the leading 0 for us on decrypt even when NoPadding is specified... |
| expectedBlockTypeOffset = 0; |
| } else { |
| expectedBlockTypeOffset = 1; |
| assertEquals(provider, 0, actualDataWithPadding[0]); |
| } |
| byte actualBlockType = actualDataWithPadding[expectedBlockTypeOffset]; |
| assertEquals(provider, expectedBlockType, actualBlockType); |
| int actualDataOffset = actualDataWithPadding.length - expectedData.length; |
| if (actualBlockType == 1) { |
| int expectedDataOffset = expectedBlockTypeOffset + 1; |
| for (int i = expectedDataOffset; i < actualDataOffset - 1; i++) { |
| assertEquals(provider, (byte) 0xFF, actualDataWithPadding[i]); |
| } |
| } |
| assertEquals(provider, 0x00, actualDataWithPadding[actualDataOffset-1]); |
| byte[] actualData = new byte[expectedData.length]; |
| System.arraycopy(actualDataWithPadding, actualDataOffset, actualData, 0, actualData.length); |
| assertEquals(provider, Arrays.toString(expectedData), Arrays.toString(actualData)); |
| } |
| |
| public void testCipherInitWithCertificate () throws Exception { |
| // no key usage specified, everything is fine |
| assertCipherInitWithKeyUsage(0, true, true, true, true); |
| |
| // common case is that encrypt/wrap is prohibited when special usage is specified |
| assertCipherInitWithKeyUsage(KeyUsage.digitalSignature, false, true, false, true); |
| assertCipherInitWithKeyUsage(KeyUsage.nonRepudiation, false, true, false, true); |
| assertCipherInitWithKeyUsage(KeyUsage.keyAgreement, false, true, false, true); |
| assertCipherInitWithKeyUsage(KeyUsage.keyCertSign, false, true, false, true); |
| assertCipherInitWithKeyUsage(KeyUsage.cRLSign, false, true, false, true); |
| |
| // Note they encipherOnly/decipherOnly don't have to do with |
| // ENCRYPT_MODE or DECRYPT_MODE, but restrict usage relative |
| // to keyAgreement. There is not a *_MODE option that |
| // corresponds to this in Cipher, the RI does not enforce |
| // anything in Cipher. |
| // http://code.google.com/p/android/issues/detail?id=12955 |
| assertCipherInitWithKeyUsage(KeyUsage.encipherOnly, false, true, false, true); |
| assertCipherInitWithKeyUsage(KeyUsage.decipherOnly, false, true, false, true); |
| assertCipherInitWithKeyUsage(KeyUsage.keyAgreement | KeyUsage.encipherOnly, |
| false, true, false, true); |
| assertCipherInitWithKeyUsage(KeyUsage.keyAgreement | KeyUsage.decipherOnly, |
| false, true, false, true); |
| |
| // except when wrapping a key is specifically allowed or |
| assertCipherInitWithKeyUsage(KeyUsage.keyEncipherment, false, true, true, true); |
| // except when wrapping data encryption is specifically allowed |
| assertCipherInitWithKeyUsage(KeyUsage.dataEncipherment, true, true, false, true); |
| } |
| |
| private void assertCipherInitWithKeyUsage (int keyUsage, |
| boolean allowEncrypt, |
| boolean allowDecrypt, |
| boolean allowWrap, |
| boolean allowUnwrap) throws Exception { |
| Certificate certificate = certificateWithKeyUsage(keyUsage); |
| assertCipherInitWithKeyUsage(certificate, allowEncrypt, Cipher.ENCRYPT_MODE); |
| assertCipherInitWithKeyUsage(certificate, allowDecrypt, Cipher.DECRYPT_MODE); |
| assertCipherInitWithKeyUsage(certificate, allowWrap, Cipher.WRAP_MODE); |
| assertCipherInitWithKeyUsage(certificate, allowUnwrap, Cipher.UNWRAP_MODE); |
| } |
| |
| private void assertCipherInitWithKeyUsage(Certificate certificate, |
| boolean allowMode, |
| int mode) throws Exception { |
| Cipher cipher = Cipher.getInstance("RSA"); |
| if (allowMode) { |
| cipher.init(mode, certificate); |
| } else { |
| try { |
| cipher.init(mode, certificate); |
| String modeString; |
| switch (mode) { |
| case Cipher.ENCRYPT_MODE: |
| modeString = "ENCRYPT_MODE"; |
| break; |
| case Cipher.DECRYPT_MODE: |
| modeString = "DECRYPT_MODE"; |
| break; |
| case Cipher.WRAP_MODE: |
| modeString = "WRAP_MODE"; |
| break; |
| case Cipher.UNWRAP_MODE: |
| modeString = "UNWRAP_MODE"; |
| break; |
| default: |
| throw new AssertionError("Unknown Cipher.*_MODE " + mode); |
| } |
| fail("Should have had InvalidKeyException for " + modeString |
| + " for " + certificate); |
| } catch (InvalidKeyException expected) { |
| } |
| } |
| } |
| |
| private Certificate certificateWithKeyUsage(int keyUsage) throws Exception { |
| // note the rare usage of non-zero keyUsage |
| return new TestKeyStore.Builder() |
| .aliasPrefix("rsa-dsa-ec") |
| .keyUsage(keyUsage) |
| .build() |
| .getPrivateKey("RSA", "RSA").getCertificate(); |
| } |
| |
| /* |
| * Test vectors generated with this private key: |
| * |
| * -----BEGIN RSA PRIVATE KEY----- |
| * MIIEpAIBAAKCAQEA4Ec+irjyKE/rnnQv+XSPoRjtmGM8kvUq63ouvg075gMpvnZq |
| * 0Q62pRXQ0s/ZvqeTDwwwZTeJn3lYzT6FsB+IGFJNMSWEqUslHjYltUFB7b/uGYgI |
| * 4buX/Hy0m56qr2jpyY19DtxTu8D6ADQ1bWMF+7zDxwAUBThqu8hzyw8+90JfPTPf |
| * ezFa4DbSoLZq/UdQOxab8247UWJRW3Ff2oPeryxYrrmr+zCXw8yd2dvl7ylsF2E5 |
| * Ao6KZx5jBW1F9AGI0sQTNJCEXeUsJTTpxrJHjAe9rpKII7YtBmx3cPn2Pz26JH9T |
| * CER0e+eqqF2FO4vSRKzsPePImrRkU6tNJMOsaQIDAQABAoIBADd4R3al8XaY9ayW |
| * DfuDobZ1ZOZIvQWXz4q4CHGG8macJ6nsvdSA8Bl6gNBzCebGqW+SUzHlf4tKxvTU |
| * XtpFojJpwJ/EKMB6Tm7fc4oV3sl/q9Lyu0ehTyDqcvz+TDbgGtp3vRN82NTaELsW |
| * LpSkZilx8XX5hfoYjwVsuX7igW9Dq503R2Ekhs2owWGWwwgYqZXshdOEZ3kSZ7O/ |
| * IfJzcQppJYYldoQcW2cSwS1L0govMpmtt8E12l6VFavadufK8qO+gFUdBzt4vxFi |
| * xIrSt/R0OgI47k0lL31efmUzzK5kzLOTYAdaL9HgNOw65c6cQIzL8OJeQRQCFoez |
| * 3UdUroECgYEA9UGIS8Nzeyki1BGe9F4t7izUy7dfRVBaFXqlAJ+Zxzot8HJKxGAk |
| * MGMy6omBd2NFRl3G3x4KbxQK/ztzluaomUrF2qloc0cv43dJ0U6z4HXmKdvrNYMz |
| * im82SdCiZUp6Qv2atr+krE1IHTkLsimwZL3DEcwb4bYxidp8QM3s8rECgYEA6hp0 |
| * LduIHO23KIyH442GjdekCdFaQ/RF1Td6C1cx3b/KLa8oqOE81cCvzsM0fXSjniNa |
| * PNljPydN4rlPkt9DgzkR2enxz1jyfeLgj/RZZMcg0+whOdx8r8kSlTzeyy81Wi4s |
| * NaUPrXVMs7IxZkJLo7bjESoriYw4xcFe2yOGkzkCgYBRgo8exv2ZYCmQG68dfjN7 |
| * pfCvJ+mE6tiVrOYr199O5FoiQInyzBUa880XP84EdLywTzhqLNzA4ANrokGfVFeS |
| * YtRxAL6TGYSj76Bb7PFBV03AebOpXEqD5sQ/MhTW3zLVEt4ZgIXlMeYWuD/X3Z0f |
| * TiYHwzM9B8VdEH0dOJNYcQKBgQDbT7UPUN6O21P/NMgJMYigUShn2izKBIl3WeWH |
| * wkQBDa+GZNWegIPRbBZHiTAfZ6nweAYNg0oq29NnV1toqKhCwrAqibPzH8zsiiL+ |
| * OVeVxcbHQitOXXSh6ajzDndZufwtY5wfFWc+hOk6XvFQb0MVODw41Fy9GxQEj0ch |
| * 3IIyYQKBgQDYEUWTr0FfthLb8ZI3ENVNB0hiBadqO0MZSWjA3/HxHvD2GkozfV/T |
| * dBu8lkDkR7i2tsR8OsEgQ1fTsMVbqShr2nP2KSlvX6kUbYl2NX08dR51FIaWpAt0 |
| * aFyCzjCQLWOdck/yTV4ulAfuNO3tLjtN9lqpvP623yjQe6aQPxZXaA== |
| * -----END RSA PRIVATE KEY----- |
| * |
| */ |
| |
| private static final BigInteger RSA_2048_modulus = new BigInteger(new byte[] { |
| (byte) 0x00, (byte) 0xe0, (byte) 0x47, (byte) 0x3e, (byte) 0x8a, (byte) 0xb8, (byte) 0xf2, (byte) 0x28, |
| (byte) 0x4f, (byte) 0xeb, (byte) 0x9e, (byte) 0x74, (byte) 0x2f, (byte) 0xf9, (byte) 0x74, (byte) 0x8f, |
| (byte) 0xa1, (byte) 0x18, (byte) 0xed, (byte) 0x98, (byte) 0x63, (byte) 0x3c, (byte) 0x92, (byte) 0xf5, |
| (byte) 0x2a, (byte) 0xeb, (byte) 0x7a, (byte) 0x2e, (byte) 0xbe, (byte) 0x0d, (byte) 0x3b, (byte) 0xe6, |
| (byte) 0x03, (byte) 0x29, (byte) 0xbe, (byte) 0x76, (byte) 0x6a, (byte) 0xd1, (byte) 0x0e, (byte) 0xb6, |
| (byte) 0xa5, (byte) 0x15, (byte) 0xd0, (byte) 0xd2, (byte) 0xcf, (byte) 0xd9, (byte) 0xbe, (byte) 0xa7, |
| (byte) 0x93, (byte) 0x0f, (byte) 0x0c, (byte) 0x30, (byte) 0x65, (byte) 0x37, (byte) 0x89, (byte) 0x9f, |
| (byte) 0x79, (byte) 0x58, (byte) 0xcd, (byte) 0x3e, (byte) 0x85, (byte) 0xb0, (byte) 0x1f, (byte) 0x88, |
| (byte) 0x18, (byte) 0x52, (byte) 0x4d, (byte) 0x31, (byte) 0x25, (byte) 0x84, (byte) 0xa9, (byte) 0x4b, |
| (byte) 0x25, (byte) 0x1e, (byte) 0x36, (byte) 0x25, (byte) 0xb5, (byte) 0x41, (byte) 0x41, (byte) 0xed, |
| (byte) 0xbf, (byte) 0xee, (byte) 0x19, (byte) 0x88, (byte) 0x08, (byte) 0xe1, (byte) 0xbb, (byte) 0x97, |
| (byte) 0xfc, (byte) 0x7c, (byte) 0xb4, (byte) 0x9b, (byte) 0x9e, (byte) 0xaa, (byte) 0xaf, (byte) 0x68, |
| (byte) 0xe9, (byte) 0xc9, (byte) 0x8d, (byte) 0x7d, (byte) 0x0e, (byte) 0xdc, (byte) 0x53, (byte) 0xbb, |
| (byte) 0xc0, (byte) 0xfa, (byte) 0x00, (byte) 0x34, (byte) 0x35, (byte) 0x6d, (byte) 0x63, (byte) 0x05, |
| (byte) 0xfb, (byte) 0xbc, (byte) 0xc3, (byte) 0xc7, (byte) 0x00, (byte) 0x14, (byte) 0x05, (byte) 0x38, |
| (byte) 0x6a, (byte) 0xbb, (byte) 0xc8, (byte) 0x73, (byte) 0xcb, (byte) 0x0f, (byte) 0x3e, (byte) 0xf7, |
| (byte) 0x42, (byte) 0x5f, (byte) 0x3d, (byte) 0x33, (byte) 0xdf, (byte) 0x7b, (byte) 0x31, (byte) 0x5a, |
| (byte) 0xe0, (byte) 0x36, (byte) 0xd2, (byte) 0xa0, (byte) 0xb6, (byte) 0x6a, (byte) 0xfd, (byte) 0x47, |
| (byte) 0x50, (byte) 0x3b, (byte) 0x16, (byte) 0x9b, (byte) 0xf3, (byte) 0x6e, (byte) 0x3b, (byte) 0x51, |
| (byte) 0x62, (byte) 0x51, (byte) 0x5b, (byte) 0x71, (byte) 0x5f, (byte) 0xda, (byte) 0x83, (byte) 0xde, |
| (byte) 0xaf, (byte) 0x2c, (byte) 0x58, (byte) 0xae, (byte) 0xb9, (byte) 0xab, (byte) 0xfb, (byte) 0x30, |
| (byte) 0x97, (byte) 0xc3, (byte) 0xcc, (byte) 0x9d, (byte) 0xd9, (byte) 0xdb, (byte) 0xe5, (byte) 0xef, |
| (byte) 0x29, (byte) 0x6c, (byte) 0x17, (byte) 0x61, (byte) 0x39, (byte) 0x02, (byte) 0x8e, (byte) 0x8a, |
| (byte) 0x67, (byte) 0x1e, (byte) 0x63, (byte) 0x05, (byte) 0x6d, (byte) 0x45, (byte) 0xf4, (byte) 0x01, |
| (byte) 0x88, (byte) 0xd2, (byte) 0xc4, (byte) 0x13, (byte) 0x34, (byte) 0x90, (byte) 0x84, (byte) 0x5d, |
| (byte) 0xe5, (byte) 0x2c, (byte) 0x25, (byte) 0x34, (byte) 0xe9, (byte) 0xc6, (byte) 0xb2, (byte) 0x47, |
| (byte) 0x8c, (byte) 0x07, (byte) 0xbd, (byte) 0xae, (byte) 0x92, (byte) 0x88, (byte) 0x23, (byte) 0xb6, |
| (byte) 0x2d, (byte) 0x06, (byte) 0x6c, (byte) 0x77, (byte) 0x70, (byte) 0xf9, (byte) 0xf6, (byte) 0x3f, |
| (byte) 0x3d, (byte) 0xba, (byte) 0x24, (byte) 0x7f, (byte) 0x53, (byte) 0x08, (byte) 0x44, (byte) 0x74, |
| (byte) 0x7b, (byte) 0xe7, (byte) 0xaa, (byte) 0xa8, (byte) 0x5d, (byte) 0x85, (byte) 0x3b, (byte) 0x8b, |
| (byte) 0xd2, (byte) 0x44, (byte) 0xac, (byte) 0xec, (byte) 0x3d, (byte) 0xe3, (byte) 0xc8, (byte) 0x9a, |
| (byte) 0xb4, (byte) 0x64, (byte) 0x53, (byte) 0xab, (byte) 0x4d, (byte) 0x24, (byte) 0xc3, (byte) 0xac, |
| (byte) 0x69, |
| }); |
| |
| private static final BigInteger RSA_2048_privateExponent = new BigInteger(new byte[] { |
| (byte) 0x37, (byte) 0x78, (byte) 0x47, (byte) 0x76, (byte) 0xa5, (byte) 0xf1, (byte) 0x76, (byte) 0x98, |
| (byte) 0xf5, (byte) 0xac, (byte) 0x96, (byte) 0x0d, (byte) 0xfb, (byte) 0x83, (byte) 0xa1, (byte) 0xb6, |
| (byte) 0x75, (byte) 0x64, (byte) 0xe6, (byte) 0x48, (byte) 0xbd, (byte) 0x05, (byte) 0x97, (byte) 0xcf, |
| (byte) 0x8a, (byte) 0xb8, (byte) 0x08, (byte) 0x71, (byte) 0x86, (byte) 0xf2, (byte) 0x66, (byte) 0x9c, |
| (byte) 0x27, (byte) 0xa9, (byte) 0xec, (byte) 0xbd, (byte) 0xd4, (byte) 0x80, (byte) 0xf0, (byte) 0x19, |
| (byte) 0x7a, (byte) 0x80, (byte) 0xd0, (byte) 0x73, (byte) 0x09, (byte) 0xe6, (byte) 0xc6, (byte) 0xa9, |
| (byte) 0x6f, (byte) 0x92, (byte) 0x53, (byte) 0x31, (byte) 0xe5, (byte) 0x7f, (byte) 0x8b, (byte) 0x4a, |
| (byte) 0xc6, (byte) 0xf4, (byte) 0xd4, (byte) 0x5e, (byte) 0xda, (byte) 0x45, (byte) 0xa2, (byte) 0x32, |
| (byte) 0x69, (byte) 0xc0, (byte) 0x9f, (byte) 0xc4, (byte) 0x28, (byte) 0xc0, (byte) 0x7a, (byte) 0x4e, |
| (byte) 0x6e, (byte) 0xdf, (byte) 0x73, (byte) 0x8a, (byte) 0x15, (byte) 0xde, (byte) 0xc9, (byte) 0x7f, |
| (byte) 0xab, (byte) 0xd2, (byte) 0xf2, (byte) 0xbb, (byte) 0x47, (byte) 0xa1, (byte) 0x4f, (byte) 0x20, |
| (byte) 0xea, (byte) 0x72, (byte) 0xfc, (byte) 0xfe, (byte) 0x4c, (byte) 0x36, (byte) 0xe0, (byte) 0x1a, |
| (byte) 0xda, (byte) 0x77, (byte) 0xbd, (byte) 0x13, (byte) 0x7c, (byte) 0xd8, (byte) 0xd4, (byte) 0xda, |
| (byte) 0x10, (byte) 0xbb, (byte) 0x16, (byte) 0x2e, (byte) 0x94, (byte) 0xa4, (byte) 0x66, (byte) 0x29, |
| (byte) 0x71, (byte) 0xf1, (byte) 0x75, (byte) 0xf9, (byte) 0x85, (byte) 0xfa, (byte) 0x18, (byte) 0x8f, |
| (byte) 0x05, (byte) 0x6c, (byte) 0xb9, (byte) 0x7e, (byte) 0xe2, (byte) 0x81, (byte) 0x6f, (byte) 0x43, |
| (byte) 0xab, (byte) 0x9d, (byte) 0x37, (byte) 0x47, (byte) 0x61, (byte) 0x24, (byte) 0x86, (byte) 0xcd, |
| (byte) 0xa8, (byte) 0xc1, (byte) 0x61, (byte) 0x96, (byte) 0xc3, (byte) 0x08, (byte) 0x18, (byte) 0xa9, |
| (byte) 0x95, (byte) 0xec, (byte) 0x85, (byte) 0xd3, (byte) 0x84, (byte) 0x67, (byte) 0x79, (byte) 0x12, |
| (byte) 0x67, (byte) 0xb3, (byte) 0xbf, (byte) 0x21, (byte) 0xf2, (byte) 0x73, (byte) 0x71, (byte) 0x0a, |
| (byte) 0x69, (byte) 0x25, (byte) 0x86, (byte) 0x25, (byte) 0x76, (byte) 0x84, (byte) 0x1c, (byte) 0x5b, |
| (byte) 0x67, (byte) 0x12, (byte) 0xc1, (byte) 0x2d, (byte) 0x4b, (byte) 0xd2, (byte) 0x0a, (byte) 0x2f, |
| (byte) 0x32, (byte) 0x99, (byte) 0xad, (byte) 0xb7, (byte) 0xc1, (byte) 0x35, (byte) 0xda, (byte) 0x5e, |
| (byte) 0x95, (byte) 0x15, (byte) 0xab, (byte) 0xda, (byte) 0x76, (byte) 0xe7, (byte) 0xca, (byte) 0xf2, |
| (byte) 0xa3, (byte) 0xbe, (byte) 0x80, (byte) 0x55, (byte) 0x1d, (byte) 0x07, (byte) 0x3b, (byte) 0x78, |
| (byte) 0xbf, (byte) 0x11, (byte) 0x62, (byte) 0xc4, (byte) 0x8a, (byte) 0xd2, (byte) 0xb7, (byte) 0xf4, |
| (byte) 0x74, (byte) 0x3a, (byte) 0x02, (byte) 0x38, (byte) 0xee, (byte) 0x4d, (byte) 0x25, (byte) 0x2f, |
| (byte) 0x7d, (byte) 0x5e, (byte) 0x7e, (byte) 0x65, (byte) 0x33, (byte) 0xcc, (byte) 0xae, (byte) 0x64, |
| (byte) 0xcc, (byte) 0xb3, (byte) 0x93, (byte) 0x60, (byte) 0x07, (byte) 0x5a, (byte) 0x2f, (byte) 0xd1, |
| (byte) 0xe0, (byte) 0x34, (byte) 0xec, (byte) 0x3a, (byte) 0xe5, (byte) 0xce, (byte) 0x9c, (byte) 0x40, |
| (byte) 0x8c, (byte) 0xcb, (byte) 0xf0, (byte) 0xe2, (byte) 0x5e, (byte) 0x41, (byte) 0x14, (byte) 0x02, |
| (byte) 0x16, (byte) 0x87, (byte) 0xb3, (byte) 0xdd, (byte) 0x47, (byte) 0x54, (byte) 0xae, (byte) 0x81, |
| }); |
| |
| private static final BigInteger RSA_2048_publicExponent = new BigInteger(new byte[] { |
| (byte) 0x01, (byte) 0x00, (byte) 0x01, |
| }); |
| |
| private static final BigInteger RSA_2048_primeP = new BigInteger(new byte[] { |
| (byte) 0x00, (byte) 0xf5, (byte) 0x41, (byte) 0x88, (byte) 0x4b, (byte) 0xc3, (byte) 0x73, (byte) 0x7b, |
| (byte) 0x29, (byte) 0x22, (byte) 0xd4, (byte) 0x11, (byte) 0x9e, (byte) 0xf4, (byte) 0x5e, (byte) 0x2d, |
| (byte) 0xee, (byte) 0x2c, (byte) 0xd4, (byte) 0xcb, (byte) 0xb7, (byte) 0x5f, (byte) 0x45, (byte) 0x50, |
| (byte) 0x5a, (byte) 0x15, (byte) 0x7a, (byte) 0xa5, (byte) 0x00, (byte) 0x9f, (byte) 0x99, (byte) 0xc7, |
| (byte) 0x3a, (byte) 0x2d, (byte) 0xf0, (byte) 0x72, (byte) 0x4a, (byte) 0xc4, (byte) 0x60, (byte) 0x24, |
| (byte) 0x30, (byte) 0x63, (byte) 0x32, (byte) 0xea, (byte) 0x89, (byte) 0x81, (byte) 0x77, (byte) 0x63, |
| (byte) 0x45, (byte) 0x46, (byte) 0x5d, (byte) 0xc6, (byte) 0xdf, (byte) 0x1e, (byte) 0x0a, (byte) 0x6f, |
| (byte) 0x14, (byte) 0x0a, (byte) 0xff, (byte) 0x3b, (byte) 0x73, (byte) 0x96, (byte) 0xe6, (byte) 0xa8, |
| (byte) 0x99, (byte) 0x4a, (byte) 0xc5, (byte) 0xda, (byte) 0xa9, (byte) 0x68, (byte) 0x73, (byte) 0x47, |
| (byte) 0x2f, (byte) 0xe3, (byte) 0x77, (byte) 0x49, (byte) 0xd1, (byte) 0x4e, (byte) 0xb3, (byte) 0xe0, |
| (byte) 0x75, (byte) 0xe6, (byte) 0x29, (byte) 0xdb, (byte) 0xeb, (byte) 0x35, (byte) 0x83, (byte) 0x33, |
| (byte) 0x8a, (byte) 0x6f, (byte) 0x36, (byte) 0x49, (byte) 0xd0, (byte) 0xa2, (byte) 0x65, (byte) 0x4a, |
| (byte) 0x7a, (byte) 0x42, (byte) 0xfd, (byte) 0x9a, (byte) 0xb6, (byte) 0xbf, (byte) 0xa4, (byte) 0xac, |
| (byte) 0x4d, (byte) 0x48, (byte) 0x1d, (byte) 0x39, (byte) 0x0b, (byte) 0xb2, (byte) 0x29, (byte) 0xb0, |
| (byte) 0x64, (byte) 0xbd, (byte) 0xc3, (byte) 0x11, (byte) 0xcc, (byte) 0x1b, (byte) 0xe1, (byte) 0xb6, |
| (byte) 0x31, (byte) 0x89, (byte) 0xda, (byte) 0x7c, (byte) 0x40, (byte) 0xcd, (byte) 0xec, (byte) 0xf2, |
| (byte) 0xb1, |
| }); |
| |
| private static final BigInteger RSA_2048_primeQ = new BigInteger(new byte[] { |
| (byte) 0x00, (byte) 0xea, (byte) 0x1a, (byte) 0x74, (byte) 0x2d, (byte) 0xdb, (byte) 0x88, (byte) 0x1c, |
| (byte) 0xed, (byte) 0xb7, (byte) 0x28, (byte) 0x8c, (byte) 0x87, (byte) 0xe3, (byte) 0x8d, (byte) 0x86, |
| (byte) 0x8d, (byte) 0xd7, (byte) 0xa4, (byte) 0x09, (byte) 0xd1, (byte) 0x5a, (byte) 0x43, (byte) 0xf4, |
| (byte) 0x45, (byte) 0xd5, (byte) 0x37, (byte) 0x7a, (byte) 0x0b, (byte) 0x57, (byte) 0x31, (byte) 0xdd, |
| (byte) 0xbf, (byte) 0xca, (byte) 0x2d, (byte) 0xaf, (byte) 0x28, (byte) 0xa8, (byte) 0xe1, (byte) 0x3c, |
| (byte) 0xd5, (byte) 0xc0, (byte) 0xaf, (byte) 0xce, (byte) 0xc3, (byte) 0x34, (byte) 0x7d, (byte) 0x74, |
| (byte) 0xa3, (byte) 0x9e, (byte) 0x23, (byte) 0x5a, (byte) 0x3c, (byte) 0xd9, (byte) 0x63, (byte) 0x3f, |
| (byte) 0x27, (byte) 0x4d, (byte) 0xe2, (byte) 0xb9, (byte) 0x4f, (byte) 0x92, (byte) 0xdf, (byte) 0x43, |
| (byte) 0x83, (byte) 0x39, (byte) 0x11, (byte) 0xd9, (byte) 0xe9, (byte) 0xf1, (byte) 0xcf, (byte) 0x58, |
| (byte) 0xf2, (byte) 0x7d, (byte) 0xe2, (byte) 0xe0, (byte) 0x8f, (byte) 0xf4, (byte) 0x59, (byte) 0x64, |
| (byte) 0xc7, (byte) 0x20, (byte) 0xd3, (byte) 0xec, (byte) 0x21, (byte) 0x39, (byte) 0xdc, (byte) 0x7c, |
| (byte) 0xaf, (byte) 0xc9, (byte) 0x12, (byte) 0x95, (byte) 0x3c, (byte) 0xde, (byte) 0xcb, (byte) 0x2f, |
| (byte) 0x35, (byte) 0x5a, (byte) 0x2e, (byte) 0x2c, (byte) 0x35, (byte) 0xa5, (byte) 0x0f, (byte) 0xad, |
| (byte) 0x75, (byte) 0x4c, (byte) 0xb3, (byte) 0xb2, (byte) 0x31, (byte) 0x66, (byte) 0x42, (byte) 0x4b, |
| (byte) 0xa3, (byte) 0xb6, (byte) 0xe3, (byte) 0x11, (byte) 0x2a, (byte) 0x2b, (byte) 0x89, (byte) 0x8c, |
| (byte) 0x38, (byte) 0xc5, (byte) 0xc1, (byte) 0x5e, (byte) 0xdb, (byte) 0x23, (byte) 0x86, (byte) 0x93, |
| (byte) 0x39, |
| }); |
| |
| /** |
| * Test data is PKCS#1 padded "Android.\n" which can be generated by: |
| * echo "Android." | openssl rsautl -inkey rsa.key -sign | openssl rsautl -inkey rsa.key -raw -verify | recode ../x1 |
| */ |
| private static final byte[] RSA_2048_Vector1 = new byte[] { |
| (byte) 0x00, (byte) 0x01, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, |
| (byte) 0x00, (byte) 0x41, (byte) 0x6E, (byte) 0x64, (byte) 0x72, (byte) 0x6F, |
| (byte) 0x69, (byte) 0x64, (byte) 0x2E, (byte) 0x0A, |
| }; |
| |
| /** |
| * This vector is simply "Android.\n" which is too short. |
| */ |
| private static final byte[] TooShort_Vector = new byte[] { |
| (byte) 0x41, (byte) 0x6E, (byte) 0x64, (byte) 0x72, (byte) 0x6F, (byte) 0x69, |
| (byte) 0x64, (byte) 0x2E, (byte) 0x0A, |
| }; |
| |
| /** |
| * This vector is simply "Android.\n" padded with zeros. |
| */ |
| private static final byte[] TooShort_Vector_Zero_Padded = new byte[] { |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, |
| (byte) 0x69, (byte) 0x64, (byte) 0x2e, (byte) 0x0a, |
| }; |
| |
| /** |
| * openssl rsautl -raw -sign -inkey rsa.key | recode ../x1 | sed 's/0x/(byte) 0x/g' |
| */ |
| private static final byte[] RSA_Vector1_Encrypt_Private = new byte[] { |
| (byte) 0x35, (byte) 0x43, (byte) 0x38, (byte) 0x44, (byte) 0xAD, (byte) 0x3F, |
| (byte) 0x97, (byte) 0x02, (byte) 0xFB, (byte) 0x59, (byte) 0x1F, (byte) 0x4A, |
| (byte) 0x2B, (byte) 0xB9, (byte) 0x06, (byte) 0xEC, (byte) 0x66, (byte) 0xE6, |
| (byte) 0xD2, (byte) 0xC5, (byte) 0x8B, (byte) 0x7B, (byte) 0xE3, (byte) 0x18, |
| (byte) 0xBF, (byte) 0x07, (byte) 0xD6, (byte) 0x01, (byte) 0xF9, (byte) 0xD9, |
| (byte) 0x89, (byte) 0xC4, (byte) 0xDB, (byte) 0x00, (byte) 0x68, (byte) 0xFF, |
| (byte) 0x9B, (byte) 0x43, (byte) 0x90, (byte) 0xF2, (byte) 0xDB, (byte) 0x83, |
| (byte) 0xF4, (byte) 0x7E, (byte) 0xC6, (byte) 0x81, (byte) 0x01, (byte) 0x3A, |
| (byte) 0x0B, (byte) 0xE5, (byte) 0xED, (byte) 0x08, (byte) 0x73, (byte) 0x3E, |
| (byte) 0xE1, (byte) 0x3F, (byte) 0xDF, (byte) 0x1F, (byte) 0x07, (byte) 0x6D, |
| (byte) 0x22, (byte) 0x8D, (byte) 0xCC, (byte) 0x4E, (byte) 0xE3, (byte) 0x9A, |
| (byte) 0xBC, (byte) 0xCC, (byte) 0x8F, (byte) 0x9E, (byte) 0x9B, (byte) 0x02, |
| (byte) 0x48, (byte) 0x00, (byte) 0xAC, (byte) 0x9F, (byte) 0xA4, (byte) 0x8F, |
| (byte) 0x87, (byte) 0xA1, (byte) 0xA8, (byte) 0xE6, (byte) 0x9D, (byte) 0xCD, |
| (byte) 0x8B, (byte) 0x05, (byte) 0xE9, (byte) 0xD2, (byte) 0x05, (byte) 0x8D, |
| (byte) 0xC9, (byte) 0x95, (byte) 0x16, (byte) 0xD0, (byte) 0xCD, (byte) 0x43, |
| (byte) 0x25, (byte) 0x8A, (byte) 0x11, (byte) 0x46, (byte) 0xD7, (byte) 0x74, |
| (byte) 0x4C, (byte) 0xCF, (byte) 0x58, (byte) 0xF9, (byte) 0xA1, (byte) 0x30, |
| (byte) 0x84, (byte) 0x52, (byte) 0xC9, (byte) 0x01, (byte) 0x5F, (byte) 0x24, |
| (byte) 0x4C, (byte) 0xB1, (byte) 0x9F, (byte) 0x7D, (byte) 0x12, (byte) 0x38, |
| (byte) 0x27, (byte) 0x0F, (byte) 0x5E, (byte) 0xFF, (byte) 0xE0, (byte) 0x55, |
| (byte) 0x8B, (byte) 0xA3, (byte) 0xAD, (byte) 0x60, (byte) 0x35, (byte) 0x83, |
| (byte) 0x58, (byte) 0xAF, (byte) 0x99, (byte) 0xDE, (byte) 0x3F, (byte) 0x5D, |
| (byte) 0x80, (byte) 0x80, (byte) 0xFF, (byte) 0x9B, (byte) 0xDE, (byte) 0x5C, |
| (byte) 0xAB, (byte) 0x97, (byte) 0x43, (byte) 0x64, (byte) 0xD9, (byte) 0x9F, |
| (byte) 0xFB, (byte) 0x67, (byte) 0x65, (byte) 0xA5, (byte) 0x99, (byte) 0xE7, |
| (byte) 0xE6, (byte) 0xEB, (byte) 0x05, (byte) 0x95, (byte) 0xFC, (byte) 0x46, |
| (byte) 0x28, (byte) 0x4B, (byte) 0xD8, (byte) 0x8C, (byte) 0xF5, (byte) 0x0A, |
| (byte) 0xEB, (byte) 0x1F, (byte) 0x30, (byte) 0xEA, (byte) 0xE7, (byte) 0x67, |
| (byte) 0x11, (byte) 0x25, (byte) 0xF0, (byte) 0x44, (byte) 0x75, (byte) 0x74, |
| (byte) 0x94, (byte) 0x06, (byte) 0x78, (byte) 0xD0, (byte) 0x21, (byte) 0xF4, |
| (byte) 0x3F, (byte) 0xC8, (byte) 0xC4, (byte) 0x4A, (byte) 0x57, (byte) 0xBE, |
| (byte) 0x02, (byte) 0x3C, (byte) 0x93, (byte) 0xF6, (byte) 0x95, (byte) 0xFB, |
| (byte) 0xD1, (byte) 0x77, (byte) 0x8B, (byte) 0x43, (byte) 0xF0, (byte) 0xB9, |
| (byte) 0x7D, (byte) 0xE0, (byte) 0x32, (byte) 0xE1, (byte) 0x72, (byte) 0xB5, |
| (byte) 0x62, (byte) 0x3F, (byte) 0x86, (byte) 0xC3, (byte) 0xD4, (byte) 0x5F, |
| (byte) 0x5E, (byte) 0x54, (byte) 0x1B, (byte) 0x5B, (byte) 0xE6, (byte) 0x74, |
| (byte) 0xA1, (byte) 0x0B, (byte) 0xE5, (byte) 0x18, (byte) 0xD2, (byte) 0x4F, |
| (byte) 0x93, (byte) 0xF3, (byte) 0x09, (byte) 0x58, (byte) 0xCE, (byte) 0xF0, |
| (byte) 0xA3, (byte) 0x61, (byte) 0xE4, (byte) 0x6E, (byte) 0x46, (byte) 0x45, |
| (byte) 0x89, (byte) 0x50, (byte) 0xBD, (byte) 0x03, (byte) 0x3F, (byte) 0x38, |
| (byte) 0xDA, (byte) 0x5D, (byte) 0xD0, (byte) 0x1B, (byte) 0x1F, (byte) 0xB1, |
| (byte) 0xEE, (byte) 0x89, (byte) 0x59, (byte) 0xC5, |
| }; |
| |
| private static final byte[] RSA_Vector1_ZeroPadded_Encrypted = new byte[] { |
| (byte) 0x60, (byte) 0x4a, (byte) 0x12, (byte) 0xa3, (byte) 0xa7, (byte) 0x4a, |
| (byte) 0xa4, (byte) 0xbf, (byte) 0x6c, (byte) 0x36, (byte) 0xad, (byte) 0x66, |
| (byte) 0xdf, (byte) 0xce, (byte) 0xf1, (byte) 0xe4, (byte) 0x0f, (byte) 0xd4, |
| (byte) 0x54, (byte) 0x5f, (byte) 0x03, (byte) 0x15, (byte) 0x4b, (byte) 0x9e, |
| (byte) 0xeb, (byte) 0xfe, (byte) 0x9e, (byte) 0x24, (byte) 0xce, (byte) 0x8e, |
| (byte) 0xc3, (byte) 0x36, (byte) 0xa5, (byte) 0x76, (byte) 0xf6, (byte) 0x54, |
| (byte) 0xb7, (byte) 0x84, (byte) 0x48, (byte) 0x2f, (byte) 0xd4, (byte) 0x45, |
| (byte) 0x74, (byte) 0x48, (byte) 0x5f, (byte) 0x08, (byte) 0x4e, (byte) 0x9c, |
| (byte) 0x89, (byte) 0xcc, (byte) 0x34, (byte) 0x40, (byte) 0xb1, (byte) 0x5f, |
| (byte) 0xa7, (byte) 0x0e, (byte) 0x11, (byte) 0x4b, (byte) 0xb5, (byte) 0x94, |
| (byte) 0xbe, (byte) 0x14, (byte) 0xaa, (byte) 0xaa, (byte) 0xe0, (byte) 0x38, |
| (byte) 0x1c, (byte) 0xce, (byte) 0x40, (byte) 0x61, (byte) 0xfc, (byte) 0x08, |
| (byte) 0xcb, (byte) 0x14, (byte) 0x2b, (byte) 0xa6, (byte) 0x54, (byte) 0xdf, |
| (byte) 0x05, (byte) 0x5c, (byte) 0x9b, (byte) 0x4f, (byte) 0x14, (byte) 0x93, |
| (byte) 0xb0, (byte) 0x70, (byte) 0xd9, (byte) 0x32, (byte) 0xdc, (byte) 0x24, |
| (byte) 0xe0, (byte) 0xae, (byte) 0x48, (byte) 0xfc, (byte) 0x53, (byte) 0xee, |
| (byte) 0x7c, (byte) 0x9f, (byte) 0x69, (byte) 0x34, (byte) 0xf4, (byte) 0x76, |
| (byte) 0xee, (byte) 0x67, (byte) 0xb2, (byte) 0xa7, (byte) 0x33, (byte) 0x1c, |
| (byte) 0x47, (byte) 0xff, (byte) 0x5c, (byte) 0xf0, (byte) 0xb8, (byte) 0x04, |
| (byte) 0x2c, (byte) 0xfd, (byte) 0xe2, (byte) 0xb1, (byte) 0x4a, (byte) 0x0a, |
| (byte) 0x69, (byte) 0x1c, (byte) 0x80, (byte) 0x2b, (byte) 0xb4, (byte) 0x50, |
| (byte) 0x65, (byte) 0x5c, (byte) 0x76, (byte) 0x78, (byte) 0x9a, (byte) 0x0c, |
| (byte) 0x05, (byte) 0x62, (byte) 0xf0, (byte) 0xc4, (byte) 0x1c, (byte) 0x38, |
| (byte) 0x15, (byte) 0xd0, (byte) 0xe2, (byte) 0x5a, (byte) 0x3d, (byte) 0xb6, |
| (byte) 0xe0, (byte) 0x88, (byte) 0x85, (byte) 0xd1, (byte) 0x4f, (byte) 0x7e, |
| (byte) 0xfc, (byte) 0x77, (byte) 0x0d, (byte) 0x2a, (byte) 0x45, (byte) 0xd5, |
| (byte) 0xf8, (byte) 0x3c, (byte) 0x7b, (byte) 0x2d, (byte) 0x1b, (byte) 0x82, |
| (byte) 0xfe, (byte) 0x58, (byte) 0x22, (byte) 0x47, (byte) 0x06, (byte) 0x58, |
| (byte) 0x8b, (byte) 0x4f, (byte) 0xfb, (byte) 0x9b, (byte) 0x1c, (byte) 0x70, |
| (byte) 0x36, (byte) 0x12, (byte) 0x04, (byte) 0x17, (byte) 0x47, (byte) 0x8a, |
| (byte) 0x0a, (byte) 0xec, (byte) 0x12, (byte) 0x3b, (byte) 0xf8, (byte) 0xd2, |
| (byte) 0xdc, (byte) 0x3c, (byte) 0xc8, (byte) 0x46, (byte) 0xc6, (byte) 0x51, |
| (byte) 0x06, (byte) 0x06, (byte) 0xcb, (byte) 0x84, (byte) 0x67, (byte) 0xb5, |
| (byte) 0x68, (byte) 0xd9, (byte) 0x9c, (byte) 0xd4, (byte) 0x16, (byte) 0x5c, |
| (byte) 0xb4, (byte) 0xe2, (byte) 0x55, (byte) 0xe6, (byte) 0x3a, (byte) 0x73, |
| (byte) 0x01, (byte) 0x1d, (byte) 0x6f, (byte) 0x30, (byte) 0x31, (byte) 0x59, |
| (byte) 0x8b, (byte) 0x2f, (byte) 0x4c, (byte) 0xe7, (byte) 0x86, (byte) 0x4c, |
| (byte) 0x39, (byte) 0x4e, (byte) 0x67, (byte) 0x3b, (byte) 0x22, (byte) 0x9b, |
| (byte) 0x85, (byte) 0x5a, (byte) 0xc3, (byte) 0x29, (byte) 0xaf, (byte) 0x8c, |
| (byte) 0x7c, (byte) 0x59, (byte) 0x4a, (byte) 0x24, (byte) 0xfa, (byte) 0xba, |
| (byte) 0x55, (byte) 0x40, (byte) 0x13, (byte) 0x64, (byte) 0xd8, (byte) 0xcb, |
| (byte) 0x4b, (byte) 0x98, (byte) 0x3f, (byte) 0xae, (byte) 0x20, (byte) 0xfd, |
| (byte) 0x8a, (byte) 0x50, (byte) 0x73, (byte) 0xe4, |
| }; |
| |
| public void testRSA_ECB_NoPadding_Private_OnlyDoFinal_Success() throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testRSA_ECB_NoPadding_Private_OnlyDoFinal_Success(provider); |
| } |
| } |
| |
| private void testRSA_ECB_NoPadding_Private_OnlyDoFinal_Success(String provider) throws Exception { |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus, |
| RSA_2048_privateExponent); |
| |
| final PrivateKey privKey = kf.generatePrivate(keySpec); |
| |
| Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| |
| /* |
| * You're actually decrypting with private keys, but there is no |
| * distinction made here. It's all keyed off of what kind of key you're |
| * using. ENCRYPT_MODE and DECRYPT_MODE are the same. |
| */ |
| c.init(Cipher.ENCRYPT_MODE, privKey); |
| byte[] encrypted = c.doFinal(RSA_2048_Vector1); |
| assertTrue("Encrypted should match expected", |
| Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted)); |
| |
| c.init(Cipher.DECRYPT_MODE, privKey); |
| encrypted = c.doFinal(RSA_2048_Vector1); |
| assertTrue("Encrypted should match expected", |
| Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted)); |
| } |
| |
| public void testRSA_ECB_NoPadding_Private_UpdateThenEmptyDoFinal_Success() throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testRSA_ECB_NoPadding_Private_UpdateThenEmptyDoFinal_Success(provider); |
| } |
| } |
| |
| private void testRSA_ECB_NoPadding_Private_UpdateThenEmptyDoFinal_Success(String provider) throws Exception { |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus, |
| RSA_2048_privateExponent); |
| |
| final PrivateKey privKey = kf.generatePrivate(keySpec); |
| |
| Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| |
| /* |
| * You're actually decrypting with private keys, but there is no |
| * distinction made here. It's all keyed off of what kind of key you're |
| * using. ENCRYPT_MODE and DECRYPT_MODE are the same. |
| */ |
| c.init(Cipher.ENCRYPT_MODE, privKey); |
| c.update(RSA_2048_Vector1); |
| byte[] encrypted = c.doFinal(); |
| assertTrue("Encrypted should match expected", |
| Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted)); |
| |
| c.init(Cipher.DECRYPT_MODE, privKey); |
| c.update(RSA_2048_Vector1); |
| encrypted = c.doFinal(); |
| assertTrue("Encrypted should match expected", |
| Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted)); |
| } |
| |
| public void testRSA_ECB_NoPadding_Private_SingleByteUpdateThenEmptyDoFinal_Success() |
| throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testRSA_ECB_NoPadding_Private_SingleByteUpdateThenEmptyDoFinal_Success(provider); |
| } |
| } |
| |
| private void testRSA_ECB_NoPadding_Private_SingleByteUpdateThenEmptyDoFinal_Success(String provider) |
| throws Exception { |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus, |
| RSA_2048_privateExponent); |
| |
| final PrivateKey privKey = kf.generatePrivate(keySpec); |
| |
| Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| |
| /* |
| * You're actually decrypting with private keys, but there is no |
| * distinction made here. It's all keyed off of what kind of key you're |
| * using. ENCRYPT_MODE and DECRYPT_MODE are the same. |
| */ |
| c.init(Cipher.ENCRYPT_MODE, privKey); |
| int i; |
| for (i = 0; i < RSA_2048_Vector1.length / 2; i++) { |
| c.update(RSA_2048_Vector1, i, 1); |
| } |
| byte[] encrypted = c.doFinal(RSA_2048_Vector1, i, RSA_2048_Vector1.length - i); |
| assertTrue("Encrypted should match expected", |
| Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted)); |
| |
| c.init(Cipher.DECRYPT_MODE, privKey); |
| for (i = 0; i < RSA_2048_Vector1.length / 2; i++) { |
| c.update(RSA_2048_Vector1, i, 1); |
| } |
| encrypted = c.doFinal(RSA_2048_Vector1, i, RSA_2048_Vector1.length - i); |
| assertTrue("Encrypted should match expected", |
| Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted)); |
| } |
| |
| public void testRSA_ECB_NoPadding_Private_OnlyDoFinalWithOffset_Success() throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testRSA_ECB_NoPadding_Private_OnlyDoFinalWithOffset_Success(provider); |
| } |
| } |
| |
| private void testRSA_ECB_NoPadding_Private_OnlyDoFinalWithOffset_Success(String provider) throws Exception { |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus, |
| RSA_2048_privateExponent); |
| final PrivateKey privKey = kf.generatePrivate(keySpec); |
| |
| Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| |
| /* |
| * You're actually decrypting with private keys, but there is no |
| * distinction made here. It's all keyed off of what kind of key you're |
| * using. ENCRYPT_MODE and DECRYPT_MODE are the same. |
| */ |
| c.init(Cipher.ENCRYPT_MODE, privKey); |
| byte[] encrypted = new byte[RSA_Vector1_Encrypt_Private.length]; |
| final int encryptLen = c |
| .doFinal(RSA_2048_Vector1, 0, RSA_2048_Vector1.length, encrypted, 0); |
| assertEquals("Encrypted size should match expected", RSA_Vector1_Encrypt_Private.length, |
| encryptLen); |
| assertTrue("Encrypted should match expected", |
| Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted)); |
| |
| c.init(Cipher.DECRYPT_MODE, privKey); |
| final int decryptLen = c |
| .doFinal(RSA_2048_Vector1, 0, RSA_2048_Vector1.length, encrypted, 0); |
| assertEquals("Encrypted size should match expected", RSA_Vector1_Encrypt_Private.length, |
| decryptLen); |
| assertTrue("Encrypted should match expected", |
| Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted)); |
| } |
| |
| public void testRSA_ECB_NoPadding_Public_OnlyDoFinal_Success() throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testRSA_ECB_NoPadding_Public_OnlyDoFinal_Success(provider); |
| } |
| } |
| |
| private void testRSA_ECB_NoPadding_Public_OnlyDoFinal_Success(String provider) throws Exception { |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent); |
| |
| final PublicKey privKey = kf.generatePublic(keySpec); |
| |
| Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| |
| /* |
| * You're actually encrypting with public keys, but there is no |
| * distinction made here. It's all keyed off of what kind of key you're |
| * using. ENCRYPT_MODE and DECRYPT_MODE are the same. |
| */ |
| c.init(Cipher.ENCRYPT_MODE, privKey); |
| byte[] encrypted = c.doFinal(RSA_Vector1_Encrypt_Private); |
| assertEncryptedEqualsNoPadding(provider, Cipher.ENCRYPT_MODE, RSA_2048_Vector1, encrypted); |
| |
| c.init(Cipher.DECRYPT_MODE, privKey); |
| encrypted = c.doFinal(RSA_Vector1_Encrypt_Private); |
| assertEncryptedEqualsNoPadding(provider, Cipher.DECRYPT_MODE, RSA_2048_Vector1, encrypted); |
| } |
| |
| public void testRSA_ECB_NoPadding_Public_OnlyDoFinalWithOffset_Success() throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testRSA_ECB_NoPadding_Public_OnlyDoFinalWithOffset_Success(provider); |
| } |
| } |
| |
| private void testRSA_ECB_NoPadding_Public_OnlyDoFinalWithOffset_Success(String provider) throws Exception { |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent); |
| |
| final PublicKey pubKey = kf.generatePublic(keySpec); |
| |
| Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| |
| /* |
| * You're actually encrypting with public keys, but there is no |
| * distinction made here. It's all keyed off of what kind of key you're |
| * using. ENCRYPT_MODE and DECRYPT_MODE are the same. |
| */ |
| c.init(Cipher.ENCRYPT_MODE, pubKey); |
| byte[] encrypted = new byte[RSA_2048_Vector1.length]; |
| final int encryptLen = c.doFinal(RSA_Vector1_Encrypt_Private, 0, |
| RSA_Vector1_Encrypt_Private.length, encrypted, 0); |
| assertEquals("Encrypted size should match expected", RSA_2048_Vector1.length, encryptLen); |
| assertEncryptedEqualsNoPadding(provider, Cipher.ENCRYPT_MODE, RSA_2048_Vector1, encrypted); |
| |
| c.init(Cipher.DECRYPT_MODE, pubKey); |
| int decryptLen = c.doFinal(RSA_Vector1_Encrypt_Private, 0, |
| RSA_Vector1_Encrypt_Private.length, encrypted, 0); |
| if (provider.equals("BC")) { |
| // BC strips the leading 0 for us on decrypt even when NoPadding is specified... |
| decryptLen++; |
| encrypted = Arrays.copyOf(encrypted, encrypted.length - 1); |
| } |
| assertEquals("Encrypted size should match expected", RSA_2048_Vector1.length, decryptLen); |
| assertEncryptedEqualsNoPadding(provider, Cipher.DECRYPT_MODE, RSA_2048_Vector1, encrypted); |
| } |
| |
| public void testRSA_ECB_NoPadding_Public_UpdateThenEmptyDoFinal_Success() throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testRSA_ECB_NoPadding_Public_UpdateThenEmptyDoFinal_Success(provider); |
| } |
| } |
| |
| private void testRSA_ECB_NoPadding_Public_UpdateThenEmptyDoFinal_Success(String provider) throws Exception { |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent); |
| |
| final PublicKey privKey = kf.generatePublic(keySpec); |
| |
| Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| |
| /* |
| * You're actually encrypting with public keys, but there is no |
| * distinction made here. It's all keyed off of what kind of key you're |
| * using. ENCRYPT_MODE and DECRYPT_MODE are the same. |
| */ |
| c.init(Cipher.ENCRYPT_MODE, privKey); |
| c.update(RSA_Vector1_Encrypt_Private); |
| byte[] encrypted = c.doFinal(); |
| assertEncryptedEqualsNoPadding(provider, Cipher.ENCRYPT_MODE, RSA_2048_Vector1, encrypted); |
| |
| c.init(Cipher.DECRYPT_MODE, privKey); |
| c.update(RSA_Vector1_Encrypt_Private); |
| encrypted = c.doFinal(); |
| assertEncryptedEqualsNoPadding(provider, Cipher.DECRYPT_MODE, RSA_2048_Vector1, encrypted); |
| } |
| |
| public void testRSA_ECB_NoPadding_Public_SingleByteUpdateThenEmptyDoFinal_Success() |
| throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testRSA_ECB_NoPadding_Public_SingleByteUpdateThenEmptyDoFinal_Success(provider); |
| } |
| } |
| |
| private void testRSA_ECB_NoPadding_Public_SingleByteUpdateThenEmptyDoFinal_Success(String provider) |
| throws Exception { |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent); |
| |
| final PublicKey privKey = kf.generatePublic(keySpec); |
| |
| Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| |
| /* |
| * You're actually encrypting with public keys, but there is no |
| * distinction made here. It's all keyed off of what kind of key you're |
| * using. ENCRYPT_MODE and DECRYPT_MODE are the same. |
| */ |
| c.init(Cipher.ENCRYPT_MODE, privKey); |
| int i; |
| for (i = 0; i < RSA_Vector1_Encrypt_Private.length / 2; i++) { |
| c.update(RSA_Vector1_Encrypt_Private, i, 1); |
| } |
| byte[] encrypted = c.doFinal(RSA_Vector1_Encrypt_Private, i, RSA_2048_Vector1.length - i); |
| assertEncryptedEqualsNoPadding(provider, Cipher.ENCRYPT_MODE, RSA_2048_Vector1, encrypted); |
| |
| c.init(Cipher.DECRYPT_MODE, privKey); |
| for (i = 0; i < RSA_Vector1_Encrypt_Private.length / 2; i++) { |
| c.update(RSA_Vector1_Encrypt_Private, i, 1); |
| } |
| encrypted = c.doFinal(RSA_Vector1_Encrypt_Private, i, RSA_2048_Vector1.length - i); |
| assertEncryptedEqualsNoPadding(provider, Cipher.DECRYPT_MODE, RSA_2048_Vector1, encrypted); |
| } |
| |
| public void testRSA_ECB_NoPadding_Public_TooSmall_Success() throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testRSA_ECB_NoPadding_Public_TooSmall_Success(provider); |
| } |
| } |
| |
| private void testRSA_ECB_NoPadding_Public_TooSmall_Success(String provider) throws Exception { |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent); |
| |
| final PublicKey privKey = kf.generatePublic(keySpec); |
| |
| Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| |
| /* |
| * You're actually encrypting with public keys, but there is no |
| * distinction made here. It's all keyed off of what kind of key you're |
| * using. ENCRYPT_MODE and DECRYPT_MODE are the same. |
| */ |
| c.init(Cipher.ENCRYPT_MODE, privKey); |
| byte[] encrypted = c.doFinal(TooShort_Vector); |
| assertTrue("Encrypted should match expected", |
| Arrays.equals(RSA_Vector1_ZeroPadded_Encrypted, encrypted)); |
| |
| c.init(Cipher.DECRYPT_MODE, privKey); |
| encrypted = c.doFinal(TooShort_Vector); |
| assertTrue("Encrypted should match expected", |
| Arrays.equals(RSA_Vector1_ZeroPadded_Encrypted, encrypted)); |
| } |
| |
| public void testRSA_ECB_NoPadding_Private_TooSmall_Success() throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testRSA_ECB_NoPadding_Private_TooSmall_Success(provider); |
| } |
| } |
| |
| private void testRSA_ECB_NoPadding_Private_TooSmall_Success(String provider) throws Exception { |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus, |
| RSA_2048_privateExponent); |
| |
| final PrivateKey privKey = kf.generatePrivate(keySpec); |
| |
| Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| |
| /* |
| * You're actually encrypting with public keys, but there is no |
| * distinction made here. It's all keyed off of what kind of key you're |
| * using. ENCRYPT_MODE and DECRYPT_MODE are the same. |
| */ |
| c.init(Cipher.ENCRYPT_MODE, privKey); |
| byte[] encrypted = c.doFinal(RSA_Vector1_ZeroPadded_Encrypted); |
| assertEncryptedEqualsNoPadding(provider, Cipher.ENCRYPT_MODE, |
| TooShort_Vector_Zero_Padded, encrypted); |
| |
| c.init(Cipher.DECRYPT_MODE, privKey); |
| encrypted = c.doFinal(RSA_Vector1_ZeroPadded_Encrypted); |
| assertEncryptedEqualsNoPadding(provider, Cipher.DECRYPT_MODE, |
| TooShort_Vector_Zero_Padded, encrypted); |
| } |
| |
| private static void assertEncryptedEqualsNoPadding(String provider, int mode, |
| byte[] expected, byte[] actual) { |
| if (provider.equals("BC") && mode == Cipher.DECRYPT_MODE) { |
| // BouncyCastle does us the favor of stripping leading zeroes in DECRYPT_MODE |
| int nonZeroOffset = 0; |
| for (byte b : expected) { |
| if (b != 0) { |
| break; |
| } |
| nonZeroOffset++; |
| } |
| expected = Arrays.copyOfRange(expected, nonZeroOffset, expected.length); |
| } |
| assertEquals("Encrypted should match expected", |
| Arrays.toString(expected), Arrays.toString(actual)); |
| } |
| |
| public void testRSA_ECB_NoPadding_Private_CombinedUpdateAndDoFinal_TooBig_Failure() |
| throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testRSA_ECB_NoPadding_Private_CombinedUpdateAndDoFinal_TooBig_Failure(provider); |
| } |
| } |
| |
| private void testRSA_ECB_NoPadding_Private_CombinedUpdateAndDoFinal_TooBig_Failure(String provider) |
| throws Exception { |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus, |
| RSA_2048_privateExponent); |
| |
| final PrivateKey privKey = kf.generatePrivate(keySpec); |
| |
| Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| |
| /* |
| * You're actually encrypting with public keys, but there is no |
| * distinction made here. It's all keyed off of what kind of key you're |
| * using. ENCRYPT_MODE and DECRYPT_MODE are the same. |
| */ |
| c.init(Cipher.ENCRYPT_MODE, privKey); |
| c.update(RSA_Vector1_ZeroPadded_Encrypted); |
| |
| try { |
| c.doFinal(RSA_Vector1_ZeroPadded_Encrypted); |
| fail("Should have error when block size is too big."); |
| } catch (IllegalBlockSizeException success) { |
| assertFalse(provider, "BC".equals(provider)); |
| } catch (ArrayIndexOutOfBoundsException success) { |
| assertEquals("BC", provider); |
| } |
| } |
| |
| public void testRSA_ECB_NoPadding_Private_UpdateInAndOutPlusDoFinal_TooBig_Failure() |
| throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testRSA_ECB_NoPadding_Private_UpdateInAndOutPlusDoFinal_TooBig_Failure(provider); |
| } |
| } |
| |
| private void testRSA_ECB_NoPadding_Private_UpdateInAndOutPlusDoFinal_TooBig_Failure(String provider) |
| throws Exception { |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus, |
| RSA_2048_privateExponent); |
| |
| final PrivateKey privKey = kf.generatePrivate(keySpec); |
| |
| Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| |
| /* |
| * You're actually encrypting with public keys, but there is no |
| * distinction made here. It's all keyed off of what kind of key you're |
| * using. ENCRYPT_MODE and DECRYPT_MODE are the same. |
| */ |
| c.init(Cipher.ENCRYPT_MODE, privKey); |
| |
| byte[] output = new byte[RSA_2048_Vector1.length]; |
| c.update(RSA_Vector1_ZeroPadded_Encrypted, 0, RSA_Vector1_ZeroPadded_Encrypted.length, |
| output); |
| |
| try { |
| c.doFinal(RSA_Vector1_ZeroPadded_Encrypted); |
| fail("Should have error when block size is too big."); |
| } catch (IllegalBlockSizeException success) { |
| assertFalse(provider, "BC".equals(provider)); |
| } catch (ArrayIndexOutOfBoundsException success) { |
| assertEquals("BC", provider); |
| } |
| } |
| |
| public void testRSA_ECB_NoPadding_Private_OnlyDoFinal_TooBig_Failure() throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testRSA_ECB_NoPadding_Private_OnlyDoFinal_TooBig_Failure(provider); |
| } |
| } |
| |
| private void testRSA_ECB_NoPadding_Private_OnlyDoFinal_TooBig_Failure(String provider) throws Exception { |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus, |
| RSA_2048_privateExponent); |
| |
| final PrivateKey privKey = kf.generatePrivate(keySpec); |
| |
| Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| |
| /* |
| * You're actually encrypting with public keys, but there is no |
| * distinction made here. It's all keyed off of what kind of key you're |
| * using. ENCRYPT_MODE and DECRYPT_MODE are the same. |
| */ |
| c.init(Cipher.ENCRYPT_MODE, privKey); |
| |
| byte[] tooBig_Vector = new byte[RSA_Vector1_ZeroPadded_Encrypted.length * 2]; |
| System.arraycopy(RSA_Vector1_ZeroPadded_Encrypted, 0, tooBig_Vector, 0, |
| RSA_Vector1_ZeroPadded_Encrypted.length); |
| System.arraycopy(RSA_Vector1_ZeroPadded_Encrypted, 0, tooBig_Vector, |
| RSA_Vector1_ZeroPadded_Encrypted.length, RSA_Vector1_ZeroPadded_Encrypted.length); |
| |
| try { |
| c.doFinal(tooBig_Vector); |
| fail("Should have error when block size is too big."); |
| } catch (IllegalBlockSizeException success) { |
| assertFalse(provider, "BC".equals(provider)); |
| } catch (ArrayIndexOutOfBoundsException success) { |
| assertEquals("BC", provider); |
| } |
| } |
| |
| public void testRSA_ECB_NoPadding_GetBlockSize_Success() throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testRSA_ECB_NoPadding_GetBlockSize_Success(provider); |
| } |
| } |
| |
| private void testRSA_ECB_NoPadding_GetBlockSize_Success(String provider) throws Exception { |
| Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| if (StandardNames.IS_RI) { |
| assertEquals(0, c.getBlockSize()); |
| } else { |
| try { |
| c.getBlockSize(); |
| fail(); |
| } catch (IllegalStateException expected) { |
| } |
| } |
| |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus, |
| RSA_2048_publicExponent); |
| final PublicKey pubKey = kf.generatePublic(pubKeySpec); |
| c.init(Cipher.ENCRYPT_MODE, pubKey); |
| assertEquals(getExpectedBlockSize("RSA", Cipher.ENCRYPT_MODE, provider), c.getBlockSize()); |
| } |
| |
| public void testRSA_ECB_NoPadding_GetOutputSize_NoInit_Failure() throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testRSA_ECB_NoPadding_GetOutputSize_NoInit_Failure(provider); |
| } |
| } |
| |
| private void testRSA_ECB_NoPadding_GetOutputSize_NoInit_Failure(String provider) throws Exception { |
| Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| try { |
| c.getOutputSize(RSA_2048_Vector1.length); |
| fail("Should throw IllegalStateException if getOutputSize is called before init"); |
| } catch (IllegalStateException success) { |
| } |
| } |
| |
| public void testRSA_ECB_NoPadding_GetOutputSize_Success() throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testRSA_ECB_NoPadding_GetOutputSize_Success(provider); |
| } |
| } |
| |
| private void testRSA_ECB_NoPadding_GetOutputSize_Success(String provider) throws Exception { |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus, |
| RSA_2048_publicExponent); |
| final PublicKey pubKey = kf.generatePublic(pubKeySpec); |
| |
| Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| c.init(Cipher.ENCRYPT_MODE, pubKey); |
| |
| final int modulusInBytes = RSA_2048_modulus.bitLength() / 8; |
| assertEquals(modulusInBytes, c.getOutputSize(RSA_2048_Vector1.length)); |
| assertEquals(modulusInBytes, c.getOutputSize(RSA_2048_Vector1.length * 2)); |
| assertEquals(modulusInBytes, c.getOutputSize(0)); |
| } |
| |
| public void testRSA_ECB_NoPadding_GetIV_Success() throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testRSA_ECB_NoPadding_GetIV_Success(provider); |
| } |
| } |
| |
| private void testRSA_ECB_NoPadding_GetIV_Success(String provider) throws Exception { |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus, |
| RSA_2048_publicExponent); |
| final PublicKey pubKey = kf.generatePublic(pubKeySpec); |
| |
| Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| assertNull("ECB mode has no IV and should be null", c.getIV()); |
| |
| c.init(Cipher.ENCRYPT_MODE, pubKey); |
| |
| assertNull("ECB mode has no IV and should be null", c.getIV()); |
| } |
| |
| public void testRSA_ECB_NoPadding_GetParameters_NoneProvided_Success() throws Exception { |
| for (String provider : RSA_PROVIDERS) { |
| testRSA_ECB_NoPadding_GetParameters_NoneProvided_Success(provider); |
| } |
| } |
| |
| private void testRSA_ECB_NoPadding_GetParameters_NoneProvided_Success(String provider) throws Exception { |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus, |
| RSA_2048_publicExponent); |
| final PublicKey pubKey = kf.generatePublic(pubKeySpec); |
| |
| Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); |
| assertNull("Parameters should be null", c.getParameters()); |
| } |
| |
| /* |
| * Test vector generation: |
| * openssl rand -hex 16 |
| * echo '3d4f8970b1f27537f40a39298a41555f' | sed 's/\(..\)/(byte) 0x\1, /g' |
| */ |
| private static final byte[] AES_128_KEY = new byte[] { |
| (byte) 0x3d, (byte) 0x4f, (byte) 0x89, (byte) 0x70, (byte) 0xb1, (byte) 0xf2, |
| (byte) 0x75, (byte) 0x37, (byte) 0xf4, (byte) 0x0a, (byte) 0x39, (byte) 0x29, |
| (byte) 0x8a, (byte) 0x41, (byte) 0x55, (byte) 0x5f, |
| }; |
| |
| /* |
| * Test key generation: |
| * openssl rand -hex 24 |
| * echo '5a7a3d7e40b64ed996f7afa15f97fd595e27db6af428e342' | sed 's/\(..\)/(byte) 0x\1, /g' |
| */ |
| private static final byte[] AES_192_KEY = new byte[] { |
| (byte) 0x5a, (byte) 0x7a, (byte) 0x3d, (byte) 0x7e, (byte) 0x40, (byte) 0xb6, |
| (byte) 0x4e, (byte) 0xd9, (byte) 0x96, (byte) 0xf7, (byte) 0xaf, (byte) 0xa1, |
| (byte) 0x5f, (byte) 0x97, (byte) 0xfd, (byte) 0x59, (byte) 0x5e, (byte) 0x27, |
| (byte) 0xdb, (byte) 0x6a, (byte) 0xf4, (byte) 0x28, (byte) 0xe3, (byte) 0x42, |
| }; |
| |
| /* |
| * Test key generation: |
| * openssl rand -hex 32 |
| * echo 'ec53c6d51d2c4973585fb0b8e51cd2e39915ff07a1837872715d6121bf861935' | sed 's/\(..\)/(byte) 0x\1, /g' |
| */ |
| private static final byte[] AES_256_KEY = new byte[] { |
| (byte) 0xec, (byte) 0x53, (byte) 0xc6, (byte) 0xd5, (byte) 0x1d, (byte) 0x2c, |
| (byte) 0x49, (byte) 0x73, (byte) 0x58, (byte) 0x5f, (byte) 0xb0, (byte) 0xb8, |
| (byte) 0xe5, (byte) 0x1c, (byte) 0xd2, (byte) 0xe3, (byte) 0x99, (byte) 0x15, |
| (byte) 0xff, (byte) 0x07, (byte) 0xa1, (byte) 0x83, (byte) 0x78, (byte) 0x72, |
| (byte) 0x71, (byte) 0x5d, (byte) 0x61, (byte) 0x21, (byte) 0xbf, (byte) 0x86, |
| (byte) 0x19, (byte) 0x35, |
| }; |
| |
| private static final String[] AES_MODES = new String[] { |
| "AES/ECB", |
| "AES/CBC", |
| "AES/CFB", |
| "AES/CTR", |
| "AES/OFB", |
| }; |
| |
| /* |
| * Test vector creation: |
| * echo -n 'Hello, world!' | recode ../x1 | sed 's/0x/(byte) 0x/g' |
| */ |
| private static final byte[] AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext = new byte[] { |
| (byte) 0x48, (byte) 0x65, (byte) 0x6C, (byte) 0x6C, (byte) 0x6F, (byte) 0x2C, |
| (byte) 0x20, (byte) 0x77, (byte) 0x6F, (byte) 0x72, (byte) 0x6C, (byte) 0x64, |
| (byte) 0x21, |
| }; |
| |
| /* |
| * Test vector creation: |
| * openssl enc -aes-128-ecb -K 3d4f8970b1f27537f40a39298a41555f -in blah|openssl enc -aes-128-ecb -K 3d4f8970b1f27537f40a39298a41555f -nopad -d|recode ../x1 | sed 's/0x/(byte) 0x/g' |
| */ |
| private static final byte[] AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded = new byte[] { |
| (byte) 0x48, (byte) 0x65, (byte) 0x6C, (byte) 0x6C, (byte) 0x6F, (byte) 0x2C, |
| (byte) 0x20, (byte) 0x77, (byte) 0x6F, (byte) 0x72, (byte) 0x6C, (byte) 0x64, |
| (byte) 0x21, (byte) 0x03, (byte) 0x03, (byte) 0x03 |
| }; |
| |
| /* |
| * Test vector generation: |
| * openssl enc -aes-128-ecb -K 3d4f8970b1f27537f40a39298a41555f -in blah|recode ../x1 | sed 's/0x/(byte) 0x/g' |
| */ |
| private static final byte[] AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted = new byte[] { |
| (byte) 0x65, (byte) 0x3E, (byte) 0x86, (byte) 0xFB, (byte) 0x05, (byte) 0x5A, |
| (byte) 0x52, (byte) 0xEA, (byte) 0xDD, (byte) 0x08, (byte) 0xE7, (byte) 0x48, |
| (byte) 0x33, (byte) 0x01, (byte) 0xFC, (byte) 0x5A, |
| }; |
| |
| /* |
| * Taken from BoringSSL test vectors. |
| */ |
| private static final byte[] AES_128_GCM_TestVector_1_Key = new byte[] { |
| (byte) 0xca, (byte) 0xbd, (byte) 0xcf, (byte) 0x54, (byte) 0x1a, (byte) 0xeb, |
| (byte) 0xf9, (byte) 0x17, (byte) 0xba, (byte) 0xc0, (byte) 0x19, (byte) 0xf1, |
| (byte) 0x39, (byte) 0x25, (byte) 0xd2, (byte) 0x67, |
| }; |
| |
| /* |
| * Taken from BoringSSL test vectors. |
| */ |
| private static final byte[] AES_128_GCM_TestVector_1_IV = new byte[] { |
| (byte) 0x2c, (byte) 0x34, (byte) 0xc0, (byte) 0x0c, (byte) 0x42, (byte) 0xda, |
| (byte) 0xe3, (byte) 0x82, (byte) 0x27, (byte) 0x9d, (byte) 0x79, (byte) 0x74, |
| }; |
| |
| /* |
| * Taken from BoringSSL test vectors. |
| */ |
| private static final byte[] AES_128_GCM_TestVector_1_AAD = new byte[] { |
| (byte) 0xdd, (byte) 0x10, (byte) 0xe3, (byte) 0x71, (byte) 0xb2, (byte) 0x2e, |
| (byte) 0x15, (byte) 0x67, (byte) 0x1c, (byte) 0x31, (byte) 0xaf, (byte) 0xee, |
| (byte) 0x55, (byte) 0x2b, (byte) 0xf1, (byte) 0xde, (byte) 0xa0, (byte) 0x7c, |
| (byte) 0xbb, (byte) 0xf6, (byte) 0x85, (byte) 0xe2, (byte) 0xca, (byte) 0xa0, |
| (byte) 0xe0, (byte) 0x36, (byte) 0x37, (byte) 0x16, (byte) 0xa2, (byte) 0x76, |
| (byte) 0xe1, (byte) 0x20, (byte) 0xc6, (byte) 0xc0, (byte) 0xeb, (byte) 0x4a, |
| (byte) 0xcb, (byte) 0x1a, (byte) 0x4d, (byte) 0x1b, (byte) 0xa7, (byte) 0x3f, |
| (byte) 0xde, (byte) 0x66, (byte) 0x15, (byte) 0xf7, (byte) 0x08, (byte) 0xaa, |
| (byte) 0xa4, (byte) 0x6b, (byte) 0xc7, (byte) 0x6c, (byte) 0x7f, (byte) 0xf3, |
| (byte) 0x45, (byte) 0xa4, (byte) 0xf7, (byte) 0x6b, (byte) 0xda, (byte) 0x11, |
| (byte) 0x7f, (byte) 0xe5, (byte) 0x6f, (byte) 0x0d, (byte) 0xc9, (byte) 0xb9, |
| (byte) 0x39, (byte) 0x04, (byte) 0x0d, (byte) 0xdd, |
| }; |
| |
| /* |
| * Taken from BoringSSL test vectors. |
| */ |
| private static final byte[] AES_128_GCM_TestVector_1_Plaintext = new byte[] { |
| (byte) 0x88, (byte) 0xcc, (byte) 0x1e, (byte) 0x07, (byte) 0xdf, (byte) 0xde, |
| (byte) 0x8e, (byte) 0x08, (byte) 0x08, (byte) 0x2e, (byte) 0x67, (byte) 0x66, |
| (byte) 0xe0, (byte) 0xa8, (byte) 0x81, (byte) 0x03, (byte) 0x38, (byte) 0x47, |
| (byte) 0x42, (byte) 0xaf, (byte) 0x37, (byte) 0x8d, (byte) 0x7b, (byte) 0x6b, |
| (byte) 0x8a, (byte) 0x87, (byte) 0xfc, (byte) 0xe0, (byte) 0x36, (byte) 0xaf, |
| (byte) 0x74, (byte) 0x41, (byte) 0xc1, (byte) 0x39, (byte) 0x61, (byte) 0xc2, |
| (byte) 0x5a, (byte) 0xfe, (byte) 0xa7, (byte) 0xf6, (byte) 0xe5, (byte) 0x61, |
| (byte) 0x93, (byte) 0xf5, (byte) 0x4b, (byte) 0xee, (byte) 0x00, (byte) 0x11, |
| (byte) 0xcb, (byte) 0x78, (byte) 0x64, (byte) 0x2c, (byte) 0x3a, (byte) 0xb9, |
| (byte) 0xe6, (byte) 0xd5, (byte) 0xb2, (byte) 0xe3, (byte) 0x58, (byte) 0x33, |
| (byte) 0xec, (byte) 0x16, (byte) 0xcd, (byte) 0x35, (byte) 0x55, (byte) 0x15, |
| (byte) 0xaf, (byte) 0x1a, (byte) 0x19, (byte) 0x0f, |
| }; |
| |
| /* |
| * Taken from BoringSSL test vectors. |
| */ |
| private static final byte[] AES_128_GCM_TestVector_1_Encrypted = new byte[] { |
| (byte) 0x04, (byte) 0x94, (byte) 0x53, (byte) 0xba, (byte) 0xf1, (byte) 0x57, |
| (byte) 0x87, (byte) 0x87, (byte) 0xd6, (byte) 0x8e, (byte) 0xd5, (byte) 0x47, |
| (byte) 0x87, (byte) 0x26, (byte) 0xc0, (byte) 0xb8, (byte) 0xa6, (byte) 0x36, |
| (byte) 0x33, (byte) 0x7a, (byte) 0x0b, (byte) 0x8a, (byte) 0x82, (byte) 0xb8, |
| (byte) 0x68, (byte) 0x36, (byte) 0xf9, (byte) 0x1c, (byte) 0xde, (byte) 0x25, |
| (byte) 0xe6, (byte) 0xe4, (byte) 0x4c, (byte) 0x34, (byte) 0x59, (byte) 0x40, |
| (byte) 0xe8, (byte) 0x19, (byte) 0xa0, (byte) 0xc5, (byte) 0x05, (byte) 0x75, |
| (byte) 0x1e, (byte) 0x60, (byte) 0x3c, (byte) 0xb8, (byte) 0xf8, (byte) 0xc4, |
| (byte) 0xfe, (byte) 0x98, (byte) 0x71, (byte) 0x91, (byte) 0x85, (byte) 0x56, |
| (byte) 0x27, (byte) 0x94, (byte) 0xa1, (byte) 0x85, (byte) 0xe5, (byte) 0xde, |
| (byte) 0xc4, (byte) 0x15, (byte) 0xc8, (byte) 0x1f, (byte) 0x2f, (byte) 0x16, |
| (byte) 0x2c, (byte) 0xdc, (byte) 0xd6, (byte) 0x50, (byte) 0xdc, (byte) 0xe7, |
| (byte) 0x19, (byte) 0x87, (byte) 0x28, (byte) 0xbf, (byte) 0xc1, (byte) 0xb5, |
| (byte) 0xf9, (byte) 0x49, (byte) 0xb9, (byte) 0xb5, (byte) 0x37, (byte) 0x41, |
| (byte) 0x99, (byte) 0xc6, |
| }; |
| |
| /* |
| * Test key generation: |
| * openssl rand -hex 16 |
| * echo '787bdeecf05556eac5d3d865e435f6d9' | sed 's/\(..\)/(byte) 0x\1, /g' |
| */ |
| private static final byte[] AES_192_CTR_NoPadding_TestVector_1_IV = new byte[] { |
| (byte) 0x78, (byte) 0x7b, (byte) 0xde, (byte) 0xec, (byte) 0xf0, (byte) 0x55, |
| (byte) 0x56, (byte) 0xea, (byte) 0xc5, (byte) 0xd3, (byte) 0xd8, (byte) 0x65, |
| (byte) 0xe4, (byte) 0x35, (byte) 0xf6, (byte) 0xd9, |
| |
| }; |
| |
| /* |
| * Test vector generation: |
| * echo -n 'AES-192 is a silly option' | recode ../x1 | sed 's/0x/(byte) 0x/g' |
| */ |
| private static final byte[] AES_192_CTR_NoPadding_TestVector_1_Plaintext = new byte[] { |
| (byte) 0x41, (byte) 0x45, (byte) 0x53, (byte) 0x2D, (byte) 0x31, (byte) 0x39, |
| (byte) 0x32, (byte) 0x20, (byte) 0x69, (byte) 0x73, (byte) 0x20, (byte) 0x61, |
| (byte) 0x20, (byte) 0x73, (byte) 0x69, (byte) 0x6C, (byte) 0x6C, (byte) 0x79, |
| (byte) 0x20, (byte) 0x6F, (byte) 0x70, (byte) 0x74, (byte) 0x69, (byte) 0x6F, |
| (byte) 0x6E |
| }; |
| |
| /* |
| * Test vector generation: |
| * echo -n 'AES-192 is a silly option' | openssl enc -aes-192-ctr -K 5a7a3d7e40b64ed996f7afa15f97fd595e27db6af428e342 -iv 787bdeecf05556eac5d3d865e435f6d9 | recode ../x1 | sed 's/0x/(byte) 0x/g' |
| */ |
| private static final byte[] AES_192_CTR_NoPadding_TestVector_1_Ciphertext = new byte[] { |
| (byte) 0xE9, (byte) 0xC6, (byte) 0xA0, (byte) 0x40, (byte) 0xC2, (byte) 0x6A, |
| (byte) 0xB5, (byte) 0x20, (byte) 0xFE, (byte) 0x9E, (byte) 0x65, (byte) 0xB7, |
| (byte) 0x7C, (byte) 0x5E, (byte) 0xFE, (byte) 0x1F, (byte) 0xF1, (byte) 0x6F, |
| (byte) 0x20, (byte) 0xAC, (byte) 0x37, (byte) 0xE9, (byte) 0x75, (byte) 0xE3, |
| (byte) 0x52 |
| }; |
| |
| /* |
| * Test key generation: openssl rand -hex 16 echo |
| * 'ceaa31952dfd3d0f5af4b2042ba06094' | sed 's/\(..\)/(byte) 0x\1, /g' |
| */ |
| private static final byte[] AES_256_CBC_PKCS5Padding_TestVector_1_IV = new byte[] { |
| (byte) 0xce, (byte) 0xaa, (byte) 0x31, (byte) 0x95, (byte) 0x2d, (byte) 0xfd, |
| (byte) 0x3d, (byte) 0x0f, (byte) 0x5a, (byte) 0xf4, (byte) 0xb2, (byte) 0x04, |
| (byte) 0x2b, (byte) 0xa0, (byte) 0x60, (byte) 0x94, |
| }; |
| |
| /* |
| * Test vector generation: |
| * echo -n 'I only regret that I have but one test to write.' | recode ../x1 | sed 's/0x/(byte) 0x/g' |
| */ |
| private static final byte[] AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext = new byte[] { |
| (byte) 0x49, (byte) 0x20, (byte) 0x6F, (byte) 0x6E, (byte) 0x6C, (byte) 0x79, |
| (byte) 0x20, (byte) 0x72, (byte) 0x65, (byte) 0x67, (byte) 0x72, (byte) 0x65, |
| (byte) 0x74, (byte) 0x20, (byte) 0x74, (byte) 0x68, (byte) 0x61, (byte) 0x74, |
| (byte) 0x20, (byte) 0x49, (byte) 0x20, (byte) 0x68, (byte) 0x61, (byte) 0x76, |
| (byte) 0x65, (byte) 0x20, (byte) 0x62, (byte) 0x75, (byte) 0x74, (byte) 0x20, |
| (byte) 0x6F, (byte) 0x6E, (byte) 0x65, (byte) 0x20, (byte) 0x74, (byte) 0x65, |
| (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x74, (byte) 0x6F, (byte) 0x20, |
| (byte) 0x77, (byte) 0x72, (byte) 0x69, (byte) 0x74, (byte) 0x65, (byte) 0x2E |
| }; |
| |
| /* |
| * Test vector generation: |
| * echo -n 'I only regret that I have but one test to write.' | openssl enc -aes-256-cbc -K ec53c6d51d2c4973585fb0b8e51cd2e39915ff07a1837872715d6121bf861935 -iv ceaa31952dfd3d0f5af4b2042ba06094 | openssl enc -aes-256-cbc -K ec53c6d51d2c4973585fb0b8e51cd2e39915ff07a1837872715d6121bf861935 -iv ceaa31952dfd3d0f5af4b2042ba06094 -d -nopad | recode ../x1 | sed 's/0x/(byte) 0x/g' |
| */ |
| private static final byte[] AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext_Padded = new byte[] { |
| (byte) 0x49, (byte) 0x20, (byte) 0x6F, (byte) 0x6E, (byte) 0x6C, (byte) 0x79, |
| (byte) 0x20, (byte) 0x72, (byte) 0x65, (byte) 0x67, (byte) 0x72, (byte) 0x65, |
| (byte) 0x74, (byte) 0x20, (byte) 0x74, (byte) 0x68, (byte) 0x61, (byte) 0x74, |
| (byte) 0x20, (byte) 0x49, (byte) 0x20, (byte) 0x68, (byte) 0x61, (byte) 0x76, |
| (byte) 0x65, (byte) 0x20, (byte) 0x62, (byte) 0x75, (byte) 0x74, (byte) 0x20, |
| (byte) 0x6F, (byte) 0x6E, (byte) 0x65, (byte) 0x20, (byte) 0x74, (byte) 0x65, |
| (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x74, (byte) 0x6F, (byte) 0x20, |
| (byte) 0x77, (byte) 0x72, (byte) 0x69, (byte) 0x74, (byte) 0x65, (byte) 0x2E, |
| (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10, |
| (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10, |
| (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10 |
| }; |
| |
| /* |
| * Test vector generation: |
| * echo -n 'I only regret that I have but one test to write.' | openssl enc -aes-256-cbc -K ec53c6d51d2c4973585fb0b8e51cd2e39915ff07a1837872715d6121bf861935 -iv ceaa31952dfd3d0f5af4b2042ba06094 | recode ../x1 | sed 's/0x/(byte) 0x/g' |
| */ |
| private static final byte[] AES_256_CBC_PKCS5Padding_TestVector_1_Ciphertext = new byte[] { |
| (byte) 0x90, (byte) 0x65, (byte) 0xDD, (byte) 0xAF, (byte) 0x7A, (byte) 0xCE, |
| (byte) 0xAE, (byte) 0xBF, (byte) 0xE8, (byte) 0xF6, (byte) 0x9E, (byte) 0xDB, |
| (byte) 0xEA, (byte) 0x65, (byte) 0x28, (byte) 0xC4, (byte) 0x9A, (byte) 0x28, |
| (byte) 0xEA, (byte) 0xA3, (byte) 0x95, (byte) 0x2E, (byte) 0xFF, (byte) 0xF1, |
| (byte) 0xA0, (byte) 0xCA, (byte) 0xC2, (byte) 0xA4, (byte) 0x65, (byte) 0xCD, |
| (byte) 0xBF, (byte) 0xCE, (byte) 0x9E, (byte) 0xF1, (byte) 0x57, (byte) 0xF6, |
| (byte) 0x32, (byte) 0x2E, (byte) 0x8F, (byte) 0x93, (byte) 0x2E, (byte) 0xAE, |
| (byte) 0x41, (byte) 0x33, (byte) 0x54, (byte) 0xD0, (byte) 0xEF, (byte) 0x8C, |
| (byte) 0x52, (byte) 0x14, (byte) 0xAC, (byte) 0x2D, (byte) 0xD5, (byte) 0xA4, |
| (byte) 0xF9, (byte) 0x20, (byte) 0x77, (byte) 0x25, (byte) 0x91, (byte) 0x3F, |
| (byte) 0xD1, (byte) 0xB9, (byte) 0x00, (byte) 0x3E |
| }; |
| |
| private static class CipherTestParam { |
| public final String transformation; |
| |
| public final byte[] key; |
| |
| public final byte[] iv; |
| |
| public final byte[] aad; |
| |
| public final byte[] plaintext; |
| |
| public final byte[] ciphertext; |
| |
| public final byte[] plaintextPadded; |
| |
| public CipherTestParam(String transformation, byte[] key, byte[] iv, byte[] aad, |
| byte[] plaintext, byte[] plaintextPadded, byte[] ciphertext) { |
| this.transformation = transformation.toUpperCase(Locale.ROOT); |
| this.key = key; |
| this.iv = iv; |
| this.aad = aad; |
| this.plaintext = plaintext; |
| this.plaintextPadded = plaintextPadded; |
| this.ciphertext = ciphertext; |
| } |
| } |
| |
| private static List<CipherTestParam> CIPHER_TEST_PARAMS = new ArrayList<CipherTestParam>(); |
| static { |
| CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/ECB/PKCS5Padding", AES_128_KEY, |
| null, |
| null, |
| AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext, |
| AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded, |
| AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted)); |
| // PKCS#5 is assumed to be equivalent to PKCS#7 -- same test vectors are thus used for both. |
| CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/ECB/PKCS7Padding", AES_128_KEY, |
| null, |
| null, |
| AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext, |
| AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded, |
| AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted)); |
| CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/GCM/NOPADDING", |
| AES_128_GCM_TestVector_1_Key, |
| AES_128_GCM_TestVector_1_IV, |
| AES_128_GCM_TestVector_1_AAD, |
| AES_128_GCM_TestVector_1_Plaintext, |
| AES_128_GCM_TestVector_1_Plaintext, |
| AES_128_GCM_TestVector_1_Encrypted)); |
| if (IS_UNLIMITED) { |
| CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/CTR/NoPadding", AES_192_KEY, |
| AES_192_CTR_NoPadding_TestVector_1_IV, |
| null, |
| AES_192_CTR_NoPadding_TestVector_1_Plaintext, |
| AES_192_CTR_NoPadding_TestVector_1_Plaintext, |
| AES_192_CTR_NoPadding_TestVector_1_Ciphertext)); |
| CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/CBC/PKCS5Padding", AES_256_KEY, |
| AES_256_CBC_PKCS5Padding_TestVector_1_IV, |
| null, |
| AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext, |
| AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext_Padded, |
| AES_256_CBC_PKCS5Padding_TestVector_1_Ciphertext)); |
| CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/CBC/PKCS7Padding", AES_256_KEY, |
| AES_256_CBC_PKCS5Padding_TestVector_1_IV, |
| null, |
| AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext, |
| AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext_Padded, |
| AES_256_CBC_PKCS5Padding_TestVector_1_Ciphertext)); |
| } |
| } |
| |
| public void testCipher_Success() throws Exception { |
| for (String provider : AES_PROVIDERS) { |
| testCipher_Success(provider); |
| } |
| } |
| |
| private void testCipher_Success(String provider) throws Exception { |
| final ByteArrayOutputStream errBuffer = new ByteArrayOutputStream(); |
| PrintStream out = new PrintStream(errBuffer); |
| for (CipherTestParam p : CIPHER_TEST_PARAMS) { |
| try { |
| checkCipher(p, provider); |
| } catch (Exception e) { |
| out.append("Error encountered checking " + p.transformation + ", keySize=" |
| + (p.key.length * 8) |
| + " with provider " + provider + "\n"); |
| |
| e.printStackTrace(out); |
| } |
| } |
| out.flush(); |
| if (errBuffer.size() > 0) { |
| throw new Exception("Errors encountered:\n\n" + errBuffer.toString() + "\n\n"); |
| } |
| } |
| |
| private void checkCipher(CipherTestParam p, String provider) throws Exception { |
| SecretKey key = new SecretKeySpec(p.key, "AES"); |
| Cipher c = Cipher.getInstance(p.transformation, provider); |
| |
| AlgorithmParameterSpec spec = null; |
| if (p.iv != null) { |
| if (isAEAD(p.transformation)) { |
| spec = new GCMParameterSpec((p.ciphertext.length - p.plaintext.length) * 8, p.iv); |
| } else { |
| spec = new IvParameterSpec(p.iv); |
| } |
| } |
| |
| c.init(Cipher.ENCRYPT_MODE, key, spec); |
| |
| if (p.aad != null) { |
| c.updateAAD(p.aad); |
| } |
| final byte[] actualCiphertext = c.doFinal(p.plaintext); |
| assertEquals(p.transformation + " " + provider, Arrays.toString(p.ciphertext), |
| Arrays.toString(actualCiphertext)); |
| |
| c = Cipher.getInstance(p.transformation, provider); |
| c.init(Cipher.ENCRYPT_MODE, key, spec); |
| byte[] emptyCipherText = c.doFinal(); |
| assertNotNull(emptyCipherText); |
| |
| c.init(Cipher.DECRYPT_MODE, key, spec); |
| |
| if (!isAEAD(p.transformation)) { |
| try { |
| c.updateAAD(new byte[8]); |
| fail("Cipher should not support AAD"); |
| } catch (UnsupportedOperationException | IllegalStateException expected) { |
| } |
| } |
| |
| try { |
| byte[] emptyPlainText = c.doFinal(emptyCipherText); |
| assertEquals(Arrays.toString(new byte[0]), Arrays.toString(emptyPlainText)); |
| } catch (AEADBadTagException e) { |
| if (!"AndroidOpenSSL".equals(provider) || !isAEAD(p.transformation)) { |
| throw e; |
| } |
| } |
| |
| // empty decrypt |
| { |
| if (!isAEAD(p.transformation) |
| && (StandardNames.IS_RI || provider.equals("AndroidOpenSSL") || |
| (provider.equals("BC") && p.transformation.contains("/CTR/")))) { |
| assertEquals(Arrays.toString(new byte[0]), |
| Arrays.toString(c.doFinal())); |
| |
| c.update(new byte[0]); |
| assertEquals(Arrays.toString(new byte[0]), |
| Arrays.toString(c.doFinal())); |
| } else if (provider.equals("BC") || isAEAD(p.transformation)) { |
| try { |
| c.doFinal(); |
| fail(p.transformation + " " + provider); |
| } catch (IllegalBlockSizeException maybe) { |
| if (isAEAD(p.transformation)) { |
| throw maybe; |
| } |
| } catch (AEADBadTagException maybe) { |
| if (!isAEAD(p.transformation)) { |
| throw maybe; |
| } |
| } |
| try { |
| c.update(new byte[0]); |
| c.doFinal(); |
| fail(p.transformation + " " + provider); |
| } catch (IllegalBlockSizeException maybe) { |
| if (isAEAD(p.transformation)) { |
| throw maybe; |
| } |
| } catch (AEADBadTagException maybe) { |
| if (!isAEAD(p.transformation)) { |
| throw maybe; |
| } |
| } |
| } else { |
| throw new AssertionError("Define your behavior here for " + provider); |
| } |
| } |
| |
| // Cipher might be in unspecified state from failures above. |
| c.init(Cipher.DECRYPT_MODE, key, spec); |
| |
| // .doFinal(input) |
| { |
| if (p.aad != null) { |
| c.updateAAD(p.aad); |
| } |
| final byte[] actualPlaintext = c.doFinal(p.ciphertext); |
| assertEquals(Arrays.toString(p.plaintext), Arrays.toString(actualPlaintext)); |
| } |
| |
| // .doFinal(input, offset, len, output) |
| { |
| final byte[] largerThanCiphertext = new byte[p.ciphertext.length + 5]; |
| System.arraycopy(p.ciphertext, 0, largerThanCiphertext, 5, p.ciphertext.length); |
| |
| if (p.aad != null) { |
| final byte[] largerThanAad = new byte[p.aad.length + 100]; |
| System.arraycopy(p.aad, 0, largerThanAad, 50, p.aad.length); |
| assertTrue(p.aad.length > 1); |
| c.updateAAD(largerThanAad, 50, 1); |
| c.updateAAD(largerThanAad, 51, p.aad.length - 1); |
| } |
| |
| final byte[] actualPlaintext = new byte[c.getOutputSize(p.ciphertext.length)]; |
| assertEquals(p.plaintext.length, |
| c.doFinal(largerThanCiphertext, 5, p.ciphertext.length, actualPlaintext)); |
| assertEquals(Arrays.toString(p.plaintext), |
| Arrays.toString(Arrays.copyOfRange(actualPlaintext, 0, p.plaintext.length))); |
| } |
| |
| // .doFinal(input, offset, len, output, offset) |
| { |
| final byte[] largerThanCiphertext = new byte[p.ciphertext.length + 10]; |
| System.arraycopy(p.ciphertext, 0, largerThanCiphertext, 5, p.ciphertext.length); |
| |
| if (p.aad != null) { |
| final byte[] largerThanAad = new byte[p.aad.length + 2]; |
| System.arraycopy(p.aad, 0, largerThanAad, 2, p.aad.length); |
| c.updateAAD(largerThanAad, 2, p.aad.length); |
| } |
| |
| final byte[] actualPlaintext = new byte[c.getOutputSize(p.ciphertext.length) + 2]; |
| assertEquals(p.plaintext.length, |
| c.doFinal(largerThanCiphertext, 5, p.ciphertext.length, actualPlaintext, 1)); |
| assertEquals(Arrays.toString(p.plaintext), |
| Arrays.toString(Arrays.copyOfRange(actualPlaintext, 1, p.plaintext.length + 1))); |
| } |
| |
| if (!p.transformation.endsWith("NOPADDING")) { |
| Cipher cNoPad = Cipher.getInstance( |
| getCipherTransformationWithNoPadding(p.transformation), provider); |
| cNoPad.init(Cipher.DECRYPT_MODE, key, spec); |
| |
| if (p.aad != null) { |
| c.updateAAD(p.aad); |
| } |
| final byte[] actualPlaintextPadded = cNoPad.doFinal(p.ciphertext); |
| assertEquals(provider + ":" + cNoPad.getAlgorithm(), |
| Arrays.toString(p.plaintextPadded), Arrays.toString(actualPlaintextPadded)); |
| } |
| |
| // Test wrapping a key. Every cipher should be able to wrap. |
| { |
| // Generate a small SecretKey for AES. |
| KeyGenerator kg = KeyGenerator.getInstance("AES"); |
| kg.init(128); |
| SecretKey sk = kg.generateKey(); |
| |
| // Wrap it |
| c = Cipher.getInstance(p.transformation, provider); |
| c.init(Cipher.WRAP_MODE, key, spec); |
| byte[] cipherText = c.wrap(sk); |
| |
| // Unwrap it |
| c.init(Cipher.UNWRAP_MODE, key, spec); |
| Key decryptedKey = c.unwrap(cipherText, sk.getAlgorithm(), Cipher.SECRET_KEY); |
| |
| assertEquals( |
| "sk.getAlgorithm()=" + sk.getAlgorithm() + " decryptedKey.getAlgorithm()=" |
| + decryptedKey.getAlgorithm() + " encryptKey.getEncoded()=" |
| + Arrays.toString(sk.getEncoded()) + " decryptedKey.getEncoded()=" |
| + Arrays.toString(decryptedKey.getEncoded()), sk, decryptedKey); |
| } |
| } |
| |
| /** |
| * Gets the Cipher transformation with the same algorithm and mode as the provided one but |
| * which uses no padding. |
| */ |
| private static String getCipherTransformationWithNoPadding(String transformation) { |
| // The transformation is assumed to be in the Algorithm/Mode/Padding format. |
| int paddingModeDelimiterIndex = transformation.lastIndexOf('/'); |
| if (paddingModeDelimiterIndex == -1) { |
| fail("No padding mode delimiter: " + transformation); |
| } |
| String paddingMode = transformation.substring(paddingModeDelimiterIndex + 1); |
| if (!paddingMode.toLowerCase().endsWith("padding")) { |
| fail("No padding mode specified:" + transformation); |
| } |
| return transformation.substring(0, paddingModeDelimiterIndex) + "/NoPadding"; |
| } |
| |
| public void testCipher_updateAAD_BeforeInit_Failure() throws Exception { |
| Cipher c = Cipher.getInstance("AES/ECB/NoPadding"); |
| |
| try { |
| c.updateAAD((byte[]) null); |
| fail("should not be able to call updateAAD before Cipher is initialized"); |
| } catch (IllegalArgumentException expected) { |
| } |
| |
| try { |
| c.updateAAD((ByteBuffer) null); |
| fail("should not be able to call updateAAD before Cipher is initialized"); |
| } catch (IllegalStateException expected) { |
| } |
| |
| try { |
| c.updateAAD(new byte[8]); |
| fail("should not be able to call updateAAD before Cipher is initialized"); |
| } catch (IllegalStateException expected) { |
| } |
| |
| try { |
| c.updateAAD(null, 0, 8); |
| fail("should not be able to call updateAAD before Cipher is initialized"); |
| } catch (IllegalStateException expected) { |
| } |
| |
| ByteBuffer bb = ByteBuffer.allocate(8); |
| try { |
| c.updateAAD(bb); |
| fail("should not be able to call updateAAD before Cipher is initialized"); |
| } catch (IllegalStateException expected) { |
| } |
| } |
| |
| public void testCipher_updateAAD_AfterInit_Failure() throws Exception { |
| Cipher c = Cipher.getInstance("AES/ECB/NoPadding"); |
| c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(new byte[128 / 8], "AES")); |
| |
| try { |
| c.updateAAD((byte[]) null); |
| fail("should not be able to call updateAAD with null input"); |
| } catch (IllegalArgumentException expected) { |
| } |
| |
| try { |
| c.updateAAD((ByteBuffer) null); |
| fail("should not be able to call updateAAD with null input"); |
| } catch (IllegalArgumentException expected) { |
| } |
| |
| try { |
| c.updateAAD(null, 0, 8); |
| fail("should not be able to call updateAAD with null input"); |
| } catch (IllegalArgumentException expected) { |
| } |
| |
| try { |
| c.updateAAD(new byte[8], -1, 7); |
| fail("should not be able to call updateAAD with invalid offset"); |
| } catch (IllegalArgumentException expected) { |
| } |
| |
| try { |
| c.updateAAD(new byte[8], 0, -1); |
| fail("should not be able to call updateAAD with negative length"); |
| } catch (IllegalArgumentException expected) { |
| } |
| |
| try { |
| c.updateAAD(new byte[8], 0, 8 + 1); |
| fail("should not be able to call updateAAD with too large length"); |
| } catch (IllegalArgumentException expected) { |
| } |
| |
| try { |
| c.updateAAD(new byte[8]); |
| fail("should not be able to call updateAAD on non-AEAD cipher"); |
| } catch (UnsupportedOperationException | IllegalStateException expected) { |
| } |
| } |
| |
| public void testCipher_updateAAD_AfterInit_WithGcm_Success() throws Exception { |
| Cipher c = Cipher.getInstance("AES/GCM/NoPadding"); |
| c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(new byte[128 / 8], "AES")); |
| c.updateAAD(new byte[8]); |
| c.updateAAD(new byte[8]); |
| } |
| |
| public void testCipher_updateAAD_AfterUpdate_WithGcm_Sucess() throws Exception { |
| Cipher c = Cipher.getInstance("AES/GCM/NoPadding"); |
| c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(new byte[128 / 8], "AES")); |
| c.updateAAD(new byte[8]); |
| c.update(new byte[8]); |
| c.updateAAD(new byte[8]); |
| } |
| |
| public void testCipher_ShortBlock_Failure() throws Exception { |
| for (String provider : AES_PROVIDERS) { |
| testCipher_ShortBlock_Failure(provider); |
| } |
| } |
| |
| private void testCipher_ShortBlock_Failure(String provider) throws Exception { |
| final ByteArrayOutputStream errBuffer = new ByteArrayOutputStream(); |
| PrintStream out = new PrintStream(errBuffer); |
| for (CipherTestParam p : CIPHER_TEST_PARAMS) { |
| try { |
| checkCipher_ShortBlock_Failure(p, provider); |
| } catch (Exception e) { |
| out.append("Error encountered checking " + p.transformation + ", keySize=" |
| + (p.key.length * 8) |
| + " with provider " + provider + "\n"); |
| e.printStackTrace(out); |
| } |
| } |
| out.flush(); |
| if (errBuffer.size() > 0) { |
| throw new Exception("Errors encountered:\n\n" + errBuffer.toString() + "\n\n"); |
| } |
| } |
| |
| public void testCipher_DoFinal_wrapMode_Failure() throws Exception { |
| checkCipher_DoFinal_invalidMode_Failure(Cipher.WRAP_MODE); |
| } |
| |
| public void testCipher_DoFinal_unwrapMode_Failure() throws Exception { |
| checkCipher_DoFinal_invalidMode_Failure(Cipher.UNWRAP_MODE); |
| } |
| |
| /** |
| * Helper for testing that Cipher.doFinal() throws IllegalStateException when |
| * initialized in modes other than DECRYPT or ENCRYPT. |
| */ |
| private static void checkCipher_DoFinal_invalidMode_Failure(int opmode) throws Exception { |
| String msg = String.format(Locale.US, |
| "doFinal() should throw IllegalStateException [mode=%d]", opmode); |
| int bs = createAesCipher(opmode).getBlockSize(); |
| assertEquals(16, bs); // check test is set up correctly |
| try { |
| createAesCipher(opmode).doFinal(); |
| fail(msg); |
| } catch (IllegalStateException expected) { |
| } |
| |
| try { |
| createAesCipher(opmode).doFinal(new byte[0]); |
| fail(msg); |
| } catch (IllegalStateException expected) { |
| } |
| |
| try { |
| createAesCipher(opmode).doFinal(new byte[2 * bs], 0, bs); |
| fail(msg); |
| } catch (IllegalStateException expected) { |
| } |
| |
| try { |
| createAesCipher(opmode).doFinal(new byte[2 * bs], 0, bs, new byte[2 * bs], 0); |
| fail(msg); |
| } catch (IllegalStateException expected) { |
| } |
| } |
| |
| public void testCipher_Update_wrapMode_Failure() throws Exception { |
| checkCipher_Update_invalidMode_Failure(Cipher.WRAP_MODE); |
| } |
| |
| public void testCipher_Update_unwrapMode_Failure() throws Exception { |
| checkCipher_Update_invalidMode_Failure(Cipher.UNWRAP_MODE); |
| } |
| |
| /** |
| * Helper for testing that Cipher.update() throws IllegalStateException when |
| * initialized in modes other than DECRYPT or ENCRYPT. |
| */ |
| private static void checkCipher_Update_invalidMode_Failure(int opmode) throws Exception { |
| String msg = "update() should throw IllegalStateException [mode=" + opmode + "]"; |
| int bs = createAesCipher(opmode).getBlockSize(); |
| assertEquals(16, bs); // check test is set up correctly |
| assertIllegalStateException(msg, () -> createAesCipher(opmode).update(new byte[0])); |
| assertIllegalStateException(msg, () -> createAesCipher(opmode).update(new byte[2 * bs])); |
| assertIllegalStateException(msg, () -> createAesCipher(opmode).update( |
| new byte[2 * bs] /* input */, bs /* inputOffset */, 0 /* inputLen */)); |
| try { |
| createAesCipher(opmode).update(new byte[2*bs] /* input */, 0 /* inputOffset */, |
| 2 * bs /* inputLen */, new byte[2 * bs] /* output */, 0 /* outputOffset */); |
| fail(msg); |
| } catch (IllegalStateException expected) { |
| } |
| } |
| |
| public void testCipher_Update_WithZeroLengthInput_ReturnsNull() throws Exception { |
| SecretKey key = new SecretKeySpec(AES_128_KEY, "AES"); |
| Cipher c = Cipher.getInstance("AES/ECB/NoPadding"); |
| c.init(Cipher.ENCRYPT_MODE, key); |
| assertNull(c.update(new byte[0])); |
| assertNull(c.update(new byte[c.getBlockSize() * 2], 0, 0)); |
| |
| // Try with non-zero offset just in case the implementation mixes up offset and inputLen |
| assertNull(c.update(new byte[c.getBlockSize() * 2], 16, 0)); |
| } |
| |
| public void testCipher_Wrap_decryptMode_Failure() throws Exception { |
| checkCipher_Wrap_invalidMode_Failure(Cipher.DECRYPT_MODE); |
| } |
| |
| public void testCipher_Wrap_encryptMode_Failure() throws Exception { |
| checkCipher_Wrap_invalidMode_Failure(Cipher.ENCRYPT_MODE); |
| } |
| |
| public void testCipher_Wrap_unwrapMode_Failure() throws Exception { |
| checkCipher_Wrap_invalidMode_Failure(Cipher.UNWRAP_MODE); |
| } |
| |
| /** |
| * Helper for testing that Cipher.wrap() throws IllegalStateException when |
| * initialized in modes other than WRAP. |
| */ |
| private static void checkCipher_Wrap_invalidMode_Failure(int opmode) throws Exception { |
| KeyGenerator kg = KeyGenerator.getInstance("AES"); |
| kg.init(128); |
| SecretKey key = kg.generateKey(); |
| Cipher cipher = createAesCipher(opmode); |
| try { |
| cipher.wrap(key); |
| fail("wrap() should throw IllegalStateException [mode=" + opmode + "]"); |
| } catch (IllegalStateException expected) { |
| } |
| } |
| |
| public void testCipher_Unwrap_decryptMode_Failure() throws Exception { |
| checkCipher_Unwrap_invalidMode_Failure(Cipher.DECRYPT_MODE); |
| } |
| |
| public void testCipher_Unwrap_encryptMode_Failure() throws Exception { |
| checkCipher_Unwrap_invalidMode_Failure(Cipher.ENCRYPT_MODE); |
| } |
| |
| public void testCipher_Unwrap_wrapMode_Failure() throws Exception { |
| checkCipher_Unwrap_invalidMode_Failure(Cipher.WRAP_MODE); |
| } |
| |
| /** |
| * Helper for testing that Cipher.unwrap() throws IllegalStateException when |
| * initialized in modes other than UNWRAP. |
| */ |
| private static void checkCipher_Unwrap_invalidMode_Failure(int opmode) throws Exception { |
| KeyGenerator kg = KeyGenerator.getInstance("AES"); |
| kg.init(128); |
| SecretKey key = kg.generateKey(); |
| Cipher cipher = createAesCipher(opmode); |
| byte[] wrappedKey = createAesCipher(Cipher.WRAP_MODE).wrap(key); |
| try { |
| cipher.unwrap(wrappedKey, key.getAlgorithm(), Cipher.PRIVATE_KEY); |
| fail("unwrap() should throw IllegalStateException [mode=" + opmode + "]"); |
| } catch (IllegalStateException expected) { |
| } |
| } |
| |
| private void checkCipher_ShortBlock_Failure(CipherTestParam p, String provider) throws Exception { |
| // Do not try to test ciphers with no padding already. |
| String noPaddingTransform = getCipherTransformationWithNoPadding(p.transformation); |
| if (p.transformation.equals(noPaddingTransform)) { |
| return; |
| } |
| |
| SecretKey key = new SecretKeySpec(p.key, "AES"); |
| Cipher c = Cipher.getInstance( |
| getCipherTransformationWithNoPadding(p.transformation), provider); |
| if (c.getBlockSize() == 0) { |
| return; |
| } |
| |
| if (!p.transformation.endsWith("NOPADDING")) { |
| c.init(Cipher.ENCRYPT_MODE, key); |
| try { |
| c.doFinal(new byte[] { 0x01, 0x02, 0x03 }); |
| fail("Should throw IllegalBlockSizeException on wrong-sized block; transform=" |
| + p.transformation + " provider=" + provider); |
| } catch (IllegalBlockSizeException expected) { |
| } |
| } |
| } |
| |
| public void test_DefaultGCMTagSizeAlgorithmParameterSpec() throws Exception { |
| final String AES = "AES"; |
| final String AES_GCM = "AES/GCM/NoPadding"; |
| byte[] input = new byte[16]; |
| byte[] key = new byte[16]; |
| Cipher cipher = Cipher.getInstance(AES_GCM, "BC"); |
| AlgorithmParameters param = AlgorithmParameters.getInstance("GCM"); |
| param.init(new byte[] { |
| (byte) 48, // DER encoding : tag_Sequence |
| (byte) 14, // DER encoding : total length |
| (byte) 4, // DER encoding : tag_OctetString |
| (byte) 12, // DER encoding : counter length |
| // Note that IV's size 12 bytes is recommended, but authentication tag size should be 16 |
| // bytes. |
| (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, |
| (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0 }); |
| cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, AES), param); |
| byte[] ciphertext = cipher.update(input); |
| byte[] tag = cipher.doFinal(); |
| assertEquals(16, tag.length); |
| } |
| |
| public void testAES_ECB_PKCS5Padding_ShortBuffer_Failure() throws Exception { |
| for (String provider : AES_PROVIDERS) { |
| testAES_ECB_PKCS5Padding_ShortBuffer_Failure(provider); |
| } |
| } |
| |
| private void testAES_ECB_PKCS5Padding_ShortBuffer_Failure(String provider) throws Exception { |
| SecretKey key = new SecretKeySpec(AES_128_KEY, "AES"); |
| Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding", provider); |
| c.init(Cipher.ENCRYPT_MODE, key); |
| |
| final byte[] fragmentOutput = c.update(AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext); |
| if (fragmentOutput != null) { |
| assertEquals(0, fragmentOutput.length); |
| } |
| |
| // Provide null buffer. |
| { |
| try { |
| c.doFinal(null, 0); |
| fail("Should throw NullPointerException on null output buffer"); |
| } catch (NullPointerException expected) { |
| } catch (IllegalArgumentException expected) { |
| } |
| } |
| |
| // Provide short buffer. |
| { |
| final byte[] output = new byte[c.getBlockSize() - 1]; |
| try { |
| c.doFinal(output, 0); |
| fail("Should throw ShortBufferException on short output buffer"); |
| } catch (ShortBufferException expected) { |
| } |
| } |
| |
| // Start 1 byte into output buffer. |
| { |
| final byte[] output = new byte[c.getBlockSize()]; |
| try { |
| c.doFinal(output, 1); |
| fail("Should throw ShortBufferException on short output buffer"); |
| } catch (ShortBufferException expected) { |
| } |
| } |
| |
| // Should keep data for real output buffer |
| { |
| final byte[] output = new byte[c.getBlockSize()]; |
| assertEquals(AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted.length, c.doFinal(output, 0)); |
| assertTrue(Arrays.equals(AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted, output)); |
| } |
| } |
| |
| public void testAES_ECB_NoPadding_IncrementalUpdate_Success() throws Exception { |
| for (String provider : AES_PROVIDERS) { |
| testAES_ECB_NoPadding_IncrementalUpdate_Success(provider); |
| } |
| } |
| |
| private void testAES_ECB_NoPadding_IncrementalUpdate_Success(String provider) throws Exception { |
| SecretKey key = new SecretKeySpec(AES_128_KEY, "AES"); |
| Cipher c = Cipher.getInstance("AES/ECB/NoPadding", provider); |
| assertEquals(provider, c.getProvider().getName()); |
| c.init(Cipher.ENCRYPT_MODE, key); |
| |
| for (int i = 0; i < AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded.length - 1; i++) { |
| final byte[] outputFragment = c.update(AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded, i, 1); |
| if (outputFragment != null) { |
| assertEquals(0, outputFragment.length); |
| } |
| } |
| |
| final byte[] output = c.doFinal(AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded, |
| AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded.length - 1, 1); |
| assertNotNull(provider, output); |
| assertEquals(provider, AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded.length, |
| output.length); |
| |
| assertTrue(provider, Arrays.equals(AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted, output)); |
| } |
| |
| private static final byte[] AES_IV_ZEROES = new byte[] { |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| }; |
| |
| public void testAES_ECB_NoPadding_IvParameters_Failure() throws Exception { |
| for (String provider : AES_PROVIDERS) { |
| testAES_ECB_NoPadding_IvParameters_Failure(provider); |
| } |
| } |
| |
| private void testAES_ECB_NoPadding_IvParameters_Failure(String provider) throws Exception { |
| SecretKey key = new SecretKeySpec(AES_128_KEY, "AES"); |
| Cipher c = Cipher.getInstance("AES/ECB/NoPadding", provider); |
| |
| AlgorithmParameterSpec spec = new IvParameterSpec(AES_IV_ZEROES); |
| try { |
| c.init(Cipher.ENCRYPT_MODE, key, spec); |
| fail("Should not accept an IV in ECB mode; provider=" + provider); |
| } catch (InvalidAlgorithmParameterException expected) { |
| } |
| } |
| |
| public void testRC4_MultipleKeySizes() throws Exception { |
| final int SMALLEST_KEY_SIZE = 40; |
| final int LARGEST_KEY_SIZE = 1024; |
| |
| /* Make an array of keys for our tests */ |
| SecretKey[] keys = new SecretKey[LARGEST_KEY_SIZE - SMALLEST_KEY_SIZE]; |
| { |
| KeyGenerator kg = KeyGenerator.getInstance("ARC4"); |
| for (int keysize = SMALLEST_KEY_SIZE; keysize < LARGEST_KEY_SIZE; keysize++) { |
| final int index = keysize - SMALLEST_KEY_SIZE; |
| kg.init(keysize); |
| keys[index] = kg.generateKey(); |
| } |
| } |
| |
| /* |
| * Use this to compare the output of the first provider against |
| * subsequent providers. |
| */ |
| String[] expected = new String[LARGEST_KEY_SIZE - SMALLEST_KEY_SIZE]; |
| |
| /* Find all providers that provide ARC4. We must have at least one! */ |
| Map<String, String> filter = new HashMap<String, String>(); |
| filter.put("Cipher.ARC4", ""); |
| Provider[] providers = Security.getProviders(filter); |
| assertTrue("There must be security providers of Cipher.ARC4", providers.length > 0); |
| |
| /* Keep track of this for later error messages */ |
| String firstProvider = providers[0].getName(); |
| |
| for (Provider p : providers) { |
| Cipher c = Cipher.getInstance("ARC4", p); |
| |
| for (int keysize = SMALLEST_KEY_SIZE; keysize < LARGEST_KEY_SIZE; keysize++) { |
| final int index = keysize - SMALLEST_KEY_SIZE; |
| final SecretKey sk = keys[index]; |
| |
| /* |
| * Test that encryption works. Donig this in a loop also has the |
| * benefit of testing that re-initialization works for this |
| * cipher. |
| */ |
| c.init(Cipher.ENCRYPT_MODE, sk); |
| byte[] cipherText = c.doFinal(ORIGINAL_PLAIN_TEXT); |
| assertNotNull(cipherText); |
| |
| /* |
| * Compare providers against eachother to make sure they're all |
| * in agreement. This helps when you add a brand new provider. |
| */ |
| if (expected[index] == null) { |
| expected[index] = Arrays.toString(cipherText); |
| } else { |
| assertEquals(firstProvider + " should output the same as " + p.getName() |
| + " for key size " + keysize, expected[index], |
| Arrays.toString(cipherText)); |
| } |
| |
| c.init(Cipher.DECRYPT_MODE, sk); |
| byte[] actualPlaintext = c.doFinal(cipherText); |
| assertEquals("Key size: " + keysize, Arrays.toString(ORIGINAL_PLAIN_TEXT), |
| Arrays.toString(actualPlaintext)); |
| } |
| } |
| } |
| |
| /** |
| * Several exceptions can be thrown by init. Check that in this case we throw the right one, |
| * as the error could fall under the umbrella of other exceptions. |
| * http://b/18987633 |
| */ |
| public void testCipher_init_DoesNotSupportKeyClass_throwsInvalidKeyException() |
| throws Exception { |
| Provider mockProvider = new MockProvider("MockProvider") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName()); |
| put("Cipher.FOO SupportedKeyClasses", "none"); |
| } |
| }; |
| |
| Security.addProvider(mockProvider); |
| try { |
| Cipher c = Cipher.getInstance("FOO"); |
| c.init(Cipher.DECRYPT_MODE, new MockKey()); |
| fail("Expected InvalidKeyException"); |
| } catch (InvalidKeyException expected) { |
| } finally { |
| Security.removeProvider(mockProvider.getName()); |
| } |
| } |
| |
| /* |
| * When in decrypt mode and using padding, the buffer shouldn't necessarily have room for an |
| * extra block when using padding. |
| * http://b/19186852 |
| */ |
| public void testDecryptBufferMultipleBlockSize_mustNotThrowException() throws Exception { |
| String testString = "Hello, World!"; |
| byte[] testKey = "0123456789012345".getBytes(StandardCharsets.US_ASCII); |
| String testedCipher = "AES/ECB/PKCS7Padding"; |
| |
| Cipher encCipher = Cipher.getInstance(testedCipher); |
| encCipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(testKey, "AES")); |
| byte[] plainBuffer = testString.getBytes(StandardCharsets.US_ASCII); |
| byte[] encryptedBuffer = new byte[16]; |
| int encryptedLength = encCipher.doFinal( |
| plainBuffer, 0, plainBuffer.length, encryptedBuffer); |
| assertEquals(16, encryptedLength); |
| |
| Cipher cipher = Cipher.getInstance(testedCipher); |
| cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(testKey, "AES")); |
| // Must not throw exception. |
| int unencryptedBytes = cipher.doFinal( |
| encryptedBuffer, 0, encryptedBuffer.length, encryptedBuffer); |
| assertEquals(testString, |
| new String(encryptedBuffer, 0, unencryptedBytes, StandardCharsets.US_ASCII)); |
| } |
| |
| /** |
| * When using padding in decrypt mode, ensure that empty buffers decode to empty strings |
| * (no padding needed for the empty buffer). |
| * http://b/19186852 |
| */ |
| public void testDecryptBufferZeroSize_mustDecodeToEmptyString() throws Exception { |
| String[] androidOpenSSLCiphers = { "AES/CBC/PKCS5PADDING", "AES/CBC/PKCS7PADDING", |
| "AES/ECB/PKCS5PADDING", "AES/ECB/PKCS7PADDING", "DESEDE/CBC/PKCS5PADDING", |
| "DESEDE/CBC/PKCS7PADDING" }; |
| for (String c : androidOpenSSLCiphers) { |
| Cipher cipher = Cipher.getInstance(c); |
| if (c.contains("/CBC/")) { |
| cipher.init(Cipher.DECRYPT_MODE, |
| new SecretKeySpec("0123456789012345".getBytes(StandardCharsets.US_ASCII), |
| (c.startsWith("AES/")) ? "AES" : "DESEDE"), |
| new IvParameterSpec( |
| ("01234567" + ((c.startsWith("AES/")) ? "89012345" : "")) |
| .getBytes(StandardCharsets.US_ASCII))); |
| } else { |
| cipher.init(Cipher.DECRYPT_MODE, |
| new SecretKeySpec("0123456789012345".getBytes(StandardCharsets.US_ASCII), |
| (c.startsWith("AES/")) ? "AES" : "DESEDE")); |
| } |
| |
| byte[] buffer = new byte[0]; |
| int bytesProduced = cipher.doFinal(buffer, 0, buffer.length, buffer); |
| assertEquals("", new String(buffer, 0, bytesProduced, StandardCharsets.US_ASCII)); |
| } |
| } |
| |
| /** |
| * If a provider rejects a key for "Cipher/Mode/Padding"", there might be another that |
| * accepts the key for "Cipher". Don't throw InvalidKeyException when trying the first one. |
| * http://b/22208820 |
| */ |
| public void testCipher_init_tryAllCombinationsBeforeThrowingInvalidKey() |
| throws Exception { |
| Provider mockProvider = new MockProvider("MockProvider") { |
| public void setup() { |
| put("Cipher.FOO/FOO/FOO", MockCipherSpi.AllKeyTypes.class.getName()); |
| put("Cipher.FOO/FOO/FOO SupportedKeyClasses", "none"); |
| } |
| }; |
| |
| Provider mockProvider2 = new MockProvider("MockProvider2") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName()); |
| } |
| }; |
| |
| Security.addProvider(mockProvider); |
| |
| try { |
| try { |
| // The provider installed doesn't accept the key. |
| Cipher c = Cipher.getInstance("FOO/FOO/FOO"); |
| c.init(Cipher.DECRYPT_MODE, new MockKey()); |
| fail("Expected InvalidKeyException"); |
| } catch (InvalidKeyException expected) { |
| } |
| |
| Security.addProvider(mockProvider2); |
| |
| try { |
| // The new provider accepts "FOO" with this key. Use it despite the other provider |
| // accepts "FOO/FOO/FOO" but doesn't accept the key. |
| Cipher c = Cipher.getInstance("FOO/FOO/FOO"); |
| c.init(Cipher.DECRYPT_MODE, new MockKey()); |
| assertEquals("MockProvider2", c.getProvider().getName()); |
| } finally { |
| Security.removeProvider(mockProvider2.getName()); |
| } |
| } finally { |
| Security.removeProvider(mockProvider.getName()); |
| } |
| } |
| |
| /** |
| * Check that RSA with OAEPPadding is supported. |
| * http://b/22208820 |
| */ |
| public void test_RSA_OAEPPadding() throws Exception { |
| KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); |
| keyGen.initialize(1024, SecureRandom.getInstance("SHA1PRNG")); |
| Cipher cipher = Cipher.getInstance("RSA/NONE/OAEPPadding"); |
| cipher.init(Cipher.ENCRYPT_MODE, keyGen.generateKeyPair().getPublic()); |
| cipher.doFinal(new byte[] {1,2,3,4}); |
| } |
| |
| /* |
| * Check that two AAD updates are equivalent to one. |
| * http://b/27371173 |
| */ |
| public void test_AESGCMNoPadding_UpdateAADTwice_Success() throws Exception { |
| SecretKeySpec key = new SecretKeySpec(new byte[16], "AES"); |
| GCMParameterSpec spec = new GCMParameterSpec(128, new byte[12]); |
| Cipher c1 = Cipher.getInstance("AES/GCM/NoPadding"); |
| Cipher c2 = Cipher.getInstance("AES/GCM/NoPadding"); |
| |
| c1.init(Cipher.ENCRYPT_MODE, key, spec); |
| c1.updateAAD(new byte[] { |
| 0x01, 0x02, 0x03, 0x04, 0x05, |
| }); |
| c1.updateAAD(new byte[] { |
| 0x06, 0x07, 0x08, 0x09, 0x10, |
| }); |
| |
| c2.init(Cipher.ENCRYPT_MODE, key, spec); |
| c2.updateAAD(new byte[] { |
| 0x01, 0x02, 0x03, 0x04, 0x05, |
| 0x06, 0x07, 0x08, 0x09, 0x10, |
| }); |
| |
| assertEquals(Arrays.toString(c1.doFinal()), Arrays.toString(c2.doFinal())); |
| } |
| |
| /* |
| * Check that GCM encryption with old and new instances update correctly. |
| * http://b/26694388 |
| */ |
| public void test_AESGCMNoPadding_Reuse_Success() throws Exception { |
| SecretKeySpec key = new SecretKeySpec(new byte[16], "AES"); |
| GCMParameterSpec spec = new GCMParameterSpec(128, new byte[12]); |
| Cipher c1 = Cipher.getInstance("AES/GCM/NoPadding"); |
| Cipher c2 = Cipher.getInstance("AES/GCM/NoPadding"); |
| |
| // Pollute the c1 cipher with AAD |
| c1.init(Cipher.ENCRYPT_MODE, key, spec); |
| c1.updateAAD(new byte[] { |
| 0x01, 0x02, 0x03, 0x04, 0x05, |
| }); |
| |
| // Now init each again and make sure the outputs are the same |
| c1.init(Cipher.ENCRYPT_MODE, key, spec); |
| c2.init(Cipher.ENCRYPT_MODE, key, spec); |
| |
| byte[] aad = new byte[] { |
| 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, |
| }; |
| c1.updateAAD(aad); |
| c2.updateAAD(aad); |
| |
| assertEquals(Arrays.toString(c1.doFinal()), Arrays.toString(c2.doFinal())); |
| |
| // .doFinal should also reset the state, so check that as well. |
| byte[] aad2 = new byte[] { |
| 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, |
| }; |
| |
| Cipher c3 = Cipher.getInstance("AES/GCM/NoPadding"); |
| c3.init(Cipher.ENCRYPT_MODE, key, spec); |
| |
| c1.updateAAD(aad2); |
| c3.updateAAD(aad2); |
| assertEquals(Arrays.toString(c1.doFinal()), Arrays.toString(c3.doFinal())); |
| } |
| |
| /** |
| * http://b/27224566 |
| * http://b/27994930 |
| * Check that a PBKDF2WITHHMACSHA1 secret key factory works well with a |
| * PBEWITHSHAAND128BITAES-CBC-BC cipher. The former is PKCS5 and the latter is PKCS12, and so |
| * mixing them is not recommended. However, until 1.52 BouncyCastle was accepting this mixture, |
| * assuming the IV was a 0 vector. Some apps still use this functionality. This |
| * compatibility is likely to be removed in later versions of Android. |
| * TODO(27995180): consider whether we keep this compatibility. Consider whether we only allow |
| * if an IV is passed in the parameters. |
| */ |
| public void test_PBKDF2WITHHMACSHA1_SKFactory_and_PBEAESCBC_Cipher_noIV() throws Exception { |
| byte[] plaintext = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, |
| 17, 18, 19 }; |
| byte[] ciphertext = new byte[] { 92, -65, -128, 16, -102, -115, -44, 52, 16, 124, -34, |
| -45, 58, -70, -17, 127, 119, -67, 87, 91, 63, -13, -40, 9, 97, -17, -71, 97, 10, |
| -61, -19, -73 }; |
| SecretKeyFactory skf = |
| SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA1"); |
| PBEKeySpec pbeks = new PBEKeySpec("password".toCharArray(), |
| "salt".getBytes(), |
| 100, 128); |
| SecretKey secretKey = skf.generateSecret(pbeks); |
| |
| Cipher cipher = |
| Cipher.getInstance("PBEWITHSHAAND128BITAES-CBC-BC"); |
| PBEParameterSpec paramSpec = new PBEParameterSpec("salt".getBytes(), 100); |
| cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec); |
| assertEquals(Arrays.toString(ciphertext), Arrays.toString(cipher.doFinal(plaintext))); |
| |
| secretKey = skf.generateSecret(pbeks); |
| cipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec); |
| assertEquals(Arrays.toString(plaintext), Arrays.toString(cipher.doFinal(ciphertext))); |
| } |
| |
| /** |
| * http://b/27224566 |
| * http://b/27994930 |
| * Check that a PBKDF2WITHHMACSHA1 secret key factory works well with a |
| * PBEWITHSHAAND128BITAES-CBC-BC cipher. The former is PKCS5 and the latter is PKCS12, and so |
| * mixing them is not recommended. However, until 1.52 BouncyCastle was accepting this mixture, |
| * assuming the IV was a 0 vector. Some apps still use this functionality. This |
| * compatibility is likely to be removed in later versions of Android. |
| * TODO(27995180): consider whether we keep this compatibility. Consider whether we only allow |
| * if an IV is passed in the parameters. |
| */ |
| public void test_PBKDF2WITHHMACSHA1_SKFactory_and_PBEAESCBC_Cipher_withIV() throws Exception { |
| byte[] plaintext = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, |
| 17, 18, 19 }; |
| byte[] ciphertext = { 68, -87, 71, -6, 32, -77, 124, 3, 35, -26, 96, -16, 100, -17, 52, -32, |
| 110, 26, -117, 112, -25, -113, -58, -30, 19, -46, -21, 59, -126, -8, -70, -89 }; |
| byte[] iv = new byte[] { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; |
| SecretKeyFactory skf = |
| SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA1"); |
| PBEKeySpec pbeks = new PBEKeySpec("password".toCharArray(), |
| "salt".getBytes(), |
| 100, 128); |
| SecretKey secretKey = skf.generateSecret(pbeks); |
| Cipher cipher = |
| Cipher.getInstance("PBEWITHSHAAND128BITAES-CBC-BC"); |
| cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv)); |
| assertEquals(Arrays.toString(ciphertext), Arrays.toString(cipher.doFinal(plaintext))); |
| |
| secretKey = skf.generateSecret(pbeks); |
| cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); |
| assertEquals(Arrays.toString(plaintext), Arrays.toString(cipher.doFinal(ciphertext))); |
| } |
| |
| private static Cipher createAesCipher(int opmode) { |
| try { |
| SecretKey key = new SecretKeySpec(AES_128_KEY, "AES"); |
| final Cipher c = Cipher.getInstance("AES/ECB/NoPadding"); |
| c.init(opmode, key); |
| return c; |
| } catch (Exception e) { |
| fail("Unexpected Exception: " + e.getMessage()); |
| return null; // unreachable |
| } |
| } |
| |
| /** |
| * Asserts that running the given runnable results in an IllegalStateException |
| */ |
| private static void assertIllegalStateException(String failureMessage, Runnable runnable) { |
| try { |
| runnable.run(); |
| fail(failureMessage); |
| } catch (IllegalStateException expected) { |
| // expected |
| } |
| } |
| |
| /** |
| * http://b/29038928 |
| * If in a second call to init the current spi doesn't support the new specified key, look for |
| * another suitable spi. |
| */ |
| public void test_init_onKeyTypeChange_reInitCipher() throws Exception { |
| Provider mockProvider = new MockProvider("MockProvider") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.SpecificKeyTypes.class.getName()); |
| } |
| }; |
| Provider mockProvider2 = new MockProvider("MockProvider2") { |
| public void setup() { |
| put("Cipher.FOO", MockCipherSpi.SpecificKeyTypes2.class.getName()); |
| } |
| }; |
| try { |
| Security.addProvider(mockProvider); |
| Security.addProvider(mockProvider2); |
| Cipher cipher = Cipher.getInstance("FOO"); |
| cipher.init(Cipher.ENCRYPT_MODE, new MockKey()); |
| assertEquals("MockProvider", cipher.getProvider().getName()); |
| // Using a different key... |
| cipher.init(Cipher.ENCRYPT_MODE, new MockKey2()); |
| // ...results in a different provider. |
| assertEquals("MockProvider2", cipher.getProvider().getName()); |
| } finally { |
| Security.removeProvider(mockProvider.getName()); |
| Security.removeProvider(mockProvider2.getName()); |
| } |
| } |
| |
| /** |
| * http://b/29038928 |
| * If in a second call to init the current spi doesn't support the new specified |
| * {@link AlgorithmParameterSpec}, look for another suitable spi. |
| */ |
| public void test_init_onAlgorithmParameterTypeChange_reInitCipher() throws Exception { |
| Provider mockProvider = new MockProvider("MockProvider") { |
| public void setup() { |
| put("Cipher.FOO", |
| MockCipherSpi.SpecificAlgorithmParameterSpecTypes.class.getName()); |
| } |
| }; |
| Provider mockProvider2 = new MockProvider("MockProvider2") { |
| public void setup() { |
| put("Cipher.FOO", |
| MockCipherSpi.SpecificAlgorithmParameterSpecTypes2.class.getName()); |
| } |
| }; |
| try { |
| Security.addProvider(mockProvider); |
| Security.addProvider(mockProvider2); |
| Cipher cipher = Cipher.getInstance("FOO"); |
| cipher.init(Cipher.ENCRYPT_MODE, |
| new MockKey(), |
| new MockCipherSpi.MockAlgorithmParameterSpec()); |
| assertEquals("MockProvider", cipher.getProvider().getName()); |
| // Using a different AlgorithmParameterSpec... |
| cipher.init(Cipher.ENCRYPT_MODE, |
| new MockKey(), |
| new MockCipherSpi.MockAlgorithmParameterSpec2()); |
| // ...results in a different provider. |
| assertEquals("MockProvider2", cipher.getProvider().getName()); |
| } finally { |
| Security.removeProvider(mockProvider.getName()); |
| Security.removeProvider(mockProvider2.getName()); |
| } |
| } |
| |
| /** |
| * http://b/29038928 |
| * If in a second call to init the current spi doesn't support the new specified |
| * {@link AlgorithmParameters}, look for another suitable spi. |
| */ |
| public void test_init_onAlgorithmParametersChange_reInitCipher() throws Exception { |
| Provider mockProvider = new MockProvider("MockProvider") { |
| public void setup() { |
| put("Cipher.FOO", |
| MockCipherSpi.SpecificAlgorithmParameterAesAlgorithm.class.getName()); |
| } |
| }; |
| Provider mockProvider2 = new MockProvider("MockProvider2") { |
| public void setup() { |
| put("Cipher.FOO", |
| MockCipherSpi.SpecificAlgorithmParametersDesAlgorithm.class.getName()); |
| } |
| }; |
| try { |
| Security.addProvider(mockProvider); |
| Security.addProvider(mockProvider2); |
| Cipher cipher = Cipher.getInstance("FOO"); |
| cipher.init(Cipher.ENCRYPT_MODE, |
| new MockKey(), |
| AlgorithmParameters.getInstance("AES")); |
| assertEquals("MockProvider", cipher.getProvider().getName()); |
| // Using a different AlgorithmParameters... |
| cipher.init(Cipher.ENCRYPT_MODE, |
| new MockKey(), |
| AlgorithmParameters.getInstance("DES")); |
| // ...results in a different provider. |
| assertEquals("MockProvider2", cipher.getProvider().getName()); |
| } finally { |
| Security.removeProvider(mockProvider.getName()); |
| Security.removeProvider(mockProvider2.getName()); |
| } |
| } |
| } |