我正在努力使用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();
}
}
下面是命令行encrypt with openssl,如果有人想要的话
openssl aes-256-cbc -e -K $KEY_VALUE -iv $IV -in hello.txt -out hello.txt.ssl
1条答案
按热度按时间q8l4jmvw1#
generateRandom()
方法返回十六进制编码的数据。当 y 字节的序列是十六进制编码时,它由 2y* 个十六进制数字组成。因此,生成的密钥和IV必须具有所需长度的两倍(64用于AES-256的32字节密钥,32用于AES的16字节IV)。然后,这些可以被十六进制解码以用于加密,例如,用HexFormat.of().parseHex()
:然而,总的来说,
generateRandom()
中的随机数据的生成有些麻烦,并且可以被重构,例如:现在
generateRandom()
直接生成所需的数据byte[]
,然后可以对这些数据进行十六进制编码,例如HexFormat.of().formatHex()
。