【问题标题】:OpenSSL AES/CBC 256 command output does not match with the java code outputOpenSSL AES/CBC 256 命令输出与 java 代码输出不匹配
【发布时间】:2018-05-10 20:47:47
【问题描述】:

您好,我正在使用 openSSL 命令来加密和解密我的消息。现在我希望将此命令转换为 java 代码,我尝试了网络上提供的不同解决方案,但没有一个代码与结果匹配。

这是我在 cmets 中的低调的 OpenSSL 命令:

key="FB4FF1BA6F1FCC1A11B8B3910342CBD3A2BEAEB8F52E8910D9B25C0C96280EEA"

# Getting 16 digits from the iv.txt file and putting it into the bin
head -c 16 iv.txt > iv.bin

# Converting iv.bin text into the HEXA value
iv=`xxd -l 16 -p iv.bin`

# encrypt without "-a" 
openssl enc -aes-256-cbc -K $key -iv $iv -in plainKey.txt -out encryptedKey.bin

# printing encrypted results in base64 format this need to be matched with my java code.
echo "<enc>"`cat encryptedKey.bin | base64`"</enc>"

这是我在 Java 中所做的:

注意:这个来自堆栈溢出的代码接受了稍作改动的答案我也尝试了其他一些代码,但这里不能全部提及。

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

public class Test {

public static void main(String[] args) {
    try {
        runEncryption();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private static void runEncryption() throws Exception
{
    //String to be encrypted
    String plainText = "abcd@1234\n";

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

    // IV text
    String iv = "C837E1B6C3D3A7E28F47719DE0C182C9";

    // getting 16 characters of iv text
    iv = iv.substring(0,16);

    // Value of key
    String key = "FB4FF1BA6F1FCC1A11B8B3910342CBD3A2BEAEB8F52E8910D9B25C0C96280EEA";

    // Logic for converting 16 Digits of IV into HEX
    StringBuffer hexString = new StringBuffer();
    for (int i=0;i<iv.getBytes().length;i++) {
        String hex=Integer.toHexString(0xff & iv.getBytes()[i]);
        if(hex.length()==1) hexString.append('0');
        hexString.append(hex);
    }

    // Seems something wrong here because if i am passing all the bytes to keySpe like key.getBytes() it is producing exception  so i am passing 16 bytes as previous code was doing in SO
    SecretKeySpec keySpec = new SecretKeySpec(hexToBytes(key), 0, 16, "AES");
    IvParameterSpec ivSpec = new IvParameterSpec(hexToBytes(hexString.toString()));

    cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
    byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));

    String encryptedBase64 = new String(DatatypeConverter.printBase64Binary(encrypted));

    System.out.println("");
    System.out.println("Encrypted base64 = " + encryptedBase64);
}

private static byte[] hexToBytes(String s)
{
    int len = s.length();
    byte[] data = new byte[len / 2];

    for (int i = 0; i < len; i += 2)
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));

    return data;
}    
}

我正在使用 openSSL 命令生成密钥和 iv

openssl enc -aes-256-cbc -k secret -P -md sha1

这里似乎有问题,因为如果我将所有字节传递给 keySpec,比如 key.getBytes(),它会产生异常,所以我传递了 16 个字节,就像之前的代码在 SO 中所做的那样,我也在代码 cmets 中提到了这一点请就此提出建议,谢谢。

【问题讨论】:

标签: java encryption openssl cryptography encryption-symmetric


【解决方案1】:

您的代码中有几个错误

让我们假设你想要做的是

 openssl enc -aes-256-cbc -K FB4FF1BA6F1FCC1A11B8B3910342CBD3A2BEAEB8F52E8910D9B25C0C96280EEA -iv 03B13BBE886F00E00000000000000000 -base64 -in input.txt

在您的代码中,您有一些错误(wtf 时刻)。我不会为你修复它们,但基本上:

  1. 我建议使用一些普通库(例如 commons-codec,..)从十六进制编码/解码,但目前看来它正在工作

  2. 您正在使用 16 字节(128 位)iv 并且密钥有效地执行 AES-128。您需要使用具有密钥和 iv 256 位长(32 字节)的 AES-256。您已将两者都削减为 16 个字节,因此它们与用于 openssl 的值不同

  3. 主要突破点:IvParameterSpec ivSpec = new IvParameterSpec(hexToBytes(hexString.toString())); 请考虑一下。 hexToBytes(iv)

【讨论】:

  • 就第 1 点而言,我没有使用几个库获得相同的十六进制代码,这就是我正常执行此操作的原因,但一旦我获得所需的加密结果,我将使用该库第 2 点,如果我增加密钥的大小并且 iv 我得到错误无效密钥,并且我使用命令 $ openssl enc -aes-256-cbc -k secret -P -md sha1 使用 open ssl 生成此密钥
  • 请确保 iv 和 key(它们是真正的字节数组大小)都是 256 位(32 字节)。它对我有用。只是一个想法 - 你使用什么 Java 版本/发行版?你不需要Unlimited Strength JCE Policy吗?
  • 它也适用于我的情况,但问题是它的输出与 openSSL 的输出不匹配我对 openSSL 和密码学了解不多,你能指导我如何获得 256第四位和关键谢谢。
  • 如果您使用 Oracle JRE,则需要安装 Unlimited Strength JCE Policy,否则您仅限于 AES-128(据我所知)。因此,也许一开始您可以尝试使用 16 字节密钥和 aes-128 与 openssl 和 Java 来查看它是否正确(它足够强大,不用担心)。或者你可以尝试使用 BouncyCastle 或 OpenJDK
  • 感谢您在安装 Unlimited Strength JCE Policy 后为我工作的最后一个 cmets,错误 Illegal key size 消失了,并且输出与所需的输出匹配。现在我正在尝试 BouncyCastle,以便应用程序不需要更改 JRE。
猜你喜欢
  • 1970-01-01
  • 2022-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-18
  • 1970-01-01
  • 2013-08-11
相关资源
最近更新 更多