RSA逐块加密为大于1kb的文件产生空白输出 [英] RSA block by block encryption produces blank output for files larger than 1kb

查看:101
本文介绍了RSA逐块加密为大于1kb的文件产生空白输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不会为AES或其他加密方式打开该线程,因为这是我将用于加密AES和其他加密方式的密钥的内容.我已经从StackOverflow和其他一些站点收集了一些代码,并对其进行了编辑,以使其适合我的程序,但是,在尝试使用RSA问题逐块加密时,我只能加密大小为1 KB的小型文本文件.文本文件的加密和解密工作正常.但是,对图片和任何更大大于1 KB的文件进行加密将产生空白加密文件.

I'm not opening this thread for AES or other encryptions because this is what I'm going to use to encrypt the keys of AES and other encryptions. I've gathered several codes from StackOverflow and a few other sites and edited it to fit my program however while trying to do a block by block encryption using RSA problem is I can only encrypt small text files of size 1 kilobyte. Encryption and Decryption of text files are working fine. However, encrypting pictures and ANY files larger than 1 kilobyte will produce a blank encrypted file.

我想问问是否有人可以帮助我指出代码段导致大于1 KB的文件导致空白输出文件/加密文件的地方.这段代码适用于AES,但是我不确定为什么它不适用于RSA加密.问题始于Encrypt_File读取循环的地方.

I would like to ask help if anyone can help me point out where the piece of code causes files greater than 1 kilobyte causes a blank output file/encrypted file. This piece of code works for AES but I'm not sure why it doesn't work on RSA encryption. The problem starts at Encrypt_File somewhere around the loop where it reads it.

代码:

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());
    }
}

推荐答案

尽管Sun提供商在内部将算法RSA扩展为"RSA/ECB/PKCS1Padding".但是,实际上并未使用ECB模式.它应该已经被命名为"RSA/None/PKCS1Padding".因此CipherOutputStream无法将RSA用于更大的数据,因为它没有实现任何分组密码模式.

Although the algorithm RSA is internally expanded to mean "RSA/ECB/PKCS1Padding" by the Sun provider. However, ECB mode is not actually used. It should have been named "RSA/None/PKCS1Padding". So RSA cannot be used for larger data by CipherOutputStream as it doesn't implement any block cipher mode.

不幸的是,CipherOutputStream具有吃"异常的讨厌习惯.这就是为什么您得到一个空字符串而不是一个清晰的警告的原因.

Unfortunately CipherOutputStream has the nasty habit of "eating" exceptions. This is why you get an empty string instead of a clear warning.

Java的问题之一是检查异常.尽管它们肯定有其好处,但特殊情况不应成为函数定义的一部分.检查异常是产生可靠/无错误代码的一种很好的方法,但是是错误的方法.

One of the problems with Java are checked exceptions. Although they certainly have their benefits, exceptional circumstances should not be part of a function definition. Checked exceptions are a well-meant but wrong method to produce reliable / error free code.

IOException可以很清楚地表明这可能会被流抛出.并非所有流实际上都执行I/O,因此异常是错误的.但是,由于IOException已检查的异常,因此必须write方法定义的一部分.另一方面,安全异常具有称为GeneralSecurityException checked 基类.这些异常不能被流抛出,因为它们未在方法定义中定义.

This is made perfectly clear by the IOException that may be thrown by streams. Not all streams do actually perform I/O so the exception is wrong. But because IOException is a checked exception it must be part of the write method definition. On the other hand, security exceptions have a checked base class called GeneralSecurityException. These exceptions cannot be thrown by a stream because they are not defined in the method definition.

现在有多种方法可以解决此问题,例如创建一个附加的secureWrite方法,该方法的确会引发异常.通常的write方法可能会抛出一个新的RuntimeException派生的异常,并带有原始的GeneralSecurityException.但是,这些解决方案似乎已经使密码流的设计者逃脱了.相反,他们选择完全删除这些异常,或者在可能会出现其他异常的地方抛出IOException.

Now there are ways around this, for instance creating an additional secureWrite method that does throw the exception. The usual write method could throw a new RuntimeException derived exception carrying the original GeneralSecurityException. These solutions seem to have escaped the designer of the cipher streams though; instead they opted remove the exceptions altogether or possibly throw an IOException where another exception is expected.

因此,应非常谨慎地使用密码流.用专有的实现方式替换它们似乎是最好的.

As a result the cipher streams should be used with extreme caution. Replacing them with a proprietary implementation seems best.

这篇关于RSA逐块加密为大于1kb的文件产生空白输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆