Java 使用AES算法对大型文件进行加密和解密
我正在加密和解密大型文件,如视频、mp3和pdf。我使用下面的算法。我曾尝试在解密后下载pdf文件,但渲染需要一分钟以上的时间,即使下载的文件只有100kb 下面是我的代码,我怎样才能更快地解决错误并呈现或下载解密文件Java 使用AES算法对大型文件进行加密和解密,java,image,pdf,encryption,aes,Java,Image,Pdf,Encryption,Aes,我正在加密和解密大型文件,如视频、mp3和pdf。我使用下面的算法。我曾尝试在解密后下载pdf文件,但渲染需要一分钟以上的时间,即使下载的文件只有100kb 下面是我的代码,我怎样才能更快地解决错误并呈现或下载解密文件 public OutputStream encrypt(OutputStream stream) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
public OutputStream encrypt(OutputStream stream) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
OutputStream fos = stream;
SecretKeySpec sks = new SecretKeySpec("MyDifficultPassw".getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE,sks);
final CipherOutputStream cos = new CipherOutputStream(fos, cipher);
return cos;
}
public InputStream decrypt(InputStream stream) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
InputStream fis = stream;
SecretKeySpec sks = new SecretKeySpec("MyDifficultPassw".getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, sks);
final CipherInputStream cis = new CipherInputStream(fis, cipher);
return cis;
}
我得到这个错误“是由:javax.crypto.IllegalBlockSizeException引起的:当使用填充密码解密时,输入长度必须是16的倍数
在java.base/com.sun.crypto.provider.CipherCore.prepareInputBuffer(CipherCore.java:1005)“此代码存在多个问题
“MyDifficultPassw”.getBytes()
getBytes()
通过使用“平台默认编码”对字符进行解码,将字符转换为字节。虽然在未来的一些java中,可能只是被硬锁定到UTF-8,但它现在不是这样工作的,这意味着您的实际密码(如密钥字节)取决于您运行它的硬件,而您显然不希望这样。尝试.getBytes(StandardCharsets.UTF_8)
取而代之,现在无论在什么硬件上运行它,它都是一致的
SecretKeySpec sks=newsecretkeyspec(“MyDifficultPassw.getBytes(),“AES”)代码>
byte[] salt = new byte[] {10, 99, 88, 20, 8, 20, 77, 1};
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHMacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
SecretKey secret = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
这将使用用户提供的密码(password
),并使用PBKDF2算法将其转换为256位密钥,这是一个好主意,而SO答案不是解释原因的合适场所-可以在web上搜索此信息。“salt”是一种很难识别密码的东西:它需要事先很难猜到,但不需要特别保密。您可以在源文件中为它硬编码8个随机选择的数字;你也需要它来解密
Cipher.getInstance(“AES”)代码>
NoPadding
。另一种流行但问题稍大的链接模式是CBC,它确实需要填充:
那么,让我们来解决这个问题:Cipher.getInstance(“AES/GCM/NoPadding”)
,或Cipher.getInstance(“AES/CBC/PKCS5Padding”)代码>
对解密代码应用相同的转换,您就解决了问题。。。有点
如何解决错误并更快地呈现或下载解密文件
public OutputStream encrypt(OutputStream stream) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
OutputStream fos = stream;
SecretKeySpec sks = new SecretKeySpec("MyDifficultPassw".getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE,sks);
final CipherOutputStream cos = new CipherOutputStream(fos, cipher);
return cos;
}
public InputStream decrypt(InputStream stream) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
InputStream fis = stream;
SecretKeySpec sks = new SecretKeySpec("MyDifficultPassw".getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, sks);
final CipherInputStream cis = new CipherInputStream(fis, cipher);
return cis;
}
这听起来像是你把缓冲搞砸了。这与粘贴的代码没有任何关系,但这是交给此方法的输入/输出流的问题。许多流需要大量写入/读取,否则速度相当慢。通过将它们包装在BufferedXStream
中来修复此问题
坏的:
好:
请注意,一般来说,如果你真的不知道自己在做什么,最终结果经受住黑客攻击的几率很低。没有一个好的解决方案可以解决这个问题——阅读安全知识,检查代码,尝试使用更多现成的东西,而不是手工操作。但是,这些都不是保证。此代码存在多个问题
“MyDifficultPassw”.getBytes()
这是个坏主意getBytes()
通过使用“平台默认编码”对字符进行解码,将字符转换为字节。虽然在未来的一些java中,可能只是被硬锁定到UTF-8,但它现在不是这样工作的,这意味着您的实际密码(如
try (FileOutputStream fos = new BufferedOutputStream(FileOutputStream("encrypted.txt"))) {
CipherOutputStream cos = encrypt(fos);
// write data
}