在java中使用rsa加密和解密大文件

时间:2015-04-08 10:35:17

标签: java encryption rsa public-key-encryption

我使用RSA算法加密和解密大小超过rsa密钥大小的文件。

在下面的加密代码中,我正在逐块读取文件内容并转换为密文。块大小为32个字节。

FileInputStream fin1 = new FileInputStream(genfile);

FileOutputStream fout = new FileOutputStream(seedcipher);

byte[] block = new byte[32];
int i;
while ((i = fin1.read(block)) != -1)
{
    byte[] inputfile= cipher.doFinal(block);
    fout.write(inputfile);
}

fin1.close();

在解密部分,在我提到块大小为128字节的代码中完成相同的逐块解密

FileInputStream fin1 = new FileInputStream(encryptedfile);
FileOutputStream fout = new FileOutputStream(seedcipher);

DataInputStream dos =new DataInputStream(fin1);
DataOutputStream dosnew =new DataOutputStream(fout);
byte[] block = new byte[128];
int i;
while ((i = fin1.read(block)) != -1)
{
    byte[] inputfile= cipher.doFinal(block);
      fout.write(inputfile);
}

输入文件大小为81.3 kB,文件包含

0
1
2
3
4.....29000 

解密文件后,输出包含一些不相关的额外值。为什么结果中有额外的数据?

3 个答案:

答案 0 :(得分:5)

用于逐块读取的IO代码不正确:

while ((i = fin1.read(block)) != -1) {
    byte[] inputfile= cipher.doFinal(block);
    fout.write(inputfile);
}
  1. 假设每次要求读取块时,都会读取整个块。情况不一定如此。只能读取几个字节。 read()方法返回实际读取的字节数(并存储在i中)。你不应该忽视它。
  2. 最后一个块很可能不完整,除非你的文件大小是32的倍数。所以在最后一次迭代中,你要加密文件的最后N个剩余字节+ 32-N在上一次迭代中存储在字节数组中的字节。
  3. 使用RSA加密大文件不是一个好主意。例如,您可以生成随机AES密钥,使用RSA对其进行加密并将其存储在输出文件中,然后使用AES加密文件本身,这样可以更快,并且对大输入没有任何问题。解密将读取加密的AES密钥,对其进行解密,然后使用AES解密文件的其余部分。

答案 1 :(得分:2)

混合密码系统

示例:对于1024位密钥,您可以加密大约1024/8 = 128个字节
注意:精确值为128字节 - 填充为11个字节

您可以使用对称密钥来加密和解密要传输的数据(> 128字节)。 RSA只能在一定程度上加密数据(例如128字节),这取决于RSA密钥长度。

这意味着如果要传输大于128字节的任何内容,则必须传输对称密钥<首先是128个字节,因此您可以拥有以下内容:

  
      
  1. 生成对称密钥(<128字节)
  2.   
  3. 使用RSA加密对称密钥
  4.   
  5. 传输加密对称密钥
  6.   
  7. 使用RSA解密对称密钥
  8.   
  9. 使用对称密钥加密数据(> 128字节)
  10.   
  11. 传输加密数据
  12.   
  13. 使用对称密钥解密加密数据
  14.   

或(同时传输加密的对称密钥和加密数据)

  
      
  1. 生成对称密钥(<128字节)
  2.   
  3. 使用RSA加密对称密钥
  4.   
  5. 使用对称密钥加密数据(> 128字节)
  6.   
  7. 传输加密对称密钥&amp;加密数据
  8.   
  9. 使用RSA解密对称密钥
  10.   
  11. 使用对称密钥解密加密数据
  12.   

有关详情,请点击here (Hybrid cryptosystem)

答案 2 :(得分:0)

你可以通过runlength编码来解决这个问题。使用DataOutputStream在开头写入一个整数,表示之后写入的字节数。解密时,读取该整数,并仅使用它所说的字节数。

我注意到你以错误的方式使用Cipher类。使用update方法将字节添加到cipher,并仅使用doFinal一次。使用this重载方法的重载版本非常重要。将inputOffset参数设置为零,将inputLen参数设置为i。这将确保Cipher仅使用它应该使用的字节。

参见JB Nizets的答案。