我正在为openssl和aes加密而挣扎。我需要在java中加密文件,同时强制使用密钥和IV值,而不是使用密码。它必须用以下命令解密:
openssl aes-256-cbc -d -K $KEY_VALUE -iv $IV -in hello.txt.ssl -out hello-clear.txt
遗憾的是,我不能更改这个命令,这是客户的要求。
我成功地用java加密了这个文件(参见下面的代码),但是当我用openssl解密它时,我得到了这个错误。
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示例:
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加密的命令行(如果有人需要的话)
openssl aes-256-cbc -e -K $KEY_VALUE -iv $IV -in hello.txt -out hello.txt.ssl
发布于 2022-12-01 18:03:57
generateRandom()
方法返回编码的数据十六进制。当y字节序列被编码时,它由2*y十六进制数字组成。因此,密钥和IV必须以所需长度的两倍(对于AES-256的32字节键,对于AES的16字节IV键是32字节)生成。然后,它们可以被解码用于加密,例如使用HexFormat.of().parseHex()
。
String keyValue = generateRandom(64);
String iv = generateRandom(32);
byte[] keyValueB = HexFormat.of().parseHex(keyValue);
byte[] ivB = HexFormat.of().parseHex(iv);
然而,总的来说,generateRandom()
中随机数据的生成有些麻烦,可以重构,例如:
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()
。
https://stackoverflow.com/questions/74645257
复制相似问题