5

CipherOutputStream在java中使用加密和解密文件,但是输入文件> 117字节不能加密。我使用 RSA 算法公钥长度为 1024 字节。

cipher.init(Cipher.ENCRYPT_MODE, secKey);

String cleartextFile = "cleartext.txt";
String ciphertextFile = "ciphertextSymm.txt";

FileInputStream fis = new FileInputStream(cleartextFile);
FileOutputStream fos = new FileOutputStream(ciphertextFile);
CipherOutputStream cos = new CipherOutputStream(fos, cipher);

byte[] block = new byte[8];
int i;
while ((i = fis.read(block)) != -1) {
      cos.write(block, 0, i);
}
cos.close();

如何加密input文件长度> 117 字节?

4

1 回答 1

22

您不能使用 RSA 加密文件,因为 RSA(更准确地说,是 RSA 在 Java 中的实现)不允许您加密比密钥长度更多的数据。对于 1024 位密钥,您只能加密 1024 位,即 128 字节(实际上由于填充原因要少一些)。

在所有情况下,使用公钥算法(非对称加密)加密大量数据都是不好的做法,主要有两个原因。

  1. 使用 RSA 加密大量数据并不实用、适当且安全的加密模式/填充(即,这样做并不安全)。

  2. 公钥算法需要一个大密钥来保证安全(1024 位、2048 位),因此比对称密钥算法(只需要 128 到 256 位的密钥就可以保证安全)慢得多。

如果您想了解有关为什么不应该单独使用 RSA 加密大量数据的更多详细信息,请参阅这两个出色的 stacktexchange 帖子:

如果你想加密大量数据,标准的做法是生成一个会话密钥(一个使用过一次的加密安全随机数)。您使用公钥加密会话密钥。然后,您使用未加密的会话密钥使用对称算法(例如 AES)加密文件(大量数据)。然后,您将加密的会话密钥和加密的数据一起存储在最终文件中。这就是 PGP(或 GnuPG)在发送加密邮件时进行的方式。SSL/TLS 也以类似的方式工作。

最后,正确使用密码学是复杂的(几乎任何事情都可能造成安全漏洞:加密模式、填充等......)所以我建议你要非常小心,并确保你的代码将由熟悉的人审查加密很重要。

这是一段显示一般过程的代码:

// 1. Generate a session key
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128)
SecretKey sessionKey = keyGen.generateKey();

// 2. Encrypt the session key with the RSA public key
Cipher rsaCipher = Cipher.getInstance("RSA");
rsaCipher.init(Cipher.ENCRYPT_MODE, rsaPublicKey)
byte[] encryptedSessionKey = rsaCipher.doFinal(sessionKey.getEncoded());

// 3. Encrypt the data using the session key (unencrypted)
Cipher aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCipher.init(Cipher.ENCRYPT_MODE, sessionKey); <-- sessionKey is the unencrypted
//                                                   session key.
// ... use aesCipher to encrypt your data

// 4. Save the encrypted data along with the encrypted 
// session key (encryptedSessionKey).
// PLEASE NOTE THAT BECAUSE OF THE ENCRYPTION MODE (CBC),
// YOU ALSO NEED TO ALSO SAVE THE IV (INITIALIZATION VECTOR).
// aesCipher.aesCipher.getParameters().
//     getParametersSpec(IvParameters.class).getIV();
于 2013-05-14T15:21:33.197 回答