错误:javax.crypto.BadPaddingException:解密时pad块损坏

时间:2016-11-03 13:10:30

标签: java android encryption base64 aes

我已经使用

完成了加密
public static String encrypt(String plainText) {
    try {
        byte[] keyData = secret_key.getBytes();
        SecretKeySpec secretKey = new SecretKeySpec(keyData, "AES/ECB/PKCS7Padding");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);

        byte[] cipherText = cipher.doFinal(plainText.getBytes("UTF-8"));
        String encryptedString = Base64.encodeToString(cipherText, Base64.NO_WRAP);

        return encryptedString;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

它运作良好。

但是Decryption的一部分给出了错误,

W/System.err: javax.crypto.BadPaddingException: pad block corrupted
W/System.err:     at com.android.org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(JCEBlockCipher.java:701)
W/System.err:     at javax.crypto.Cipher.doFinal(Cipher.java:1111)

decrypt代码,

public static String decrypt(String encryptedText) {
    try {
        byte[] keyData = secret_key.getBytes();
        SecretKeySpec secretKey = new SecretKeySpec(keyData, "AES/ECB/PKCS7Padding");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);

        byte[] cipherText = Base64.decode(encryptedText,Base64.NO_WRAP);
        String decryptedString = new String(cipher.doFinal(cipherText),"UTF-8");

        return decryptedString;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

这里有什么问题?我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

您的secret_key值可能包含在您使用的模糊编码中未充分表示的字节。在未指定编码的情况下调用String#getBytes()时,您将获得系统默认值,该值可能会有所不同。

每当您将密钥表示为String时,都应使用十六进制编码。这将在每个平台上的序列化/反序列化中保持一致。这种编码/解码过程有许多标准实现可用(即org.bouncycastle.util.encoders.Hex.decode("0123456789ABCDEFFEDCBA9876543210");org.apache.commons.codec.binary.Hex.decodeHex("0123456789ABCDEFFEDCBA9876543210".toCharArray());,它们都返回原始byte[])。

一些旁注:

  1. 您正在使用ECB mode of operation,这对于密码分析非常容易受到频率分析的影响,并且除了玩具加密演示之外,还有效已弃用。我建议您使用CBCCTRGCM
  2. 您不提供初始化向量(IV),因此使用相同密钥加密的相同消息将始终生成相同的密文。通过从SecureRandom生成16个字节并将其填充到IvParameterSpec,为每个加密操作使用唯一且不可预测的IV。您可以将IV字节添加到密文中,并以明文形式传输/存储它。
  3. 您的密文未经过身份验证,允许恶意用户操纵加密数据并通过填充oracle / CCA攻击尝试解密。使用经过身份验证的加密和关联数据(AEAD)模式(如GCM),或使用HMAC/SHA-256消息身份验证代码(MAC)覆盖密文,并使用常量进行验证-time等于尝试任何解密之前的方法。
  4. 实例化密钥时,不需要提供操作模式或填充方案。 SecretKey key = new SecretKeySpec(keyData, "AES");就足够了。