【问题标题】:Openssl, Java: unable to decrypt for long messagesOpenssl,Java:无法解密长消息
【发布时间】:2018-08-24 16:42:48
【问题描述】:

我正在使用 java 加密文本并尝试在 Linux 上使用 Openssl 对其进行解密。我正在使用 AES-128 和 CBC。

当我使用 Openssl 解密 Java 生成的 64 个字符的加密字符串时,我从 Openssl 收到“解密错误”错误。但是如果字符串是 16 个字符,Openssl 可以正确解密。

我在 Linux 上运行它:

echo ${encryptedText} | ./openssl aes-128-cbc -d -a -K $( echo -n ${KEY} | hexdump -v -e '/1 "%02X"') -iv $(echo -n ${IV} | hexdump -v -e '/1 "%02X"')

注意:$encryptedText、$KEY、$IV 作为字符串而不是十六进制传递。此命令将其转换为十六进制: $( echo -n ${KEY} | hexdump -v -e '/1 "%02X"')

并收到此错误:

358048944:error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length:evp_enc.c:460:

我的Java加密代码,基本上是:

import javax.crypto.*;

Cipher cipher;
SecretKey key;
String IV;
IvParameterSpec params;

cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
String randomString = GENERATE_RANDOM_TYPEABLE_ASCII(16_LENGTH);

key = new SecretKeySpec(randomString.getBytes("UTF-8"), "AES");
IV = GENERATE_RANDOM_TYPEABLE_ASCII(16_LENGTH);
params = new IvParameterSpec(IV.getBytes("UTF-8"));

cipher.init(Cipher.ENCRYPT_MODE, key, params);
byte[] encryptedTextBytes = cipher.doFinal((decryptedString).getBytes("UTF-8")); // decryptedString is passed as a parameter

String encryptedText = new Base64().encodeAsString(encryptedTextBytes);
return encryptedText;

我不明白为什么我的加密适用于 16 个字符串,但对 64 个字符串无效。

另一件需要注意的重要事情是,如果我使用http://aes.online-domain-tools.com/ 等在线工具解密文本,则字符串将完美解密。所以我认为我的加密工作正常,但由于某种原因,OpenSSL 出现了问题。

【问题讨论】:

  • 在使用openssl解密密文之前,它肯定无法工作。
  • @James 这就是为什么我在上面的 openssl 命令中有 -a 标志。我错过了什么吗?感谢您的回复
  • 哦,是的,我忘记了那个标志。
  • 我看不出它对于 16 字节和 64 字节有何不同,但是 PKCS5 填充对于 AES 的定义并不明确。也许尝试 PKCS7 以防 Java 用它做一些奇怪的事情?

标签: java encryption openssl aes


【解决方案1】:

我没有重现您的问题,但怀疑这会导致您出现问题:Base64.encodeAsString() 函数在您使用时返回一个长字符串,而不是 16 个字符宽的块:

import org.apache.commons.codec.binary.Base64;

public class B64Test {

    public static void main(String[] args) {
        byte[] plaintext = new byte[100];
        String b64text = new Base64().encodeAsString(plaintext);
        System.out.println(b64text);
    }
}

给出输出

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==

如果您想将其输入openssl 进行解码,您需要提供附加选项-A 以使openssl base64 处理一行数据。注意-A需要和-a一起使用,或者和-base64一起使用,是一样的东西,但更易读。这在openssl enc 的文档中进行了解释。

或者,您可以告诉Base64() 构造函数在例如 64 个字符之后插入换行符,如下所示:

String b64text = new Base64(64).encodeAsString(plaintext);

【讨论】:

  • 我改为 -A 标志,但我遇到了同样的问题。我也尝试了 80 个字符的换行符(带有 -a 标志),但我仍然遇到同样的问题。
  • 那太糟糕了。您能否发布所需变量的实际示例值以简化问题的重现和分析?
  • 顺便说一句,您说“更改”为-A 标志。但是,您应该添加它。你这样做了吗?
  • 好的,周末愉快...您需要同时使用-a-A。文档对-A 说:“如果设置了-a 选项,则base64 处理[es] 一行上的数据。”。或者用-base64 -A代替-a -A,一样但是更好看。
  • @ReinierTorenbeek:添加行终止符(Unix \n 或 Windows \r\n)。普通 -d -a 的输入必须是 lines 不超过限制,即使是更短的值(如 32 个没有终止符的字符)也会失败。类似地,没有-A 的编码输出总是至少有一个终止符。 (更令人困惑的是,如果您有一个包含多行的输入文件并且最后一个没有终止,但其他当然是因为这需要多行,那么您将使用 part i> 您的数据。)
猜你喜欢
  • 2020-04-30
  • 2018-02-13
  • 2012-12-04
  • 2011-02-08
  • 1970-01-01
  • 2013-10-21
  • 2012-05-30
  • 2017-02-16
相关资源
最近更新 更多