问题 密码:IllegalBlockSizeException的原因是什么?


我在工作时观察到以下情况 暗号

加密代码:

Cipher aes = Cipher.getInstance("AES");
aes.init(Cipher.ENCRYPT_MODE, generateKey());
byte[] ciphertext = aes.doFinal(rawPassword.getBytes());

解密代码:

Cipher aes = Cipher.getInstance("AES");
aes.init(Cipher.DECRYPT_MODE, generateKey());
byte[] ciphertext = aes.doFinal(rawPassword.getBytes());

在运行Decrypt代码时,我得到IllegalBlockSizeException(输入长度​​必须是16的倍数)。

但是,如果我将解密代码更改为

Cipher aes = Cipher.getInstance("AES/ECB/PKCS5Padding"); //I am passing the padding too
aes.init(Cipher.DECRYPT_MODE, generateKey());
byte[] ciphertext = aes.doFinal(rawPassword.getBytes());

它工作正常。 我明白这是在模式中 algorithm/mode/padding。所以我认为这是因为我没有提到填充。所以我尝试在加密过程中给出模式和填充,

加密代码:

Cipher aes = Cipher.getInstance("AES/ECB/PKCS5Padding");//Gave padding during encryption too
aes.init(Cipher.ENCRYPT_MODE, generateKey());
byte[] ciphertext = aes.doFinal(rawPassword.getBytes());

解密代码:

Cipher aes = Cipher.getInstance("AES/ECB/PKCS5Padding");
aes.init(Cipher.DECRYPT_MODE, generateKey());
byte[] ciphertext = aes.doFinal(rawPassword.getBytes());

但它失败了IllegalBlockSizeException。

是什么原因,为什么例外以及究竟发生了什么。 如果有人可以帮忙吗?提前致谢

UPDATE

看起来问题在于我正在加密和解密的字符串。因为,即使我说的代码有效,也并不总是有效。我基本上是在加密UUID(例如:8e7307a2-ef01-4d7d-b854-e81ce152bbf6)。它适用于某些字符串,而不适用于某些其他字符串。

加密String的长度为64,可以被16整除。是的,我在同一台机器上运行它。

密钥生成方法:

    private Key generateKey() throws NoSuchAlgorithmException {
    MessageDigest digest = MessageDigest.getInstance("SHA");
            String passphrase = "blahbl blahbla blah";
    digest.update(passphrase.getBytes());
    return new SecretKeySpec(digest.digest(), 0, 16, "AES");
}

9335
2018-04-24 12:32


起源

加密方法生成的密文长度是多少?它应该是16的倍数 - 如果不是,那么请用您的所有加密代码编辑您的问题,以便我们可以看到出了什么问题。此外,这可能不是问题(我假设你在同一台机器上运行加密和解密),但你应该总是使用rawPassword.getBytes(“UTF-8”),因为不同的JVM使用不同的默认字符编码。 - Zim-Zam O'Pootertoot
我已经更新了我的答案。是的,我应该通过编码标准。 - shazinltc
您的代码是否始终因某个UUID值而失败?如果是这样,请编辑您的问题以显示单个代码( SSCCE)失败,以便我们可以试验。 - Duncan Jones


答案:


在解密期间,可以 只要 得到一个 IllegalBlockSizeException 如果输入数据不是块大小的倍数(AES为16字节)。

如果密钥或数据无效(但长度正确),您将得到一个 BadPaddingException 因为PKCS#5填充在明文中是错误的。偶尔填充看起来是正确的,你也不会有任何例外。


注:我建议你总是指定填充和模式。如果不这样做,如果提供商更改默认值,您可能会感到惊讶。 Sun提供商AFAIK转换 "AES" 至 "AES/ECB/PKCS5Padding"


7
2018-04-24 14:41



'rawPassword'是一个复制/粘贴问题。是的,你对模式和填充是正确的。我现在正在这样做。 - shazinltc
你的答案很接近,所以我接受了:)如果有人碰巧有一天看过这篇文章,我自己就有一个答案,解释究竟是什么问题:)欢呼! - shazinltc
未来对Android开发人员的注意:在API 25(编写本文时),您 能够 得到 javax.crypto.IllegalBlockSizeException ... stack trace ... Caused by: android.security.KeyStoreException: Key user not authenticated 使用时 SecretKey 直接从密钥库加载而不是通过一个引用它 CryptoObject 验证密钥使用的包装器。 - Scruffy
@Scruffy你能解释一下吗? - madyx
@IgorGanapolsky这意味着输入数据的长度为“k * n“,哪里 ñ 块大小和 ķ 是不变的。因此,它可以干净地分成长度块 ñ。 - Duncan Jones


虽然我还没有完全理解内部,但我发现了问题所在。

我将加密的字符串作为GET请求参数获取。由于字符串包含不安全的字符,因此在请求中字符串会被破坏。解决方案是进行URL编码和解码。

我能够成功地使用它 URLEncoder的 和 URLDecoder

现在结果是一致的。谢谢 :)

如果有人能为此做出更多贡献,我将不胜感激。


3
2018-04-24 14:40



啊,它解释了它。你破坏的密文不再是正确的长度,因此是例外(基本上看到我的答案的内容)。 - Duncan Jones
究竟是发生了什么.. - shazinltc