java - 如何使用 CipherInputStream 解密文件或为什么以下方法不起作用
问题描述
我有以下功能来加密文件。我打印了两个文件的结果,一切似乎都正常工作。
加密文件已更改,并且与输入文件的长度相同。
public void encrypt(String password, String filePath){
InputStream is = null;
OutputStream os = null;
CipherOutputStream cos = null;
try {
is = new FileInputStream(new File(filePath));
os = new FileOutputStream(new File(filePath + ".enc"));
char[] passwordChars = password.toCharArray();
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(passwordChars, salt, 1024, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey key = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, key, iv);
cos = new CipherOutputStream(os, c);
byte[] b = new byte[1024];
while(is.read(b) != -1)
cos.write(b);
b = new byte[1024];
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (os != null)
os.close();
if (is != null)
is.close();
if (cos != null)
cos.close();
} catch (IOException e) {
}
}
}
之后我尝试解密文件时会出现问题。我使用具有以下功能的 CipherInputStream:
public void decrypt(String password, String filePath){
InputStream is = null;
OutputStream os = null;
CipherInputStream cis = null;
try {
is = new FileInputStream(new File(filePath));
os = new FileOutputStream(new File(filePath + ".dec"));
char[] passwordChars = password.toCharArray();
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(passwordChars, salt, 1024, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey key = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.DECRYPT_MODE, key, iv);
cis = new CipherInputStream(is, c);
byte[] b = new byte[1024];
while(cis.read(b) != -1){
os.write(b);
b = new byte[1024];
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (os != null)
os.close();
if (is != null)
is.close();
if (cis != null)
cis.close();
} catch (IOException e) {
}
}
}
根本没有进入while循环。当我验证时,它就像文件是空的,但显然不是。加密似乎可以正常工作,但不能解密。
我尝试更改函数以使用 CipherOutputStream 但同样的事情发生了。我得到一个长度为 0 的解密文件。
为什么解密方法不起作用?
解决方案
有很多东西要修复
c.init(Cipher.ENCRYPT_MODE, key, iv);
IV在哪里定义?如果它是静态的,则使用 cbc 模式几乎完全破坏了安全性。
下一步 - 您正在使用没有任何身份验证的 CBC 模式(hmac),尝试搜索“malleable cipher”
为什么解密方法不起作用?
byte[] b = new byte[1024];
while(is.read(b) != -1)
cos.write(b);
b = new byte[1024];
}
这是完全错误的。无论读取输入如何,您都在写入一个b
1024 字节的完整数组。(是否有理由在循环中重新创建数组?)
尝试类似的东西
b=byte[1024];
for(int bytesRead=in.read(b); bytesRead>-1; bytesRead=in.read(b))
cos.write(b, 0, bytesRead);
cos.flush()
同样适用于解密,请先修复此问题,然后尝试调试您的应用
注意:我不是很喜欢 CipherStream 实现,我建议你使用cipher.update
和cipher.doFinal
推荐阅读
- google-cloud-platform - google.apis 和 google.cloud 中的相同产品有什么区别
- sql - 如何获取多个连接行的前 N 行
- c++ - 我设法修复了错误(LNK1169 和 LNK2005),但为什么会这样?
- amazon-web-services - 使用我的减速器和映射器创建 emr 集群时出现错误 403?
- c# - 使用 EF6 保存新记录时主键已存在
- mysql - 是否可以通过 ssl 将 typeorm 连接到 sql gcloud 的实例?
- antlr4 - 如何知道我必须解析多少相同的结构
- shell - 递归复制文件夹:Shell
- javascript - 如何在不下载的情况下获取图像 URL?
- android - 如何从另一个活动中返回后按时列表视图的滚动位置