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



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

如果有人可以帮助我指出这段代码导致大于 1 KB 的文件导致空白输出文件/加密文件的位置,我想寻求帮助。这段代码适用于 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());
}
}

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

当您需要 RSA 的两个密钥,同时需要加密的多个密钥时,您通常会使用混合加密,即使用随机对称密钥加密数据部分,然后使用RSA加密加密密钥。通过这种方式,您可以获得对称密钥的速度,以及RSA的两个密钥。但是,如果您真的不需要使用不同的密钥进行加密和解密,那么您根本不应该使用RSA

由于RSA不适用于批量加密,因此当您尝试加密一个块中的内容超过可以加密的内容时,标准实现无法处理它 - 没有实现将加密块与RSA链接的逻辑。这将是开箱即用的对称密码的句柄。

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

不幸的是,CipherOutputStream有"吃"例外的讨厌习惯。这就是为什么您会收到空字符串而不是明确警告的原因。


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

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


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

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

最新更新