doutuo7156 2017-05-20 01:57 采纳率: 100%
浏览 331
已采纳

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

我使用以下代码对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个字符在解密值中丢失。

  • 写回答

1条回答 默认 最新

  • donglu8779 2017-05-20 03:33
    关注

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥50 易语言把MYSQL数据库中的数据添加至组合框
  • ¥20 求数据集和代码#有偿答复
  • ¥15 关于下拉菜单选项关联的问题
  • ¥20 java-OJ-健康体检
  • ¥15 rs485的上拉下拉,不会对a-b<-200mv有影响吗,就是接受时,对判断逻辑0有影响吗
  • ¥15 使用phpstudy在云服务器上搭建个人网站
  • ¥15 应该如何判断含间隙的曲柄摇杆机构,轴与轴承是否发生了碰撞?
  • ¥15 vue3+express部署到nginx
  • ¥20 搭建pt1000三线制高精度测温电路
  • ¥15 使用Jdk8自带的算法,和Jdk11自带的加密结果会一样吗,不一样的话有什么解决方案,Jdk不能升级的情况