summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Carlstrom <bdc@google.com>2013-01-30 05:52:33 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2013-01-30 05:52:33 +0000
commitb8bddcfe1c0fdb5fd26a0285673f7d4d488dbab7 (patch)
tree0680698559d75d295e856044f26fb9aef64e1b96
parent6c392aa76b14c3bc3bab3b0c1209d52febab621a (diff)
parentaea1f1224e7ad62991b68c485f086abcb289f82b (diff)
downloadandroid_external_bouncycastle-b8bddcfe1c0fdb5fd26a0285673f7d4d488dbab7.tar.gz
android_external_bouncycastle-b8bddcfe1c0fdb5fd26a0285673f7d4d488dbab7.tar.bz2
android_external_bouncycastle-b8bddcfe1c0fdb5fd26a0285673f7d4d488dbab7.zip
Merge "Restore PBE Cipher wrap and unwrap support from upstream"
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java110
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java119
-rw-r--r--bouncycastle.config2
-rwxr-xr-ximport_bouncycastle.sh2
-rw-r--r--patches/CipherSpi-engineWrap.patch303
-rw-r--r--patches/README11
6 files changed, 543 insertions, 4 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java
index 2205a26..ca655cf 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java
@@ -5,9 +5,15 @@ import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.InvalidParameterException;
import java.security.Key;
+import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
@@ -22,7 +28,9 @@ import javax.crypto.spec.PBEParameterSpec;
// import javax.crypto.spec.RC2ParameterSpec;
// import javax.crypto.spec.RC5ParameterSpec;
// END android-removed
+import javax.crypto.spec.SecretKeySpec;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.CipherParameters;
@@ -779,6 +787,108 @@ public class JCEBlockCipher
return "CCM".equals(modeName) || "EAX".equals(modeName) || "GCM".equals(modeName);
}
+ protected byte[] engineWrap(
+ Key key)
+ throws IllegalBlockSizeException, InvalidKeyException
+ {
+ byte[] encoded = key.getEncoded();
+ if (encoded == null)
+ {
+ throw new InvalidKeyException("Cannot wrap key, null encoding.");
+ }
+
+ try
+ {
+ return engineDoFinal(encoded, 0, encoded.length);
+ }
+ catch (BadPaddingException e)
+ {
+ throw new IllegalBlockSizeException(e.getMessage());
+ }
+ }
+
+ protected Key engineUnwrap(
+ byte[] wrappedKey,
+ String wrappedKeyAlgorithm,
+ int wrappedKeyType)
+ throws InvalidKeyException
+ {
+ byte[] encoded;
+ try
+ {
+ encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
+ }
+ catch (BadPaddingException e)
+ {
+ throw new InvalidKeyException(e.getMessage());
+ }
+ catch (IllegalBlockSizeException e2)
+ {
+ throw new InvalidKeyException(e2.getMessage());
+ }
+
+ if (wrappedKeyType == Cipher.SECRET_KEY)
+ {
+ return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
+ }
+ else if (wrappedKeyAlgorithm.equals("") && wrappedKeyType == Cipher.PRIVATE_KEY)
+ {
+ /*
+ * The caller doesn't know the algorithm as it is part of
+ * the encrypted data.
+ */
+ try
+ {
+ PrivateKeyInfo in = PrivateKeyInfo.getInstance(encoded);
+
+ PrivateKey privKey = BouncyCastleProvider.getPrivateKey(in);
+
+ if (privKey != null)
+ {
+ return privKey;
+ }
+ else
+ {
+ throw new InvalidKeyException("algorithm " + in.getPrivateKeyAlgorithm().getAlgorithm() + " not supported");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("Invalid key encoding.");
+ }
+ }
+ else
+ {
+ try
+ {
+ KeyFactory kf = KeyFactory.getInstance(wrappedKeyAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
+
+ if (wrappedKeyType == Cipher.PUBLIC_KEY)
+ {
+ return kf.generatePublic(new X509EncodedKeySpec(encoded));
+ }
+ else if (wrappedKeyType == Cipher.PRIVATE_KEY)
+ {
+ return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
+ }
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new InvalidKeyException("Unknown key type " + e.getMessage());
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new InvalidKeyException("Unknown key type " + e.getMessage());
+ }
+ catch (InvalidKeySpecException e2)
+ {
+ throw new InvalidKeyException("Unknown key type " + e2.getMessage());
+ }
+
+ throw new InvalidKeyException("Unknown key type " + wrappedKeyType);
+ }
+ }
+
/*
* The ciphers that inherit from us.
*/
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java
index 16a14ec..4600679 100644
--- a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java
@@ -4,11 +4,20 @@ import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.ShortBufferException;
@@ -18,7 +27,9 @@ import javax.crypto.spec.PBEParameterSpec;
// import javax.crypto.spec.RC2ParameterSpec;
// import javax.crypto.spec.RC5ParameterSpec;
// END android-removed
+import javax.crypto.spec.SecretKeySpec;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
@@ -347,7 +358,8 @@ public class JCEStreamCipher
protected byte[] engineDoFinal(
byte[] input,
int inputOffset,
- int inputLen)
+ int inputLen)
+ throws BadPaddingException, IllegalBlockSizeException
{
if (inputLen != 0)
{
@@ -368,7 +380,8 @@ public class JCEStreamCipher
int inputOffset,
int inputLen,
byte[] output,
- int outputOffset)
+ int outputOffset)
+ throws BadPaddingException
{
if (inputLen != 0)
{
@@ -380,6 +393,108 @@ public class JCEStreamCipher
return inputLen;
}
+ protected byte[] engineWrap(
+ Key key)
+ throws IllegalBlockSizeException, InvalidKeyException
+ {
+ byte[] encoded = key.getEncoded();
+ if (encoded == null)
+ {
+ throw new InvalidKeyException("Cannot wrap key, null encoding.");
+ }
+
+ try
+ {
+ return engineDoFinal(encoded, 0, encoded.length);
+ }
+ catch (BadPaddingException e)
+ {
+ throw new IllegalBlockSizeException(e.getMessage());
+ }
+ }
+
+ protected Key engineUnwrap(
+ byte[] wrappedKey,
+ String wrappedKeyAlgorithm,
+ int wrappedKeyType)
+ throws InvalidKeyException
+ {
+ byte[] encoded;
+ try
+ {
+ encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
+ }
+ catch (BadPaddingException e)
+ {
+ throw new InvalidKeyException(e.getMessage());
+ }
+ catch (IllegalBlockSizeException e2)
+ {
+ throw new InvalidKeyException(e2.getMessage());
+ }
+
+ if (wrappedKeyType == Cipher.SECRET_KEY)
+ {
+ return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
+ }
+ else if (wrappedKeyAlgorithm.equals("") && wrappedKeyType == Cipher.PRIVATE_KEY)
+ {
+ /*
+ * The caller doesn't know the algorithm as it is part of
+ * the encrypted data.
+ */
+ try
+ {
+ PrivateKeyInfo in = PrivateKeyInfo.getInstance(encoded);
+
+ PrivateKey privKey = BouncyCastleProvider.getPrivateKey(in);
+
+ if (privKey != null)
+ {
+ return privKey;
+ }
+ else
+ {
+ throw new InvalidKeyException("algorithm " + in.getPrivateKeyAlgorithm().getAlgorithm() + " not supported");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("Invalid key encoding.");
+ }
+ }
+ else
+ {
+ try
+ {
+ KeyFactory kf = KeyFactory.getInstance(wrappedKeyAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
+
+ if (wrappedKeyType == Cipher.PUBLIC_KEY)
+ {
+ return kf.generatePublic(new X509EncodedKeySpec(encoded));
+ }
+ else if (wrappedKeyType == Cipher.PRIVATE_KEY)
+ {
+ return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
+ }
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new InvalidKeyException("Unknown key type " + e.getMessage());
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new InvalidKeyException("Unknown key type " + e.getMessage());
+ }
+ catch (InvalidKeySpecException e2)
+ {
+ throw new InvalidKeyException("Unknown key type " + e2.getMessage());
+ }
+
+ throw new InvalidKeyException("Unknown key type " + wrappedKeyType);
+ }
+ }
+
/*
* The ciphers that inherit from us.
*/
diff --git a/bouncycastle.config b/bouncycastle.config
index 7ee682e..c31204f 100644
--- a/bouncycastle.config
+++ b/bouncycastle.config
@@ -592,5 +592,5 @@ NEEDED_BCPROV_SOURCES="org"
NEEDED_BCPKIX_SOURCES="org"
# list of patch files to apply in the given order
-BOUNCYCASTLE_BCPROV_PATCHES="patches/bcprov.patch"
+BOUNCYCASTLE_BCPROV_PATCHES="patches/bcprov.patch patches/CipherSpi-engineWrap.patch"
BOUNCYCASTLE_BCPKIX_PATCHES="patches/bcpkix.patch"
diff --git a/import_bouncycastle.sh b/import_bouncycastle.sh
index 5cbd504..a97b060 100755
--- a/import_bouncycastle.sh
+++ b/import_bouncycastle.sh
@@ -235,7 +235,7 @@ function applypatches () {
# Apply appropriate patches
for i in $bouncycastle_patches; do
echo "Applying patch $i"
- patch -p1 < ../$i || die "Could not apply patches/$i. Fix source and run: $0 regenerate patches/$i"
+ patch -p1 < ../$i || die "Could not apply patches/$i. Fix source and run: $0 regenerate $i"
# make sure no unneeded sources got into the patch
problem=0
diff --git a/patches/CipherSpi-engineWrap.patch b/patches/CipherSpi-engineWrap.patch
new file mode 100644
index 0000000..1df8688
--- /dev/null
+++ b/patches/CipherSpi-engineWrap.patch
@@ -0,0 +1,303 @@
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCEBlockCipher.java 2012/04/05 10:57:52 1.31
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCEBlockCipher.java 2013/01/02 08:01:03 1.32
+@@ -5,9 +5,15 @@
+ import java.security.InvalidKeyException;
+ import java.security.InvalidParameterException;
+ import java.security.Key;
++import java.security.KeyFactory;
+ import java.security.NoSuchAlgorithmException;
++import java.security.NoSuchProviderException;
++import java.security.PrivateKey;
+ import java.security.SecureRandom;
+ import java.security.spec.AlgorithmParameterSpec;
++import java.security.spec.InvalidKeySpecException;
++import java.security.spec.PKCS8EncodedKeySpec;
++import java.security.spec.X509EncodedKeySpec;
+
+ import javax.crypto.BadPaddingException;
+ import javax.crypto.Cipher;
+@@ -20,9 +26,11 @@
+ import javax.crypto.spec.PBEParameterSpec;
+ // BEGIN android-removed
+ // import javax.crypto.spec.RC2ParameterSpec;
+ // import javax.crypto.spec.RC5ParameterSpec;
+ // END android-removed
++import javax.crypto.spec.SecretKeySpec;
+
++import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+ import org.bouncycastle.crypto.BlockCipher;
+ import org.bouncycastle.crypto.BufferedBlockCipher;
+ import org.bouncycastle.crypto.CipherParameters;
+@@ -739,6 +747,108 @@
+ return "CCM".equals(modeName) || "EAX".equals(modeName) || "GCM".equals(modeName);
+ }
+
++ protected byte[] engineWrap(
++ Key key)
++ throws IllegalBlockSizeException, InvalidKeyException
++ {
++ byte[] encoded = key.getEncoded();
++ if (encoded == null)
++ {
++ throw new InvalidKeyException("Cannot wrap key, null encoding.");
++ }
++
++ try
++ {
++ return engineDoFinal(encoded, 0, encoded.length);
++ }
++ catch (BadPaddingException e)
++ {
++ throw new IllegalBlockSizeException(e.getMessage());
++ }
++ }
++
++ protected Key engineUnwrap(
++ byte[] wrappedKey,
++ String wrappedKeyAlgorithm,
++ int wrappedKeyType)
++ throws InvalidKeyException
++ {
++ byte[] encoded;
++ try
++ {
++ encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
++ }
++ catch (BadPaddingException e)
++ {
++ throw new InvalidKeyException(e.getMessage());
++ }
++ catch (IllegalBlockSizeException e2)
++ {
++ throw new InvalidKeyException(e2.getMessage());
++ }
++
++ if (wrappedKeyType == Cipher.SECRET_KEY)
++ {
++ return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
++ }
++ else if (wrappedKeyAlgorithm.equals("") && wrappedKeyType == Cipher.PRIVATE_KEY)
++ {
++ /*
++ * The caller doesn't know the algorithm as it is part of
++ * the encrypted data.
++ */
++ try
++ {
++ PrivateKeyInfo in = PrivateKeyInfo.getInstance(encoded);
++
++ PrivateKey privKey = BouncyCastleProvider.getPrivateKey(in);
++
++ if (privKey != null)
++ {
++ return privKey;
++ }
++ else
++ {
++ throw new InvalidKeyException("algorithm " + in.getPrivateKeyAlgorithm().getAlgorithm() + " not supported");
++ }
++ }
++ catch (Exception e)
++ {
++ throw new InvalidKeyException("Invalid key encoding.");
++ }
++ }
++ else
++ {
++ try
++ {
++ KeyFactory kf = KeyFactory.getInstance(wrappedKeyAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
++
++ if (wrappedKeyType == Cipher.PUBLIC_KEY)
++ {
++ return kf.generatePublic(new X509EncodedKeySpec(encoded));
++ }
++ else if (wrappedKeyType == Cipher.PRIVATE_KEY)
++ {
++ return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
++ }
++ }
++ catch (NoSuchProviderException e)
++ {
++ throw new InvalidKeyException("Unknown key type " + e.getMessage());
++ }
++ catch (NoSuchAlgorithmException e)
++ {
++ throw new InvalidKeyException("Unknown key type " + e.getMessage());
++ }
++ catch (InvalidKeySpecException e2)
++ {
++ throw new InvalidKeyException("Unknown key type " + e2.getMessage());
++ }
++
++ throw new InvalidKeyException("Unknown key type " + wrappedKeyType);
++ }
++ }
++
+ /*
+ * The ciphers that inherit from us.
+ */
+--- bcprov-jdk15on-147.orig/org/bouncycastle/jce/provider/JCEStreamCipher.java 2011/08/25 06:17:08 1.15
++++ bcprov-jdk15on-147/org/bouncycastle/jce/provider/JCEStreamCipher.java 2013/01/29 05:42:31 1.16
+@@ -4,11 +4,20 @@
+ import java.security.InvalidAlgorithmParameterException;
+ import java.security.InvalidKeyException;
+ import java.security.Key;
++import java.security.KeyFactory;
++import java.security.NoSuchAlgorithmException;
++import java.security.NoSuchProviderException;
++import java.security.PrivateKey;
+ import java.security.SecureRandom;
+ import java.security.spec.AlgorithmParameterSpec;
++import java.security.spec.InvalidKeySpecException;
++import java.security.spec.PKCS8EncodedKeySpec;
++import java.security.spec.X509EncodedKeySpec;
+
++import javax.crypto.BadPaddingException;
+ import javax.crypto.Cipher;
+ import javax.crypto.CipherSpi;
++import javax.crypto.IllegalBlockSizeException;
+ import javax.crypto.NoSuchPaddingException;
+ import javax.crypto.SecretKey;
+ import javax.crypto.ShortBufferException;
+@@ -16,9 +25,11 @@
+ import javax.crypto.spec.PBEParameterSpec;
+ // BEGIN android-removed
+ // import javax.crypto.spec.RC2ParameterSpec;
+ // import javax.crypto.spec.RC5ParameterSpec;
+ // END android-removed
++import javax.crypto.spec.SecretKeySpec;
+
++import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+ import org.bouncycastle.crypto.BlockCipher;
+ import org.bouncycastle.crypto.CipherParameters;
+ import org.bouncycastle.crypto.DataLengthException;
+@@ -339,7 +350,8 @@
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+- int inputLen)
++ int inputLen)
++ throws BadPaddingException, IllegalBlockSizeException
+ {
+ if (inputLen != 0)
+ {
+@@ -360,7 +372,8 @@
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+- int outputOffset)
++ int outputOffset)
++ throws BadPaddingException
+ {
+ if (inputLen != 0)
+ {
+@@ -372,6 +385,108 @@
+ return inputLen;
+ }
+
++ protected byte[] engineWrap(
++ Key key)
++ throws IllegalBlockSizeException, InvalidKeyException
++ {
++ byte[] encoded = key.getEncoded();
++ if (encoded == null)
++ {
++ throw new InvalidKeyException("Cannot wrap key, null encoding.");
++ }
++
++ try
++ {
++ return engineDoFinal(encoded, 0, encoded.length);
++ }
++ catch (BadPaddingException e)
++ {
++ throw new IllegalBlockSizeException(e.getMessage());
++ }
++ }
++
++ protected Key engineUnwrap(
++ byte[] wrappedKey,
++ String wrappedKeyAlgorithm,
++ int wrappedKeyType)
++ throws InvalidKeyException
++ {
++ byte[] encoded;
++ try
++ {
++ encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
++ }
++ catch (BadPaddingException e)
++ {
++ throw new InvalidKeyException(e.getMessage());
++ }
++ catch (IllegalBlockSizeException e2)
++ {
++ throw new InvalidKeyException(e2.getMessage());
++ }
++
++ if (wrappedKeyType == Cipher.SECRET_KEY)
++ {
++ return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
++ }
++ else if (wrappedKeyAlgorithm.equals("") && wrappedKeyType == Cipher.PRIVATE_KEY)
++ {
++ /*
++ * The caller doesn't know the algorithm as it is part of
++ * the encrypted data.
++ */
++ try
++ {
++ PrivateKeyInfo in = PrivateKeyInfo.getInstance(encoded);
++
++ PrivateKey privKey = BouncyCastleProvider.getPrivateKey(in);
++
++ if (privKey != null)
++ {
++ return privKey;
++ }
++ else
++ {
++ throw new InvalidKeyException("algorithm " + in.getPrivateKeyAlgorithm().getAlgorithm() + " not supported");
++ }
++ }
++ catch (Exception e)
++ {
++ throw new InvalidKeyException("Invalid key encoding.");
++ }
++ }
++ else
++ {
++ try
++ {
++ KeyFactory kf = KeyFactory.getInstance(wrappedKeyAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
++
++ if (wrappedKeyType == Cipher.PUBLIC_KEY)
++ {
++ return kf.generatePublic(new X509EncodedKeySpec(encoded));
++ }
++ else if (wrappedKeyType == Cipher.PRIVATE_KEY)
++ {
++ return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
++ }
++ }
++ catch (NoSuchProviderException e)
++ {
++ throw new InvalidKeyException("Unknown key type " + e.getMessage());
++ }
++ catch (NoSuchAlgorithmException e)
++ {
++ throw new InvalidKeyException("Unknown key type " + e.getMessage());
++ }
++ catch (InvalidKeySpecException e2)
++ {
++ throw new InvalidKeyException("Unknown key type " + e2.getMessage());
++ }
++
++ throw new InvalidKeyException("Unknown key type " + wrappedKeyType);
++ }
++ }
++
+ /*
+ * The ciphers that inherit from us.
+ */
diff --git a/patches/README b/patches/README
index 0caaea9..b9c9181 100644
--- a/patches/README
+++ b/patches/README
@@ -48,3 +48,14 @@ patch against Bouncy Castle's bcpkix:
The main differences involve:
- removing algorithms not in our bcprov (MD2, MD4, SHA224, RIPEMD, GOST)
- using the singleton DERNull.INSTANCE
+
+
+CipherSpi-engineWrap.patch:
+
+Fixes from upstream BouncyCastle repository for:
+ https://code.google.com/p/android/issues/detail?id=41405
+
+"added wrap/unwrap support back in."
+ http://www.bouncycastle.org/viewcvs/viewcvs.cgi/java/crypto/src/org/bouncycastle/jce/provider/JCEBlockCipher.java?r1=1.31&r2=1.32&view=patch
+"fix for JCEStreamCipher PBE wrapping"
+ http://www.bouncycastle.org/viewcvs/viewcvs.cgi/java/crypto/src/org/bouncycastle/jce/provider/JCEStreamCipher.java?r1=1.15&r2=1.16&view=patch