【问题标题】:AES-256-CBC in JavaJava 中的 AES-256-CBC
【发布时间】:2017-10-19 16:59:28
【问题描述】:

我正在尝试编写一个简单的 Java 程序,该程序将使用 AES-256-CBC 加密纯文本。有课:

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class AesCBC {
    private byte[] key;
    private byte[] iv;

    private static final String ALGORITHM="AES";

    public AesCBC(byte[] key, byte[] iv) {
        this.key = key;
        this.iv = iv;
    }

    public byte[] encrypt(byte[] plainText) throws Exception{
        SecretKeySpec secretKey=new SecretKeySpec(key,ALGORITHM);
        IvParameterSpec ivParameterSpec=new IvParameterSpec(iv);
        Cipher cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE,secretKey,ivParameterSpec);
        return cipher.doFinal(plainText);
    }

    public byte[] getKey() {
        return key;
    }

    public void setKey(byte[] key) {
        this.key = key;
    }

    public byte[] getIv() {
        return iv;
    }

    public void setIv(byte[] iv) {
        this.iv = iv;
    }
}

还有可能的用法:

byte[] test="a".getBytes();

byte[] key=DatatypeConverter.parseHexBinary("b38b730d4cc721156e3760d1d58546ce697adc939188e4c6a80f0e24e032b9b7");
byte[] iv=DatatypeConverter.parseHexBinary("064df9633d9f5dd0b5614843f6b4b059");
AesCBC aes=new AesCBC(key,iv);
try{
    String result=DatatypeConverter.printBase64Binary(aes.encrypt(test));
    System.out.println(result);
}catch(Exception e){
    e.printStackTrace();
}

我的输出是VTUOJJp38Tk+P5ikR4YLfw==,但是当我执行这个命令时:

/usr/bin/openssl enc -A -aes-256-cbc -base64 -K "b38b730d4cc721156e3760d1d58546ce697adc939188e4c6a80f0e24e032b9b7" -iv "064df9633d9f5dd0b5614843f6b4b059" <<< "a"

我得到的东西与 Java 程序(Y65q9DFdR3k1XcWhA2AO2Q==)不同。可悲的是,我不知道为什么结果不一样,因为我使用相同的算法和相同的密钥和 iv。这是否意味着我的 Java 程序不能正常工作?任何帮助将不胜感激。

【问题讨论】:

  • 您是否尝试过使用 Java 和/或 OpenSSL 解密 Java 输出?如果您再次使用 OpenSSL 加密,您会得到相同的输出吗?根据底部附近的 openssl enc 帮助页面 (wiki.openssl.org/index.php/Enc),“所有加盐选项也已过时。”我相信如果您使用密钥,OpenSSL 将始终为您的结果加盐。

标签: java encryption cryptography aes


【解决方案1】:

两种方式都可以正常工作,但是您加密的内容不同。

此处的字符串语法 (&lt;&lt;&lt;) 在字符串中添加换行符。所以Java输出是加密“a”的结果,命令行输出是加密“a\n”的结果(即字符a后跟换行符)。

从命令行试试这个:

printf "a" | /usr/bin/openssl enc -aes-256-cbc -base64 -K "b38b730d4cc721156e3760d1d58546ce697adc939188e4c6a80f0e24e032b9b7" -iv "064df9633d9f5dd0b5614843f6b4b059"

结果是VTUOJJp38Tk+P5ikR4YLfw==,与您的 Java 结果相匹配。

【讨论】:

    【解决方案2】:

    Java 结果正确,见AES CALCULATOR。

    因此 openssl 命令行加密不正确,请仔细阅读手册页。

    请注意,我在输入数据中手动添加了 PKCS#7 填充。
    十六进制的VTUOJJp38Tk+P5ikR4YLfw== 也是55350E249A77F1393E3F98A447860B7F

    【讨论】:

      【解决方案3】:

      很好地记录和解释。精彩的例子。如果数据是 ASCII 而不是十六进制,您可能需要扩展您的代码。

      // when data is ASCII
      byte[] key="abcdefghi123456".getBytes();
      byte[] iv="1234567890123456".getBytes();
      

      【讨论】:

      • 在不使用固定标准字符集(例如“UTF-8”)的情况下从字符串转换为字节数组可能不是最好的主意
      猜你喜欢
      • 1970-01-01
      • 2022-08-17
      • 2022-11-16
      • 2019-01-30
      • 2014-01-13
      • 2013-08-11
      • 1970-01-01
      • 1970-01-01
      • 2014-07-11
      相关资源
      最近更新 更多