缺少前16个字符 - Java AES CBC加密和golang解密

时间:2022-08-25 18:23:37

I have used following code to encrypt and decrypt data in Java. Encryption and Decryption is working fine.

我使用以下代码来加密和解密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 "";
    }

}

But if I decrypt in golang using https://play.golang.org/p/u4fip_ZW6a code. First 16 characters are missing in the decrypted value.

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

1 个解决方案

#1


2  

From the Go code you shared in your playground:

您在游乐场分享的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:]

So as you can see, this code is expecting the first 16 bytes of the ciphertext to be the IV.

如您所见,此代码期望密文的前16个字节为IV。

However, in your Java code, you do just:

但是,在Java代码中,您只需:

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

所以你加密了字符串,这就是你要返回的所有内容(然后在Go程序中使用)。

As we saw, the Go code is removing 16 bytes from the ciphertext and that's why you are missing data.

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

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.

我建议你改变你的Java代码,在字符串的开头包含IV,以匹配你的Go代码所期望的。

You can change your encryptWithIVandKey method in Java to read:

您可以将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);

The change here is that we are concatenating the IV + the encrypted string before encoding to Base64.

这里的变化是我们在编码之前将IV +加密的字符串连接到Base64。

The resulting Base64 is then:

得到的Base64然后是:

adAz5d5J3PAOuxntOe/9uMJgFHwIcdKobhRSKXwspmnxFlSlF40dtBYf9VSY34fU

And if you try that String in your Go code it will produce the output you expect.

如果你在Go代码中尝试使用String,它将产生你期望的输出。

#1


2  

From the Go code you shared in your playground:

您在游乐场分享的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:]

So as you can see, this code is expecting the first 16 bytes of the ciphertext to be the IV.

如您所见,此代码期望密文的前16个字节为IV。

However, in your Java code, you do just:

但是,在Java代码中,您只需:

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

所以你加密了字符串,这就是你要返回的所有内容(然后在Go程序中使用)。

As we saw, the Go code is removing 16 bytes from the ciphertext and that's why you are missing data.

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

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.

我建议你改变你的Java代码,在字符串的开头包含IV,以匹配你的Go代码所期望的。

You can change your encryptWithIVandKey method in Java to read:

您可以将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);

The change here is that we are concatenating the IV + the encrypted string before encoding to Base64.

这里的变化是我们在编码之前将IV +加密的字符串连接到Base64。

The resulting Base64 is then:

得到的Base64然后是:

adAz5d5J3PAOuxntOe/9uMJgFHwIcdKobhRSKXwspmnxFlSlF40dtBYf9VSY34fU

And if you try that String in your Go code it will produce the output you expect.

如果你在Go代码中尝试使用String,它将产生你期望的输出。