I am currently registering the BouncyCastleProvider to JCE and installing the Unlimited Strength Policy in my Java Runtime. Because this enforces me to ship the runtime along with the product, I'd like to switch to BouncyCastle's lightweight API.
Unfortunately, the lightweight API comes along poorly documented, so I'm struggling on my way to setup an exact equivalence of the "PBEWITHSHA256AND256BITAES-CBC-BC" algorithm.
After delving into BouncyCastle's source and searching SO I have written a small test util which doesn't return the expected contents:
public class AESCipherTest {
private static final String data = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, " +
"sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, " +
"sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet " +
"clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem " +
"ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor " +
"invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et " +
"accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata " +
"sanctus est Lorem ipsum dolor sit amet.";
private static final String password = "MySuperStrongPassword";
private static final byte[] salt = "MakeItSpicey".getBytes();
private static final String jce_algorithm = "PBEWITHSHA256AND256BITAES-CBC-BC";
public static void main(String[] args) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
File file = new File("D:\\test.dat");
file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);
OutputStream cos = encryptWithJCE(fos, password);
cos.write(data.getBytes());
cos.flush();
cos.close();
FileInputStream fis = new FileInputStream(file);
InputStream cis = decryptWithBCLWA(fis, password);
byte[] readByteData = new byte[data.getBytes().length];
cis.read(readByteData);
cis.close();
String readData = new String(readByteData);
System.out.println(readData);
}
public static OutputStream encryptWithJCE(OutputStream os, String password) throws Exception {
javax.crypto.spec.PBEParameterSpec pbeParamSpec = new javax.crypto.spec.PBEParameterSpec(salt, 20);
javax.crypto.spec.PBEKeySpec pbeKeySpec = new javax.crypto.spec.PBEKeySpec(password.toCharArray());
javax.crypto.SecretKeyFactory secretKeyFactory = javax.crypto.SecretKeyFactory.getInstance(jce_algorithm);
javax.crypto.SecretKey secretKey = secretKeyFactory.generateSecret(pbeKeySpec);
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(jce_algorithm);
cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, secretKey, pbeParamSpec);
OutputStream fOutputStream = new FilterOutputStream(
new BufferedOutputStream(os)) {
@Override
public void close() throws IOException {
// do nothing
}
};
return new javax.crypto.CipherOutputStream(fOutputStream, cipher);
}
public static InputStream decryptWithBCLWA(InputStream inputStream, String password) throws Exception {
org.bouncycastle.crypto.generators.PKCS12ParametersGenerator generator = new org.bouncycastle.crypto.generators.PKCS12ParametersGenerator(new org.bouncycastle.crypto.digests.SHA256Digest());
char[] passwordChars = password.toCharArray();
byte[] pkcs12PasswordToBytes = org.bouncycastle.crypto.PBEParametersGenerator.PKCS12PasswordToBytes(passwordChars);
generator.init(pkcs12PasswordToBytes, salt, 20);
org.bouncycastle.crypto.modes.CBCBlockCipher cbcBlockCipher = new org.bouncycastle.crypto.modes.CBCBlockCipher(new org.bouncycastle.crypto.engines.AESEngine());
org.bouncycastle.crypto.params.ParametersWithIV cipherParameters = (org.bouncycastle.crypto.params.ParametersWithIV) generator.generateDerivedParameters(256, 128);
cbcBlockCipher.init(false, cipherParameters);
org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher aesCipher = new org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher(cbcBlockCipher, new org.bouncycastle.crypto.paddings.PKCS7Padding());
return new org.bouncycastle.crypto.io.CipherInputStream(inputStream, aesCipher);
}}
What am I missing? Any help is greatly appreciated!
Update
There's still one piece of old code remaining which needs transition from JCE to BC lightweight API:
byte[] keyBytes = ... // password in bytes
javax.crypto.spec.SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
javax.crypto.Cipher cipher = Cipher.getInstance("PBEWITHSHA256AND128BITAES-CBC-BC");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
return new javax.crypto.CipherInputStream(in, cipher);
I am aware of the oddness of mixing an AES key with PBE, but as previously outlined it is old code which used to de/encrypt data and now I have to be able to read that encrypted data with BC lightweight API. Here I struggle with SecretKeySpec - is there something similar in BC lightweight API?