在 java 中使用 rsa 加密和解密大文件
encrypting and decryption large file using rsa in java
我正在使用 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
文件解密后,输出包含一些不相关的额外值。为什么结果中有额外的数据?
你可以通过游程编码来解决这个问题。使用 DataOutputStream 在开头写入一个整数,表示之后写入的字节数。解密时,读取那个整数,只使用它说的字节数。
我注意到您正在使用更新方法的 Cipher class in a wrong way. Use the update
method to add bytes to cipher
and only use doFinal
once. It is important that you use this 重载版本。将 inputOffset
参数设置为零,将 inputLen
参数设置为 i
。这将确保 Cipher
只使用它应该使用的字节。
参见 JB Nizets 的回答。
您逐块读取的IO代码不正确:
while ((i = fin1.read(block)) != -1) {
byte[] inputfile= cipher.doFinal(block);
fout.write(inputfile);
}
- 它假定每次你要求读取一个块时,都会读取整个块。不一定如此。可能只读取几个字节。实际读取的字节数由 read() 方法返回(并存储在
i
中)。你不应该忽视它。
- 最后一个块很可能不完整,除非你的文件大小是 32 的倍数。所以在最后一次迭代中,你加密文件的最后 N 个剩余字节 + 32 - N上一次迭代时存储在字节数组中的字节数。
使用 RSA 加密大文件不是一个好主意。例如,您可以生成一个随机 AES 密钥,使用 RSA 对其进行加密并将其存储在输出文件中,然后使用 AES 对文件本身进行加密,这样速度要快得多,并且对于大输入没有任何问题。解密将读取加密的 AES 密钥,对其进行解密,然后使用 AES 对文件的其余部分进行解密。
混合密码系统
示例:对于 1024 位密钥,您可以加密大约 1024 / 8 = 128 字节
注意:准确值为 128 字节 - 11 字节用于填充
您可以使用对称密钥加密和解密要传输的数据(> 128 字节)。 RSA 只能将数据加密到一定程度(例如 128 字节),这取决于 RSA 密钥长度。
这意味着如果你想传输任何大于 128 字节的东西,你必须先传输一个小于 128 字节的对称密钥,这样你就可以有以下内容:
- Generate a symmetric key (< 128 bytes)
- Encrypt symmetric key with RSA
- Transfer encrypted symmetric key
- Decrypt symmetric key with RSA
- Encrypt data (> 128 bytes) with symmetric key
- Transfer encrypted data
- Decrypt encrypted data with symmetric key
或(同时传输加密对称密钥和加密数据)
- Generate a symmetric key (< 128 bytes)
- Encrypt symmetric key with RSA
- Encrypt data (> 128 bytes) with symmetric key
- Transfer encrypted symmetric key & encrypted data
- Decrypt symmetric key with RSA
- Decrypt encrypted data with symmetric key
有关详细信息,请单击 here (Hybrid cryptosystem)
我正在使用 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
文件解密后,输出包含一些不相关的额外值。为什么结果中有额外的数据?
你可以通过游程编码来解决这个问题。使用 DataOutputStream 在开头写入一个整数,表示之后写入的字节数。解密时,读取那个整数,只使用它说的字节数。
我注意到您正在使用更新方法的 Cipher class in a wrong way. Use the update
method to add bytes to cipher
and only use doFinal
once. It is important that you use this 重载版本。将 inputOffset
参数设置为零,将 inputLen
参数设置为 i
。这将确保 Cipher
只使用它应该使用的字节。
参见 JB Nizets 的回答。
您逐块读取的IO代码不正确:
while ((i = fin1.read(block)) != -1) {
byte[] inputfile= cipher.doFinal(block);
fout.write(inputfile);
}
- 它假定每次你要求读取一个块时,都会读取整个块。不一定如此。可能只读取几个字节。实际读取的字节数由 read() 方法返回(并存储在
i
中)。你不应该忽视它。 - 最后一个块很可能不完整,除非你的文件大小是 32 的倍数。所以在最后一次迭代中,你加密文件的最后 N 个剩余字节 + 32 - N上一次迭代时存储在字节数组中的字节数。
使用 RSA 加密大文件不是一个好主意。例如,您可以生成一个随机 AES 密钥,使用 RSA 对其进行加密并将其存储在输出文件中,然后使用 AES 对文件本身进行加密,这样速度要快得多,并且对于大输入没有任何问题。解密将读取加密的 AES 密钥,对其进行解密,然后使用 AES 对文件的其余部分进行解密。
混合密码系统
示例:对于 1024 位密钥,您可以加密大约 1024 / 8 = 128 字节
注意:准确值为 128 字节 - 11 字节用于填充
您可以使用对称密钥加密和解密要传输的数据(> 128 字节)。 RSA 只能将数据加密到一定程度(例如 128 字节),这取决于 RSA 密钥长度。
这意味着如果你想传输任何大于 128 字节的东西,你必须先传输一个小于 128 字节的对称密钥,这样你就可以有以下内容:
- Generate a symmetric key (< 128 bytes)
- Encrypt symmetric key with RSA
- Transfer encrypted symmetric key
- Decrypt symmetric key with RSA
- Encrypt data (> 128 bytes) with symmetric key
- Transfer encrypted data
- Decrypt encrypted data with symmetric key
或(同时传输加密对称密钥和加密数据)
- Generate a symmetric key (< 128 bytes)
- Encrypt symmetric key with RSA
- Encrypt data (> 128 bytes) with symmetric key
- Transfer encrypted symmetric key & encrypted data
- Decrypt symmetric key with RSA
- Decrypt encrypted data with symmetric key
有关详细信息,请单击 here (Hybrid cryptosystem)