我自己实施CBC模式。我使用AES作为每个CBC块的E函数。
这是我的加密代码:
public static List<Byte> encrypt(List<Byte> bytes, byte[] key) throws Exception {
byte[] bytesArray = BytesConverter.toByteArray(bytes);
SecretKey secretKey = new SecretKeySpec(key, AES);
Cipher cipher = Cipher.getInstance(AES);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return BytesConverter.toByteList(cipher.update(bytesArray));
}
我使用update
因为我不想添加AES pad。在CBC algorythm的开头,我自己做了最后一个块。
当我想解密密文块时,我使用与Cipher.DECRYPTION_MODE相同的功能。
public static List<Byte> decrypt(List<Byte> bytes, byte[] key) throws Exception {
byte[] bytesArray = BytesConverter.toByteArray(bytes);
SecretKey secretKey = new SecretKeySpec(key, AES);
Cipher cipher = Cipher.getInstance(AES);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return BytesConverter.toByteList(cipher.update(bytesArray));
}
问题是解密模式下的Cipher.update
返回由encrypt
方法加密的输入的空字节数组。
我很困惑。怎么了?
答案 0 :(得分:2)
您错过了对doFinal
的来电。由于ECB和CBC模式加密的填充,Cipher
个实例需要缓冲一个块大小 - 1个字节,只会在doFinal()
中填充和加密(或解密和取消填充) call,它释放密文的最后一部分(或用于解密的明文)。
你应该做的是使用"AES/ECB/NoPadding"
而不是doFinal
代替update
来为每个块实现CBC (尽管只是update
也可以工作,但它不是100%指定它应该)。这与底层AES密码的块加密相同。您还可以使用Bouncy Castle的较低级别,轻量级(即:直接,非JCE)API,它提供AES 引擎,它只是实现分组密码本身。