首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >AES-256-CBC在java中使用密钥/ IV加密,在OpenSSL中解密。

AES-256-CBC在java中使用密钥/ IV加密,在OpenSSL中解密。
EN

Stack Overflow用户
提问于 2022-12-01 16:36:50
回答 1查看 38关注 0票数 0

我正在为openssl和aes加密而挣扎。我需要在java中加密文件,同时强制使用密钥和IV值,而不是使用密码。它必须用以下命令解密:

代码语言:javascript
运行
复制
openssl aes-256-cbc -d -K $KEY_VALUE -iv $IV -in hello.txt.ssl -out hello-clear.txt

遗憾的是,我不能更改这个命令,这是客户的要求。

我成功地用java加密了这个文件(参见下面的代码),但是当我用openssl解密它时,我得到了这个错误。

代码语言:javascript
运行
复制
hex string is too short, padding with zero bytes to length
hex string is too short, padding with zero bytes to length
bad decrypt
40874B28DD7F0000:error:1C800064:Provider routines:ossl_cipher_unpadblock:bad decrypt:providers/implementations/ciphers/ciphercommon_block.c:124:

知道我在加密过程中错过了什么吗?或者其他的方法?

下面是加密和生成解密命令的完整java示例:

代码语言:javascript
运行
复制
import org.apache.commons.io.IOUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.*;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Arrays;

public class OpenSslEncryptor {

    public static void main(String... args) throws Exception {

        int keyLength = 256;
        int keyLengthInBit = keyLength / 8;

        File baseFile = new File("hello.txt");
        IOUtils.write("hello openssl !", new FileOutputStream(baseFile), StandardCharsets.UTF_8);
        byte[] inBytes = new FileInputStream(baseFile).readAllBytes();

        String keyValue = generateRandom(40);
        String iv = generateRandom(16);
        byte[] keyValueB = Arrays.copyOfRange(keyValue.getBytes(), 0, keyLengthInBit);
        byte[] ivB = Arrays.copyOfRange(iv.getBytes(), 0, 16);

        final SecretKeySpec key = new SecretKeySpec(keyValueB, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(ivB));

        byte[] data = cipher.doFinal(inBytes);

        File outputFile = new File(baseFile.getAbsolutePath() + ".ssl");
        IOUtils.write(data, new FileOutputStream(outputFile));

        String decryptCommand = "openssl aes-256-cbc -d -K " + keyValue
                + " -iv " + iv
                + " -in " + outputFile.getName()
                + " -out hello-clear.txt";

        System.out.println(decryptCommand);
    }

    private static String generateRandom(int length) {
        SecureRandom secureRandom = new SecureRandom();
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < length; i++) {
            builder.append(Integer.toHexString(secureRandom.nextInt(16)));
        }
        return builder.toString();
    }
}

以下是使用openssl加密的命令行(如果有人需要的话)

代码语言:javascript
运行
复制
openssl aes-256-cbc -e -K $KEY_VALUE -iv $IV -in hello.txt -out hello.txt.ssl
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-12-01 18:03:57

generateRandom()方法返回编码的数据十六进制。当y字节序列被编码时,它由2*y十六进制数字组成。因此,密钥和IV必须以所需长度的两倍(对于AES-256的32字节键,对于AES的16字节IV键是32字节)生成。然后,它们可以被解码用于加密,例如使用HexFormat.of().parseHex()

代码语言:javascript
运行
复制
String keyValue = generateRandom(64); 
String iv = generateRandom(32); 
byte[] keyValueB = HexFormat.of().parseHex(keyValue);
byte[] ivB = HexFormat.of().parseHex(iv);

然而,总的来说,generateRandom()中随机数据的生成有些麻烦,可以重构,例如:

代码语言:javascript
运行
复制
byte[] keyValueB = generateRandom(32);
byte[] ivB = generateRandom(16);
String keyValue = HexFormat.of().formatHex(keyValueB);
String iv = HexFormat.of().formatHex(ivB);
...
private static SecureRandom secureRandom = new SecureRandom();
private static byte[] generateRandom(int lengthInBytes) {
    byte[] data = new byte[lengthInBytes];
    secureRandom.nextBytes(data);
    return data;
}

现在,generateRandom()byte[]的形式直接生成所需的数据。然后,可以对OpenSSL语句进行十六进制编码,例如使用HexFormat.of().formatHex()

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74645257

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档