如何对文件进行加密和解密?

时间:2013-05-14 15:18:13

标签: java encryption

我在java中使用CipherOutputStream加密和解密文件,但输入文件> 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字节?

1 个答案:

答案 0 :(得分:21)

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

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

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

    < / LI>
  2. 公钥算法要求大密钥是安全的(1024位,2048位),因此比对称密钥算法要慢得多(只需要128到256位密钥才能保证安全)。

  3. 如果您想了解不应仅使用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();