使用 AES 加密和解密大文件
Encrypt and decrypt large file with AES
我正在尝试使用 AES加密 一个大文件,然后 解密 并且与原版对比
此 class 总结了工作。它适用于 .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;
}
}
我发现您的解决方案有 2 个问题:
您的代码:
int numBtyes = fis.available();
byte[] bytes = new byte[numBtyes];
fis.read(bytes);
这实际上并不能保证阅读全部内容。同样,在加密大文件时(当不能保证它适合内存时),您可能不想将所有内容读入内存。
加密/解密大内容(无限制)时,您可能需要使用类似的东西:
byte[] buff = new byte[BUFFERSIZE];
for(int readBytes=in.read(buff); readBytes>-1;readBytes=in.read(buff)) {
out.write(cipher.update(buff,0, readBytes);
}
out.write(cipher.doFinal());
或查看 CipherOutputStream 和 CipherInputStream
另一个问题是比较:
String largeFileStringToCheck = new String(largeFileBytesToCheck);
如前所述,这是比较内容的糟糕方式。在 Java 中,字符串仅用于可打印字符,当尝试 "stringify" 任何字节数组时,将应用编码并且不可打印字符可能是 "trashed".
为了简单比较(有字节数组),你可以使用Arrays.equals方法
当比较非常大的内容时(当您不确定它是否适合您的 RAM 内存时),通常最好创建一个 message hash 并比较散列
编辑:如果你真的想see/print/compare密文为字符串,你可以编码二进制数据,你可以看看Base64 encoding。
如果有人感兴趣,我将最终解决方案放在这里。
它的灵感来自于人们所做的一些评论。主要是避免使用String,使用byte[]:
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class LargeFileEncryptionTest11 {
private static final String FOLDER_PATH = "C:/temp/";
private static final String FILE = "some-large-file";
private static final String EXT = ".pdf";
private static final String ENCRYPTION_ALGORITHM = "AES";
private static final int KEY_SIZE = 128; // 192 and 256 bits may not be available
public static void main(String[] args) throws Exception {
//Common stuff to encrypt/decrypt
KeyGenerator kgen = KeyGenerator.getInstance(ENCRYPTION_ALGORITHM);
kgen.init(KEY_SIZE);
SecretKey skey = kgen.generateKey();
byte[] secretKey = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(secretKey, ENCRYPTION_ALGORITHM);
Cipher cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM);
//Load file to encrypt
byte[] largeFileBytes = Files.readAllBytes(Paths.get(FOLDER_PATH + FILE + EXT));
//Encrypt file
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] largeFileEncBytes = cipher.doFinal(largeFileBytes);
//Save encrypted file
Files.write(Paths.get(FOLDER_PATH + FILE + "-encrypted" + EXT), largeFileEncBytes);
//Load encrypted file
byte[] largeFileEncBytesToCheck = Files.readAllBytes(Paths.get(FOLDER_PATH + FILE + "-encrypted" + EXT));
//Decrypt file
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] largeFileBytesToCheck = cipher.doFinal(largeFileEncBytesToCheck);
//Save decrypted file
Files.write(Paths.get(FOLDER_PATH + FILE + "-decrypted" + EXT), largeFileBytesToCheck);
//Compare results
if (Arrays.equals(largeFileBytes, largeFileBytesToCheck)) {
System.out.println("OK :-) ");
} else {
System.out.println("KO :-( ");
}
}
}
我正在尝试使用 AES加密 一个大文件,然后 解密 并且与原版对比
此 class 总结了工作。它适用于 .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;
}
}
我发现您的解决方案有 2 个问题:
您的代码:
int numBtyes = fis.available(); byte[] bytes = new byte[numBtyes]; fis.read(bytes);
这实际上并不能保证阅读全部内容。同样,在加密大文件时(当不能保证它适合内存时),您可能不想将所有内容读入内存。
加密/解密大内容(无限制)时,您可能需要使用类似的东西:
byte[] buff = new byte[BUFFERSIZE];
for(int readBytes=in.read(buff); readBytes>-1;readBytes=in.read(buff)) {
out.write(cipher.update(buff,0, readBytes);
}
out.write(cipher.doFinal());
或查看 CipherOutputStream 和 CipherInputStream
另一个问题是比较:
String largeFileStringToCheck = new String(largeFileBytesToCheck);
如前所述,这是比较内容的糟糕方式。在 Java 中,字符串仅用于可打印字符,当尝试 "stringify" 任何字节数组时,将应用编码并且不可打印字符可能是 "trashed".
为了简单比较(有字节数组),你可以使用Arrays.equals方法
当比较非常大的内容时(当您不确定它是否适合您的 RAM 内存时),通常最好创建一个 message hash 并比较散列
编辑:如果你真的想see/print/compare密文为字符串,你可以编码二进制数据,你可以看看Base64 encoding。
如果有人感兴趣,我将最终解决方案放在这里。
它的灵感来自于人们所做的一些评论。主要是避免使用String,使用byte[]:
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class LargeFileEncryptionTest11 {
private static final String FOLDER_PATH = "C:/temp/";
private static final String FILE = "some-large-file";
private static final String EXT = ".pdf";
private static final String ENCRYPTION_ALGORITHM = "AES";
private static final int KEY_SIZE = 128; // 192 and 256 bits may not be available
public static void main(String[] args) throws Exception {
//Common stuff to encrypt/decrypt
KeyGenerator kgen = KeyGenerator.getInstance(ENCRYPTION_ALGORITHM);
kgen.init(KEY_SIZE);
SecretKey skey = kgen.generateKey();
byte[] secretKey = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(secretKey, ENCRYPTION_ALGORITHM);
Cipher cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM);
//Load file to encrypt
byte[] largeFileBytes = Files.readAllBytes(Paths.get(FOLDER_PATH + FILE + EXT));
//Encrypt file
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] largeFileEncBytes = cipher.doFinal(largeFileBytes);
//Save encrypted file
Files.write(Paths.get(FOLDER_PATH + FILE + "-encrypted" + EXT), largeFileEncBytes);
//Load encrypted file
byte[] largeFileEncBytesToCheck = Files.readAllBytes(Paths.get(FOLDER_PATH + FILE + "-encrypted" + EXT));
//Decrypt file
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] largeFileBytesToCheck = cipher.doFinal(largeFileEncBytesToCheck);
//Save decrypted file
Files.write(Paths.get(FOLDER_PATH + FILE + "-decrypted" + EXT), largeFileBytesToCheck);
//Compare results
if (Arrays.equals(largeFileBytes, largeFileBytesToCheck)) {
System.out.println("OK :-) ");
} else {
System.out.println("KO :-( ");
}
}
}