Reputation: 703
I need to encrypt string on Java, and then decrypt it on Kotlin. I do following things:
encrypt string like that
private static String encrypt(String value, String password) throws NoSuchPaddingException, ... {
final SecretKeySpec secretKeySpec = new SecretKeySpec(password.getBytes(Charset.forName("UTF-8")), "AES");
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
final byte[] encryptedValue = cipher.doFinal(value.getBytes(Charset.forName("UTF-8")));
return DatatypeConverter.printBase64Binary(encryptedValue);
}
For decrypt in Kotlin I use this method:
fun String.decrypt(password: String): String {
val secretKeySpec = SecretKeySpec(password.toByteArray(), "AES")
val iv = ByteArray(16)
val charArray = password.toCharArray()
for (i in 0 until charArray.size){
iv[i] = charArray[i].toByte()
}
val ivParameterSpec = IvParameterSpec(iv)
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec)
(1) val decryptedByteValue = cipher.doFinal(Base64.decode(this, Base64.DEFAULT))
return String(decryptedByteValue)
}
In that case on line (1) I receive AEADBadTagException: mac check in GCM failed
So, I changed it a little bit
fun String.decrypt(password: String): String {
val secretKeySpec = SecretKeySpec(password.toByteArray(), "AES")
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
(2) cipher.init(Cipher.DECRYPT_MODE, secretKeySpec)
val decryptedByteValue = cipher.doFinal(Base64.decode(this, Base64.DEFAULT))
return String(decryptedByteValue)
}
In that case in line (2) I receive RuntimeException: java.security.InvalidAlgorithmParameterException: IV must be specified in GCM mode
So, after that, I changed encryption method
private static String encrypt(String value, String password) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
final SecretKeySpec secretKeySpec = new SecretKeySpec(password.getBytes(Charset.forName("UTF-8")), "AES");
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
final byte[] iv = new byte[16];
for (int i = 0; i < password.length(); i++) {
iv[i] = (byte) password.toCharArray()[0];
}
final IvParameterSpec ivSpec = new IvParameterSpec(iv);
(3) cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);
final byte[] encryptedValue = cipher.doFinal(value.getBytes(Charset.forName("UTF-8")));
return DatatypeConverter.printBase64Binary(encryptedValue);
}
But here in line (3) I receive java.security.InvalidAlgorithmParameterException: Unsupported parameter: javax.crypto.spec.IvParameterSpec@6d311334
Please help me to solve this puzzle
Upvotes: 0
Views: 2387
Reputation: 42710
Executing SecretKeySpec(password.toByteArray(), "AES")
is clearly a functionality and a security problem. AES requires a key of 16/24/32 bytes, but your password is of variable length. Never use a password as a key. Use a key derivation algorithm like PBKDF2 instead.
Regarding your error:
You are using an IvParameterSpec, however GCM does not use an IV, but a Nonce and it requires to specify the authentication tag length. Therefore you have to provide an GCMParameterSpec.
Upvotes: 4