我试图使用spring security crypto创建文件加密概念证明。根据我发现的其他一些帖子,我已经下载了Unlimited JCE Policy并将jar文件添加到我的java_home / jre / lib / security文件夹中。
调用bytesEncryptor.decrypt时发生错误。加密可能正在工作,因为执行后文件中存在加密内容,但我不确定是否有办法确认问题所在。关于这个错误的一些其他帖子并没有使用Spring说关键是不对的,但这不是因为我使用相同的bytesEncryptor对象? (Given final block not properly padded)
堆栈:
Exception in thread "main" java.lang.IllegalStateException: Unable to invoke Cipher due to bad padding
at org.springframework.security.crypto.encrypt.CipherUtils.doFinal(CipherUtils.java:142)
at org.springframework.security.crypto.encrypt.AesBytesEncryptor.decrypt(AesBytesEncryptor.java:128)
at com.test.encryption.MyTest.crypt(MyTest.java:45)
at com.test.encryption.MyTest.decryptFile(MyTest.java:31)
at com.test.encryption.MyTest.main(MyTest.java:21)
Caused by: javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313)
at javax.crypto.Cipher.doFinal(Cipher.java:2087)
at org.springframework.security.crypto.encrypt.CipherUtils.doFinal(CipherUtils.java:135)
... 4 more
代码:
public static void main(String args[]) throws Exception {
String salt = KeyGenerators.string().generateKey();
BytesEncryptor bytesEncryptor = Encryptors.standard("password", salt);
encryptFile(bytesEncryptor, "C:/test/testIn.txt", "C:/test/testOut.txt");
decryptFile(bytesEncryptor, "C:/test/testOut.txt", "C:/test/testOutDecode.txt");
}
private static void encryptFile (BytesEncryptor bytesEncryptor, String in, String out) throws Exception {
crypt(bytesEncryptor, in, out, true);
}
private static void decryptFile (BytesEncryptor bytesEncryptor, String in, String out) throws Exception {
crypt(bytesEncryptor, in, out, false);
}
private static void crypt (BytesEncryptor bytesEncryptor, String in, String out, boolean encrypt) throws Exception {
byte[] buffer = new byte[1024];
int numRead;
byte[] bytes = null;
InputStream input = new FileInputStream(in);
OutputStream output = new FileOutputStream(out);
while ((numRead = input.read(buffer)) > 0) {
if(encrypt) {
bytes = bytesEncryptor.encrypt(buffer);
} else {
bytes = bytesEncryptor.decrypt(buffer);
}
if (bytes != null) {
output.write(bytes, 0, numRead);
}
}
input.close();
output.close();
}
答案 0 :(得分:0)
我怀疑问题来自于他们以1024字节的块读取文件的方式。 AES是一种分组密码,因此可以对特定大小的数据块进行操作。当它加密时,它将填充输出以确保它适合适当大小的块。当你将数据提供给解密时,它希望在必要时对数据进行类似的填充。
尝试将整个文件读入字节数组,然后加密和解密。或者,您可以尝试使用与您用于AES的块大小相匹配的块大小(它将是128,192或256位)。
答案 1 :(得分:0)
原则上你需要为FileInputStreams和FileOutputStreams使用CipherInputStream和CipherOutputStream。
更新的代码:
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.SecureRandom;
public class MyTest {
private static String algorithm = "AES/CBC/PKCS5Padding";
public static void main(String args[]) throws Exception {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256);
SecretKey secretKey = keyGen.generateKey();
final int AES_KEYLENGTH = 256;
byte[] iv = new byte[AES_KEYLENGTH / 16];
SecureRandom prng = new SecureRandom();
prng.nextBytes(iv);
Cipher aesCipherForEncryption = Cipher.getInstance(algorithm);
Cipher aesCipherForDecryption = Cipher.getInstance(algorithm);
aesCipherForEncryption.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
aesCipherForDecryption.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
encryptFile(aesCipherForEncryption, "C:/test/testIn.txt", "C:/test/testOut.txt");
decryptFile(aesCipherForDecryption, "C:/test/testOut.txt", "C:/test/testOutDecode.txt");
}
private static void encryptFile (Cipher cipher, String in, String out) throws Exception {
crypt(cipher, in, out, true);
}
private static void decryptFile (Cipher cipher, String in, String out) throws Exception {
crypt(cipher, in, out, false);
}
private static void crypt (Cipher cipher, String in, String out, boolean encrypt) throws Exception {
byte[] buffer = new byte[256];
int numRead;
InputStream input = new FileInputStream(in);
OutputStream output = new FileOutputStream(out);
if(encrypt) {
output = new CipherOutputStream(output, cipher);
} else {
input = new CipherInputStream(input, cipher);
}
while ((numRead = input.read(buffer)) >= 0) {
output.write(buffer, 0, numRead);
}
input.close();
output.close();
}
}
注意 - 我最终没有使用Spring Security Crypto实现。
答案 2 :(得分:0)
对于它的价值,当我使用错误的密码/盐解密(虽然长度相同)时,我得到了此消息