Java AES CBC加密和Golang解密

huangapple go评论83阅读模式
英文:

First 16 characters missing - Java AES CBC encryption and golang decryption

问题

我已经使用以下代码在Java中进行了数据加密和解密。加密和解密都正常工作。

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 "";
    }

}

但是,如果我使用https://play.golang.org/p/u4fip_ZW6a中的代码在golang中进行解密,解密后的值中缺少前16个字符。

英文:

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.

答案1

得分: 2

从您在代码播放器中分享的Go代码中可以看出:

// 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:]

因此,正如您所看到的,这段代码期望ciphertext的前16个字节是IV。

然而,在您的Java代码中,您只是这样做:

encryptedStr = DatatypeConverter.printBase64Binary(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));

因此,您只加密了字符串,这就是您返回的内容(然后在Go程序中使用)。

正如我们所看到的,Go代码从密文中删除了16个字节,这就是为什么您丢失了数据。

我建议您将Java代码更改为在字符串开头包含IV,以匹配Go代码的期望。

您可以将Java中的encryptWithIVandKey方法更改为:

        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);

这里的更改是我们在编码为Base64之前将IV和加密字符串连接起来。

生成的Base64结果是:

adAz5d5J3PAOuxntOe/9uMJgFHwIcdKobhRSKXwspmnxFlSlF40dtBYf9VSY34fU

如果您在Go代码中尝试该字符串,它将产生您期望的输出。

英文:

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.

答案2

得分: 0

这不是推荐的做法,但是尝试在加密之前在你的字符串前面添加16个空格。

英文:

This is not recommend but try adding 16 spaces to your string before encryption

huangapple
  • 本文由 发表于 2017年5月20日 09:57:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/44081175.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定