我正在尝试用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;
}
}
万一有人感兴趣,我把最后的解决方案放在这里。
它的灵感来自于人们所做的一些评论。主要避免使用字符串,使用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 :-( ");
}
}
}
我发现您的解决方案有两个问题:
您的代码:
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,字符串只用于可打印的字符,当试图“字符串化”任何字节数组时,会应用一种编码,而不可打印的字符可能会被“丢弃”。
对于简单的比较(具有字节数组),可以使用arrays.equals方法
在比较真正大的内容时(当您可能不确定它是否适合您的RAM内存时),通常创建消息哈希并比较哈希是一个好主意
编辑:如果你真的想看到/打印/比较作为字符串的密文,你可以对二进制数据进行编码,你可以看一下Base64编码。
问题内容: 我迅速编写了一个应用程序,我需要AES加密和解密功能,我从另一个.Net解决方案中接收了加密数据,但是我找不到解决办法。 这是我的.net加密: 我需要迅速解密功能。 问题答案: 我找到了解决方案,它是一个很好的库。 跨平台256位AES加密/解密。 此项目包含在所有平台(C#,iOS,Android)上均可使用的256位AES加密的实现。关键目标之一是通过简单的实现使AES在所有平台
我之所以问这个问题,是因为两天来我读了很多关于crypto AES加密的帖子,就在我以为我得到了它的时候,我意识到我根本没有得到它。 这个帖子是最接近我的问题,我有完全相同的问题,但它没有得到回答: CryptoJS AES加密与JAVA AES解密值不匹配 我得到的是已经加密的字符串(我得到的代码只是为了看看他们是怎么做的),所以修改加密方式不是一个选项。这就是为什么所有类似的问题对我来说都不是
问题内容: 我想使用128位AES加密和16字节密钥对密码进行加密和解密。解密值时出现错误。解密时我丢失任何内容吗? 错误信息 最后我基于@QuantumMechanic答案使用以下解决方案 } 问题答案: 如果对于块密码,您将不使用包含填充方案的转换,则需要使明文中的字节数为该密码的块大小的整数倍。 因此,要么将纯文本填充到16字节的倍数(即AES块大小),要么在创建对象时指定填充方案。例如,您
我有这段代码,它基本上对两条纯文本消息进行加密,然后尝试解密,然后打印。问题是第一条消息恢复得很好,但第二条消息是垃圾。我从本教程下载了这段代码,然后将其修改为使用字符串而不是文件,因为我需要它通过套接字发送加密文本。所以其他endpoint不知道明文的长度,有没有办法找到长度,或者我必须以某种方式将明文的长度与密码一起发送? 现在,我认为解密的中断条件有问题。 另外,main()代码在概念上是否
文件解密后,输出包含一些不相关的额外值。为什么结果中有额外的数据?
我试图在Android和PHP端使用AES加密/解密数据,并累犯空答案。 首先,我在Android中生成了对称密钥: 在服务器端,我试图解密数据。我可以解密(从RSA)秘密的AES密钥,并得到它的字符串表示。在客户端(Android)和服务器端(PHP)上是一样的。但是如何使用这个字符串AES密钥来解密数据呢?我尝试了这个(PHP): PHP中的结果: 怎么啦?