RSA逐块加密为大于1kb的文件生成空白输出

时间:2017-06-30 07:22:07

标签: java file encryption cryptography output

我没有为AES或其他加密打开这个线程,因为这是我将用来加密AES和其他加密的密钥。我从StackOverflow和其他一些网站收集了几个代码并编辑它以适合我的程序但是当我尝试使用RSA问题进行逐块加密时,我只能加密大小为1千字节的小文本文件。文本文件的加密和解密工作正常。但是,加密图片和大于的任何文件将超过1 KB,这将生成空白加密文件。

我想请求帮助,如果有人可以帮我指出这段代码导致大于1千字节的文件会导致空白输出文件/加密文件。这段代码适用于AES,但我不确定为什么它不适用于RSA加密。问题从Encrypt_File开始,在它所读取的循环周围。

代码:

public static final String ALGORITHM = "RSA";
private static final short KEY_LENGTH = 1024;
private static final short KEY_BYTES = 32;
private static final String CIPHER_EXTENSION = ".cgfile";

public void Encrypt_File(Path path_fileToEncrypt) {
    //get file name and the new file name
    String fileName = path_fileToEncrypt.getFileName().toString();
    String encryptedFileName = fileName+CIPHER_EXTENSION;
    String pathToEncryptedFile = path_fileToEncrypt.getParent()+File.separator+encryptedFileName;

    //attempt to open the public key
    try (ObjectInputStream publicKeyFile = new ObjectInputStream(new FileInputStream(PUBLIC_KEY_FILE))) {
        //load the key
        PublicKey publicKey = (PublicKey) publicKeyFile.readObject();

        // load file to encrypt and inputstream
        FileInputStream fileInputStream = new FileInputStream(new File(path_fileToEncrypt.toString()));

        // init the cipher
        final Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        CipherOutputStream cos = new CipherOutputStream(new FileOutputStream(pathToEncryptedFile),cipher);
        byte[] buffer = new byte[KEY_BYTES];
        int count;
        while((count = fileInputStream.read(buffer))>0){
            cos.write(buffer, 0, count);
        }

        //close
        fileInputStream.close();
        cos.close();
        //delete fileToEncrypt since we have the encrypted file now
        DeleteFile(new File(path_fileToEncrypt.toString()));
        System.out.println("Finished encrypting "+ fileName +" It's new file name is "+ encryptedFileName);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
public static void main(String[] args) {
    try {

        CGcipher rsaencrypt = new CGcipher();
        Path pathTosecret = Paths.get(System.getProperty("user.dir"), "pic.png");
        // Encrypt the string using the public key
        rsaencrypt.Encrypt_File(pathTosecret);
        //rsaencrypt.Decrypt_File(pathTosecret);

    } catch (Exception e) {
        System.out.println(e.toString());
    }
}

2 个答案:

答案 0 :(得分:5)

RSA 不适用于批量加密,因为与 AES 等对称算法相比,它的退出速度较慢(它超过了1000倍)慢点)。可以使用 RSA 在一个块中加密的数据量取决于密钥大小和填充可能使用的任何数据。

如果您需要 RSA 的两个键,同时需要加密比 RSA 块中的更多,您通常会使用{{3使用随机对称密钥加密数据部分,然后使用 RSA 加密加密密钥。这样您就可以获得对称密钥的速度,以及 RSA 的两个密钥。但是,如果您真的不需要使用不同的密钥进行加密和解密,那么您根本不应该使用 RSA

由于 RSA 不适用于批量加密,因此当您尝试加密超过一个块中的内容时,标准实现无法处理它 - 没有逻辑使用 RSA Hybrid encryption实施。这将是开箱即用的对称密码的处理方式。

答案 1 :(得分:2)

虽然算法RSA在内部扩展为Sun提供商的"RSA/ECB/PKCS1Padding"。但是,实际上并未使用ECB模式。它应该被命名为"RSA/None/PKCS1Padding"。因此,CipherOutputStream不能将RSA用于更大的数据,因为它不会实现任何分组密码模式。

不幸的是CipherOutputStream有一种讨厌的习惯" eat"例外。这就是为什么你得到一个空字符串而不是一个明确的警告。

Java的一个问题是检查异常。虽然它们肯定有它们的好处,但特殊情况不应该是功能定义的一部分。检查异常是一种很好的但是错误的方法来生成可靠/无错误的代码。

流可能引发的IOException非常清楚这一点。并非所有流都实际执行I / O,因此异常是错误的。但由于IOException已检查的异常,因此必须成为write方法定义的一部分。另一方面,安全性异常有一个名为GeneralSecurityException已检查基类。这些异常不能被抛出,因为它们未在方法定义中定义。

现在有办法解决这个问题,例如创建一个可以抛出异常的额外secureWrite方法。通常的write方法可能会抛出一个带有原始RuntimeException的新GeneralSecurityException派生异常。这些解决方案似乎已经逃脱了密码流的设计者;相反,他们选择完全删除异常,或者可能抛出IOException,预期会有另一个异常。

因此,应谨慎使用密码流。用专有实现替换它们似乎是最好的。