vetalitet
vetalitet

Reputation: 703

Cannot encrypt/decrypt string using Java/Kotlin

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

Answers (1)

Robert
Robert

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

Related Questions