【问题标题】:encrypting and decryption large file using rsa in java在java中使用rsa加密和解密大文件
【发布时间】:2015-06-13 06:32:18
【问题描述】:

我正在使用 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

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

【问题讨论】:

  • 额外的值在哪里?它们只是在文件的末尾吗?
  • 是的,额外的值是输出文件的结尾。
  • 没有人使用 RSA 进行直接数据加密,每个人都使用混合加密,因为 RSA 太慢了。使用 AES 加密文件,使用 RSA 加密使用的 AES 密钥。
  • 什么是“在解密部分,在我提到块大小为 128 字节的代码中进行相同的块级解密”应该是什么意思?还是英文吗?
  • 在这种情况下,祝你的项目好运。我确实希望,当你交出它的时候,你也能礼貌地向你的导师提一下,你在现实世界中永远不会做这种傻事。谁知道呢,这甚至可能是你应该从中吸取的教训。

标签: java encryption rsa public-key-encryption


【解决方案1】:

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

while ((i = fin1.read(block)) != -1) {
    byte[] inputfile= cipher.doFinal(block);
    fout.write(inputfile);
}
  1. 假定每次您要求读取一个块时,都会读取整个块。情况不一定如此。只能读取几个字节。实际读取的字节数由 read() 方法返回(并存储在i 中)。你不应该忽视它。
  2. 最后一个块很有可能是不完整的,除非您的文件大小是 32 的倍数。所以在最后一次迭代中,您正在加密文件的最后 N 个剩余字节 + 32 - N 个字节在上一次迭代中存储在字节数组中。

使用 RSA 加密大文件不是一个好主意。例如,您可以生成一个随机 AES 密钥,使用 RSA 对其进行加密并将其存储在输出文件中,然后使用 AES 对文件本身进行加密,这样速度更快,并且对大输入没有任何问题。解密将读取加密的 AES 密钥,对其进行解密,然后使用 AES 解密文件的其余部分。

【讨论】:

  • 我发布的代码读取并加密文件中的数据,无论文件大小如何。但是,如果文件大小超过 128 字节,下面的代码不会将数据转换为密码。为什么第一个代码有效,而不是这个? CipherOutputStream cos = new CipherOutputStream(fout, cipher); byte[] block = new byte[32]; int i; while ((i = fin1.read(block)) != -1) { cos.write(block, 0, i); } cos.close();
  • 因为输入太大而无法使用 RSA 加密。这正是您只加密 32 字节的块并连接结果的原因。
【解决方案2】:

混合密码系统

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

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

这意味着如果您要传输大于 128 字节的任何内容,您必须先传输一个

  1. 生成对称密钥(
  2. 使用 RSA 加密对称密钥
  3. 传输加密的对称密钥
  4. 使用 RSA 解密对称密钥
  5. 使用对称密钥加密数据(> 128 字节)
  6. 传输加密数据
  7. 使用对称密钥解密加密数据

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

  1. 生成对称密钥(
  2. 使用 RSA 加密对称密钥
  3. 使用对称密钥加密数据(> 128 字节)
  4. 传输加密的对称密钥和加密数据
  5. 使用 RSA 解密对称密钥
  6. 使用对称密钥解密加密数据

更多信息,请点击here (Hybrid cryptosystem)

【讨论】:

    【解决方案3】:

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

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

    请参阅 JB Nizets 的答案。

    【讨论】:

    • RSA 无法加密任意长度的负载。这就是为什么 OP 会一一加密 32 字节的块。
    • 好吧,我不知道。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-12
    • 1970-01-01
    • 2011-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-11
    相关资源
    最近更新 更多