java - 使用 CipherOutputStream 进行递归加密会给出一个空字节 []
问题描述
我想多次加密一个字符串。但我不知道为什么我以一个空字节数组结尾。一个公钥是可以的,但添加另一个会返回一个空结果。有谁知道为什么?
private static byte[] encrypt(LinkedList<PublicKey> keys, byte[] input) throws Exception {
System.out.println("Input length : " + input.length);
if (keys.isEmpty()) {
return input;
}
PublicKey publicKey = keys.poll();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
try (CipherOutputStream cipherOutputStream = new CipherOutputStream(byteArrayOutputStream, cipher)) {
cipherOutputStream.write(input);
}
byteArrayOutputStream.flush();
byteArrayOutputStream.close();
return encrypt(keys, byteArrayOutputStream.toByteArray());
}
public static void main(String[] args) throws Exception {
KeyPair pair1 = createPair();
KeyPair pair2 = createPair();
LinkedList<PublicKey> keys = new LinkedList<>();
keys.add(pair1.getPublic());
keys.add(pair2.getPublic());
byte[] result = encrypt(keys, "Just testing".getBytes(Charset.forName("UTF-8")));
System.out.println(new String(result, Charset.forName("UTF-8")));
}
public static KeyPair createPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(2048);
return keyPairGen.generateKeyPair();
}
输出是
Input length : 12
Input length : 256
Input length : 0
在 Topaco 的回答之后.. 一个工作版本是:
private static BufferedInputStream encryptS(LinkedList<PublicKey> keys, BufferedInputStream inputStream) throws Exception {
if (keys.isEmpty()) {
return inputStream;
}
PublicKey publicKey = keys.poll();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
int currentPos = 0;
while (inputStream.available() > 0) {
int sizeToRead = Math.min(inputStream.available(), 245);
try (CipherOutputStream cipherOutputStream = new CipherOutputStream(byteArrayOutputStream, cipher)) {
byte[] array = new byte[sizeToRead];
inputStream.read(array, 0, sizeToRead);
cipherOutputStream.write(array);
currentPos += sizeToRead;
}
}
byteArrayOutputStream.close();
return encryptS(keys, new BufferedInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray())));
}
解决方案
对于 RSA,必须考虑以下事项:
- 消息加上填充的长度不得超过密钥长度(= 模数的大小)[
0
] , [1
] , [2
] , [3
]。填充意味着根据某种方案[4
]将额外的字节添加到消息中。 - 密文的长度对应于密钥长度(=模数的大小),[
5
]。
这意味着在第一次加密之后已经达到最大允许长度。因此,如果没有填充,则不会超过最大长度,如果有填充,则超过了最大长度。
创建密码实例
Cipher.getInstance("RSA")
对应于
Cipher.getInstance("RSA/ECB/PKCS1Padding")
对于 SunJCE-Provider ( [ 6
] , [ 7
] ),即 PKCS1 v1.5 填充与至少 11 个字符的填充一起使用,因此密钥大小为 256 字节时,消息的最大大小不得超过 245 字节.
这就是为什么当前代码中的递归加密不起作用的原因。如果密码实例是用
Cipher.getInstance("RSA/ECB/NoPadding")
(不使用填充),当前代码有效。
但是,出于安全原因,在实践中必须始终使用填充!
推荐阅读
- java - AWS EMR 上的 Spark:更新到 emr-5.20(使用 Spark 2.4):作业比以前花费更多
- database - Azure SQL DW 中基于 Cust_Id/Tenant_Id(多租户)的表分区?
- r - R:计算单个列和按组中连续出现的值
- c++ - stl 中是否有任何数据结构可以在 O(1) 或 O(log n) 中插入元素,并且我可以在其上编写自己的 bin_search?
- java - OffsetDateTime 的 Java 最快解析器
- scala - 无法获取火花数据帧的 first()
- python-3.x - Python 3.x:Pandas DataFrame 如何覆盖 csv 文件(批处理)
- python - 限制 py.test 只运行 pylint 而不是单元测试
- php - 尝试用php替换单个键中的数据
- swift - WatchKit:自定义 WKInterfaceButton 类在调用函数时因 exc_bad_access 而失败