diff options
-rw-r--r-- | crypto/src/main/java/org/conscrypt/OpenSSLCipher.java | 49 | ||||
-rw-r--r-- | luni/src/test/java/libcore/javax/crypto/CipherTest.java | 60 |
2 files changed, 100 insertions, 9 deletions
diff --git a/crypto/src/main/java/org/conscrypt/OpenSSLCipher.java b/crypto/src/main/java/org/conscrypt/OpenSSLCipher.java index 632f9e2..7acccc7 100644 --- a/crypto/src/main/java/org/conscrypt/OpenSSLCipher.java +++ b/crypto/src/main/java/org/conscrypt/OpenSSLCipher.java @@ -16,6 +16,7 @@ package org.conscrypt; +import java.io.IOException; import java.security.AlgorithmParameters; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -118,6 +119,11 @@ public abstract class OpenSSLCipher extends CipherSpi { } /** + * Returns the standard name for the particular algorithm. + */ + protected abstract String getBaseCipherName(); + + /** * Returns the OpenSSL cipher name for the particular {@code keySize} and * cipher {@code mode}. */ @@ -214,10 +220,22 @@ public abstract class OpenSSLCipher extends CipherSpi { @Override protected AlgorithmParameters engineGetParameters() { + if (iv != null && iv.length > 0) { + try { + AlgorithmParameters params = AlgorithmParameters.getInstance(getBaseCipherName()); + params.init(iv); + return params; + } catch (NoSuchAlgorithmException e) { + return null; + } catch (IOException e) { + return null; + } + } return null; } - private void engineInitInternal(int opmode, Key key, byte[] iv) throws InvalidKeyException, InvalidAlgorithmParameterException { + private void engineInitInternal(int opmode, Key key, byte[] iv, SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException { if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE) { encrypting = true; } else if (opmode == Cipher.DECRYPT_MODE || opmode == Cipher.UNWRAP_MODE) { @@ -245,9 +263,15 @@ public abstract class OpenSSLCipher extends CipherSpi { } final int ivLength = NativeCrypto.EVP_CIPHER_iv_length(cipherType); - if (iv == null) { + if (iv == null && ivLength != 0) { iv = new byte[ivLength]; - } else if (iv.length != ivLength) { + if (encrypting) { + if (random == null) { + random = new SecureRandom(); + } + random.nextBytes(iv); + } + } else if (iv != null && iv.length != ivLength) { throw new InvalidAlgorithmParameterException("expected IV length of " + ivLength); } @@ -273,7 +297,7 @@ public abstract class OpenSSLCipher extends CipherSpi { @Override protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { try { - engineInitInternal(opmode, key, null); + engineInitInternal(opmode, key, null, random); } catch (InvalidAlgorithmParameterException e) { throw new RuntimeException(e); } @@ -290,7 +314,7 @@ public abstract class OpenSSLCipher extends CipherSpi { iv = null; } - engineInitInternal(opmode, key, iv); + engineInitInternal(opmode, key, iv, random); } @Override @@ -631,6 +655,11 @@ public abstract class OpenSSLCipher extends CipherSpi { } @Override + protected String getBaseCipherName() { + return "AES"; + } + + @Override protected String getCipherName(int keyLength, Mode mode) { return "aes-" + (keyLength * 8) + "-" + mode.toString().toLowerCase(Locale.US); } @@ -721,6 +750,11 @@ public abstract class OpenSSLCipher extends CipherSpi { } @Override + protected String getBaseCipherName() { + return "DESede"; + } + + @Override protected String getCipherName(int keySize, Mode mode) { final String baseCipherName; if (keySize == 16) { @@ -780,6 +814,11 @@ public abstract class OpenSSLCipher extends CipherSpi { } @Override + protected String getBaseCipherName() { + return "ARCFOUR"; + } + + @Override protected String getCipherName(int keySize, Mode mode) { return "rc4"; } diff --git a/luni/src/test/java/libcore/javax/crypto/CipherTest.java b/luni/src/test/java/libcore/javax/crypto/CipherTest.java index dac43a2..7922a04 100644 --- a/luni/src/test/java/libcore/javax/crypto/CipherTest.java +++ b/luni/src/test/java/libcore/javax/crypto/CipherTest.java @@ -21,6 +21,7 @@ import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.math.BigInteger; import java.nio.ByteBuffer; +import java.security.AlgorithmParameters; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; @@ -778,8 +779,10 @@ public final class CipherTest extends TestCase { // Cipher.getInstance(String) Cipher c1 = Cipher.getInstance(algorithm); - assertEquals(algorithm, c1.getAlgorithm()); - test_Cipher(c1); + if (provider.equals(c1.getProvider())) { + assertEquals(algorithm, c1.getAlgorithm()); + test_Cipher(c1); + } // Cipher.getInstance(String, Provider) Cipher c2 = Cipher.getInstance(algorithm, provider); @@ -812,6 +815,23 @@ public final class CipherTest extends TestCase { 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; + } + } + c.init(encryptMode, encryptKey, encryptSpec); assertEquals(cipherID + " getBlockSize() encryptMode", getExpectedBlockSize(algorithm, encryptMode, providerName), c.getBlockSize()); @@ -826,9 +846,41 @@ public final class CipherTest extends TestCase { assertEquals(cipherID + " getOutputSize(0) decryptMode", getExpectedOutputSize(algorithm, decryptMode, providerName), c.getOutputSize(0)); - // TODO: test Cipher.getIV() + 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 { + 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; + } + } + } - // TODO: test Cipher.getParameters() + AlgorithmParameters params = c.getParameters(); + if (decryptSpec == null) { + assertNull(cipherID + " getParameters()", params); + } else if (decryptSpec instanceof IvParameterSpec) { + IvParameterSpec ivDecryptSpec = (IvParameterSpec) params.getParameterSpec(IvParameterSpec.class); + assertEquals(cipherID + " getIV()", + Arrays.toString(((IvParameterSpec) decryptSpec).getIV()), + Arrays.toString(ivDecryptSpec.getIV())); + } else if (decryptSpec instanceof PBEParameterSpec) { + // Bouncycastle seems to be schizophrenic about whther it returns this or not + if (!"BC".equals(providerName)) { + assertNotNull(cipherID + " getParameters()", params); + } + } assertNull(cipherID, c.getExemptionMechanism()); |