Issue
I have used following code to encrypt and decrypt data in Java. Encryption and Decryption is working fine.
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.SecureRandom;
public class MainNew {
public static void main(String[] args) throws Exception{
String iv = getEncryptionIV();
System.out.println(" iv = "+iv);
String encryptedData= encryptWithIVandKey(iv,encryptionKey,"hello world! golang is awesome!");
System.out.println(encryptedData);
String decryptedData = decrypt (iv,encryptionKey,encryptedData);
System.out.println(decryptedData);
}
static final String encryptionKey = "rakesh1@n1111112";
static byte[] doFinal(int encryptMode, SecretKey key, String iv, byte[] bytes) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(encryptMode, key, new IvParameterSpec(DatatypeConverter.parseBase64Binary(iv)));
byte[] data = cipher.doFinal(bytes);
return data;
} catch (Exception e) {
e.printStackTrace();
System.out.println(e);
}
return null;
}
static SecretKey generateKey(String passphrase) {
SecretKey key = null;
try {
key = new SecretKeySpec(passphrase.getBytes("UTF-8"), "AES");
} catch (Exception e) {
e.printStackTrace();
System.out.println(e);
}
return key;
}
static String getEncryptionIV() {
SecureRandom random = new SecureRandom();
byte[] ivBytes = new byte[16];
random.nextBytes(ivBytes);
return DatatypeConverter.printBase64Binary(ivBytes);
}
static String encryptWithIVandKey( String iv, String passphrase, final String strToEncrypt) {
String encryptedStr = "";
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey key = generateKey(passphrase);
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(DatatypeConverter.parseBase64Binary(iv)));
encryptedStr = DatatypeConverter.printBase64Binary(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));
} catch (Exception e) {
e.printStackTrace();
System.out.println(e);
}
return encryptedStr;
}
static String decrypt(String iv, String passphrase, String ciphertext) {
try {
SecretKey key = generateKey(passphrase);
byte[] decrypted = doFinal(Cipher.DECRYPT_MODE, key, iv, DatatypeConverter.parseBase64Binary(ciphertext));
return new String(decrypted, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
System.out.println(e);
}
return "";
}
}
But if I decrypt in golang using https://play.golang.org/p/u4fip_ZW6a code. First 16 characters are missing in the decrypted value.
Solution
From the Go code you shared in your playground:
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
...
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
So as you can see, this code is expecting the first 16 bytes of the ciphertext
to be the IV.
However, in your Java code, you do just:
encryptedStr = DatatypeConverter.printBase64Binary(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));
So you encrypt the string, and that's all you are returning (and then using in the Go program).
As we saw, the Go code is removing 16 bytes from the ciphertext and that's why you are missing data.
I'd suggest you change your Java code to include the IV at the beginning of the string to match what your Go code expects.
You can change your encryptWithIVandKey
method in Java to read:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey key = generateKey(passphrase);
byte[] ivBytes = DatatypeConverter.parseBase64Binary(iv);
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(ivBytes));
byte[] encBytes = cipher.doFinal(strToEncrypt.getBytes("UTF-8"));
// concat iv + encripted bytes
byte[] concat = new byte[ivBytes.length + encBytes.length];
System.arraycopy(ivBytes, 0, concat, 0, ivBytes.length);
System.arraycopy(encBytes, 0, concat, ivBytes.length, encBytes.length);
encryptedStr = DatatypeConverter.printBase64Binary(concat);
The change here is that we are concatenating the IV + the encrypted string before encoding to Base64.
The resulting Base64 is then:
adAz5d5J3PAOuxntOe/9uMJgFHwIcdKobhRSKXwspmnxFlSlF40dtBYf9VSY34fU
And if you try that String in your Go code it will produce the output you expect.
Answered By - eugenioy
Answer Checked By - Mildred Charles (JavaFixing Admin)