Java CryptoCipher 不消耗所有输入字节
Java CryptoCipher Doesn't consume all input bytes
我正在尝试从使用 Chilkat 的专有解密库转换为使用 Apache 的公共加密。我有 2 个正在使用的示例加密输入。第一个是 16 字节,第二个是 96 字节。第一个效果很好,但在第二个上,CryptoCipher 似乎没有消耗最后 16 个字节。
下面是设置和解密的一些示例代码以及输出:
Properties properties = new Properties();
CryptoCipher crypt = CryptoCipherFactory.getCryptoCipher("AES/CBC/PKCS5Padding", properties);
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hashedKeyBytes = digest.digest("SHARED_SECRET".getBytes(
StandardCharsets.UTF_8));
MessageDigest ivDigest = MessageDigest.getInstance("MD5");
byte[] ivBytes = ivDigest.digest("SHARED_SECRET".getBytes(StandardCharsets.UTF_8));
final SecretKeySpec key = new SecretKeySpec(hashedKeyBytes, "AES");
IvParameterSpec iv = new IvParameterSpec(ivBytes);
crypt.init(Cipher.DECRYPT_MODE, key, iv);
ByteBuffer encBuffer = ByteBuffer.allocateDirect(enc.length);
System.out.println("--" + enc.length);
encBuffer.put(enc);
encBuffer.flip();
System.out.println("encln " + encBuffer.limit());
ByteBuffer decoded = ByteBuffer.allocateDirect(bufferSize);
CryptoCipher crypt = init();
System.out.println("consume " + crypt.update(encBuffer, decoded));
System.out.println("finish " + crypt.doFinal(encBuffer, decoded));
decoded.flip();
return asString(decoded);
这会为 2 个输入生成这 2 个输出:
短输入:
--16
encln 16
consume 0
finish 13
长输入:
--96
encln 96
consume 80
finish 3
如您所见,它只消耗了输入中的 80 个字节...由于与 Chilkat 生成的相比,较短的输入会生成正确的输出,所以我不确定该从哪里着手让它发挥作用使用更长的输入。
crypt.update()
和crypt.doFinal(..)
返回的数字是解密的字节数,不是操作消耗的字节数。随着您的数据被填充(或者至少您将其指定为 PKCS5Padded),您的加密数据将始终比解密版本大一点。使用 PSCS5 和 AES 填充会将 1 到 16 个字节的填充添加到最接近的 16 字节乘数,这是 [=16 的块大小=]AES。
在第一个示例中,您的 13 个字节的明文数据有 3 个字节的填充,提供 16 个字节的加密数据(或一个完整的 AES 块)。在第二个示例中,您有 83 个字节的明文数据和 13 个字节的填充(给出 6 个 16 字节的 AES 块)。
我正在尝试从使用 Chilkat 的专有解密库转换为使用 Apache 的公共加密。我有 2 个正在使用的示例加密输入。第一个是 16 字节,第二个是 96 字节。第一个效果很好,但在第二个上,CryptoCipher 似乎没有消耗最后 16 个字节。
下面是设置和解密的一些示例代码以及输出:
Properties properties = new Properties();
CryptoCipher crypt = CryptoCipherFactory.getCryptoCipher("AES/CBC/PKCS5Padding", properties);
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hashedKeyBytes = digest.digest("SHARED_SECRET".getBytes(
StandardCharsets.UTF_8));
MessageDigest ivDigest = MessageDigest.getInstance("MD5");
byte[] ivBytes = ivDigest.digest("SHARED_SECRET".getBytes(StandardCharsets.UTF_8));
final SecretKeySpec key = new SecretKeySpec(hashedKeyBytes, "AES");
IvParameterSpec iv = new IvParameterSpec(ivBytes);
crypt.init(Cipher.DECRYPT_MODE, key, iv);
ByteBuffer encBuffer = ByteBuffer.allocateDirect(enc.length);
System.out.println("--" + enc.length);
encBuffer.put(enc);
encBuffer.flip();
System.out.println("encln " + encBuffer.limit());
ByteBuffer decoded = ByteBuffer.allocateDirect(bufferSize);
CryptoCipher crypt = init();
System.out.println("consume " + crypt.update(encBuffer, decoded));
System.out.println("finish " + crypt.doFinal(encBuffer, decoded));
decoded.flip();
return asString(decoded);
这会为 2 个输入生成这 2 个输出:
短输入:
--16
encln 16
consume 0
finish 13
长输入:
--96
encln 96
consume 80
finish 3
如您所见,它只消耗了输入中的 80 个字节...由于与 Chilkat 生成的相比,较短的输入会生成正确的输出,所以我不确定该从哪里着手让它发挥作用使用更长的输入。
crypt.update()
和crypt.doFinal(..)
返回的数字是解密的字节数,不是操作消耗的字节数。随着您的数据被填充(或者至少您将其指定为 PKCS5Padded),您的加密数据将始终比解密版本大一点。使用 PSCS5 和 AES 填充会将 1 到 16 个字节的填充添加到最接近的 16 字节乘数,这是 [=16 的块大小=]AES。
在第一个示例中,您的 13 个字节的明文数据有 3 个字节的填充,提供 16 个字节的加密数据(或一个完整的 AES 块)。在第二个示例中,您有 83 个字节的明文数据和 13 个字节的填充(给出 6 个 16 字节的 AES 块)。