Reputation: 197
I am creating an application which calls a third party API, they provided PHP code and what we require is a Java code.
The PHP code is given below:
function encryptIt( $string ) {
$key = 'qJB0rGtIn5UB1xG03efyCp';
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
$encrypted = openssl_encrypt($string, 'aes-256-cbc', $key, 0, $iv);
return base64_encode($encrypted . '::' . $iv);
}
Now I changed the abouve code to java as:
private static String openssl_encrypt(String data, String strKey, String strIv) throws Exception {
SecureRandom randomSecureRandom = new SecureRandom();
Base64 base64 = new Base64();
Cipher ciper = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] ivv = new byte[ciper.getBlockSize()];
randomSecureRandom.nextBytes(ivv);
SecretKeySpec key = new SecretKeySpec(strKey.getBytes(), "AES");
IvParameterSpec iv = new IvParameterSpec(ivv, 0, ciper.getBlockSize());
// Encrypt
ciper.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] encryptedCiperBytes = ciper.doFinal(data.getBytes());
String s = new String(base64.encode(encryptedCiperBytes));
System.out.println("Ciper : " + s);
return s;
}
Actually I am not good in encryption techniques so the PHP code creates a IV code but after searching in internet I tried to create a IV code as above,
But I got the error as:
java.security.InvalidKeyException: Invalid AES key length: 22 bytes
at com.sun.crypto.provider.AESCipher.engineGetKeySize(AESCipher.java:509)
at javax.crypto.Cipher.passCryptoPermCheck(Cipher.java:1067)
at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1038)
at javax.crypto.Cipher.init(Cipher.java:1393)
at javax.crypto.Cipher.init(Cipher.java:1327)
Please help me to solve this
UPDATED:
I updated the code to :
private static String openssl_encrypt(String data) throws Exception {
SecureRandom random = new SecureRandom();
byte[] salt = new byte[16];
random.nextBytes(salt);
KeySpec spec = new PBEKeySpec("qJB0rGtIn5UB1xG03efyCp".toCharArray(), salt, 65536, 256); // AES-256
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] key = f.generateSecret(spec).getEncoded();
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
byte[] ivBytes = new byte[16];
random.nextBytes(ivBytes);
IvParameterSpec iv = new IvParameterSpec(ivBytes);
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, keySpec, iv);
byte[] encValue = c.doFinal(data.getBytes());
byte[] finalCiphertext = new byte[encValue.length+2*16];
System.arraycopy(ivBytes, 0, finalCiphertext, 0, 16);
System.arraycopy(salt, 0, finalCiphertext, 16, 16);
System.arraycopy(encValue, 0, finalCiphertext, 32, encValue.length);
String s = new String(Base64.getEncoder().encodeToString(finalCiphertext));
return s;
}
Still i got the error as :
java.security.InvalidKeyException: Illegal key size
My API providers says that thats the key!
Upvotes: 2
Views: 298
Reputation: 93968
Just like the ill-fated mcrypt
crap, openssl_encrypt
allows incorrectly sized keys. Instead of rejecting such keys, it simply fills the rest of the key with zero valued bytes ("\0"
in PHP). This is completely against any good cryptographic practice, by almost any library for higher level languages.
This is very likely due to two reasons:
-256
in the openssl
commands).To copy the flawed PHP code you therefore have to pad the key with zero bytes (until the array is 32 bytes long). In Java, that's commonly performed using the horrible Arrays.copyOf
nowadays (as it also right-pads zero bytes).
Note that the IV will of course still make sure that your encryption results never match. Instead, try to decrypt in Java and use the same scheme for encryption, making sure the IV stays random in the final code.
Keys are never strings. Keys consist of bits or - preferably - references to keys stored somewhere in secure memory. Passwords are strings however, and using PKBDF2 should indeed be preferred.
Of course, to use PBKDF2 it is required to:
Upvotes: 3