【发布时间】:2020-04-17 17:11:55
【问题描述】:
我正在尝试使用 AES 加密一个大文件,然后对其解密并与原始文件进行比较。
本课总结了这项工作。它适用于 .txt 文件,但不是适用于 .mp3、.pdf 等。
我们将不胜感激。
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class LargeFileEncryptionTest7 {
protected static String FOLDER_PATH = "C:/temp/";
protected static String FILE = "some-large-file";
protected static String EXT = ".mp3"; //Works for .txt, but not for .mp3 or .pdf
public static void main(String[] args) throws Exception {
//Load file to encrypt
byte[] largeFileBytes = loadFile(FOLDER_PATH + FILE + EXT);
String largeFileString = new String(largeFileBytes);
//Encrypt file with AES
AESUtils aesUtils = new AESUtils();
byte[] secretKey = aesUtils.generateSecretKey();
aesUtils.setSecretKey(secretKey);
byte[] largeFileEncBytes = aesUtils.encrypt(largeFileString);
//Save encrypted file
saveFile(largeFileEncBytes, FOLDER_PATH + FILE + "-encrypted" + EXT);
//Load encrypted file
byte[] largeFileEncBytesToCheck = loadFile(FOLDER_PATH + FILE + "-encrypted" + EXT);
//Decrypt file
byte[] largeFileBytesToCheck = aesUtils.decrypt(largeFileEncBytesToCheck);
String largeFileStringToCheck = new String(largeFileBytesToCheck);
//Save decrypted file
saveFile(largeFileBytesToCheck, FOLDER_PATH + FILE + "-decrypted" + EXT);
//Check strings
//System.out.println("Original content: " + largeFileStringToCheck);
if (largeFileStringToCheck.equals(largeFileString)) {
System.out.println("OK :-) ");
} else {
System.out.println("KO :-( ");
}
}
private static void saveFile(byte[] bytes, String fileName) throws Exception {
FileOutputStream fos = new FileOutputStream(fileName);
fos.write(bytes);
fos.close();
}
private static byte[] loadFile(String fileName) throws Exception {
FileInputStream fis = new FileInputStream(fileName);
int numBtyes = fis.available();
byte[] bytes = new byte[numBtyes];
fis.read(bytes);
fis.close();
return bytes;
}
}
【问题讨论】:
-
您应该排除编码作为一个因素。要么在任何地方明确提及编码,要么不再使用旧的繁琐文件 api,而是使用 NIO。以您的
loadFile方法为例,将其替换为Files.readAllBytes(Paths.get(fileName)),就是这样。并且它将始终使用 UTF-8。与saveFile类似,只是Files.write(Paths.get(fileName), bytes),完成。在创建字符串时还要提及编码new String(bytes, StandardCharset.UTF_8)。只要确保它在所有地方都是相同的编码,否则你会遇到问题。 -
最后,不要比较字符串。比较原始数据
byte[]s,否则您将再次依赖编码。如果字节仍然相等,那么加密/解密很顺利,只是你没有为字符串表示指定正确的编码。 -
尝试将任意二进制数据转换为
String似乎是个坏主意。AESUtils是否有接受byte[]作为输入的方法?如果没有,你能加一个吗? -
正如迈克尔所说。而且“坏主意”是轻描淡写。任何承诺在
Strings 上执行加密的库/实用程序要么注定会让你失败(例如,由不知情的人提供),要么通过阅读文档做出您应该了解的假设(例如,它仅在字符串输入 Base64 编码字符串时才有效)。加密是字节级别的过程,而不是字符级别的。再次强调前一点,将任何二进制文件转换为字符串(甚至不指定编码)是要求数据损坏,并且有一天会崩溃。不要。
标签: java encryption aes