【问题标题】:Crazy exception at AES Decryption - BadPaddingExceptionAES 解密的疯狂异常 - BadPaddingException
【发布时间】:2013-04-22 06:14:42
【问题描述】:

我在尝试解码一些加密文本时遇到了一些麻烦。 CheckpswdBasedKey 总是返回 false,因为 c.doFinal 的 BadPaddingException 我正在使用 AES,基本上是加密:

public static String generatePswdBasedKey(String password){
String finalKey = null;
SecretKey sk = null;
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, IT, KEY_LENGTH);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
sk = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance(Cifrador.AES_MODE);//AES_MODE = AES/CBC/PKCS5Padding
IvParameterSpec ivParams = new IvParameterSpec(iv);//IV already initialized
cipher.init(Cipher.ENCRYPT_MODE, sk, ivParams);
byte pwdbytes[] = password.getBytes();//I also tried using Base64 to decode... without success
byte cc[] = cipher.doFinal(pwdbytes);
finalKey = Base64.encodeToString(cc, false);  //.encodeToString(byte[] sArr, boolean lineSep)
return finalKey;

现在解密模式:

//This method compares a password received from keyboard with the decrypted password (decrypting output from generatePswdBasedKey(String password))
public static boolean checkPswdBasedKey(String password, String passwordInput){
byte bufferBytes[] = Base64.decode(password);
SecretKey sk = new SecretKeySpec(bufferBytes, 0, bufferBytes.length, "AES"); //Also tried new SecretKeySPec(bufferBytes, "AES");...
Cipher c = Cipher.getInstance(Cifrador.AES_MODE);//AES_MODE = AES/CBC/PKCS5Padding
IvParameterSpec ivParams = new IvParameterSpec(iv);//IV already initialized
c.init(Cipher.DECRYPT_MODE, sk, ivParams);
byte result[] = c.doFinal(bufferBytes);
String resultStr = Base64.encodeToString(result, false); //.encodeToString(byte[] sArr, boolean lineSep)
if(passwordInput.equalsIgnoreCase(resultStr)){
return true;
}
return false;
}

我比较了来自 iv @checkPswdBasedKey 和 iv @generatePswdBasedKey 的字节,它们都是一样的。秘密密钥@checkPswdBasedKey (我得到这些字节: sk.getEncoded() )和秘密密钥@generatePswdBasedKey ......它们都是平等的。 所以基本上当我解密时我知道我使用的是相同的密钥、相同的 IV 和相同的消息......以及适当的长度(16 字节密钥、16 字节消息、16 字节 iv,使用 AES 128)有什么想法吗?

【问题讨论】:

  • 有点跑题了,但是有什么特别的理由不使用安全哈希来代替密码吗?
  • 将解密端设置为无填充,看看你得到了什么。各种错误都是可能的,知道明文末尾的内容可以消除其中的一些错误。
  • @rossum 好的,我做到了,谢谢你,现在完全没有例外,但是解密输出与密码输入不匹配
  • @Viccari 因为我被告知要使用基于密码的加密 :))
  • 您确定要回答我,而不是@JoachimIsaksson 吗?

标签: exception encryption aes padding badpaddingexception


【解决方案1】:

正如 Joachim Isaksson 所评论的,如果你想实现密码检查,你应该使用 secure hash 表示密码,这是不可逆的。这样即使hash+key被泄露,也无法解密得到密码。

无论如何,在您的generatePswdBasedKey 中,您使用PBKDF2WithHmacSHA1 算法生成SecretKey,然后使用该密钥加密密码。现在您有两个选项来验证checkPswdBasedKey 中的密码。无论是你:

  • 以与generatePswdBasedKey 相同的方式加密密码,并比较它们给出相同的加密字符串

或者你

  • 解密加密版本并将结果与​​明文密码进行比较。

我假设您在初始化密码以进行解密时尝试后一种方法:

c.init(Cipher.DECRYPT_MODE, sk, ivParams);

但是,要使这种方法起作用,您需要实例化您的 SecretKey 以相同的方式 正如您在generatePswdBasedKey 中所做的那样 - 目前您最终得到了两个不同的密钥。

在 generatePswdBasedKey 中:

SecretKey sk = null;
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, IT, KEY_LENGTH);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
sk = new SecretKeySpec(keyBytes, "AES");

在 checkPswdBasedKey 中:

byte bufferBytes[] = Base64.decode(password);
SecretKey sk = new SecretKeySpec(bufferBytes, 0, bufferBytes.length, "AES");

修复后,您还需要查看比较逻辑。您不应该在比较之前对结果进行 Base64 编码 - 并且比较应该区分大小写。 不要使用:

byte result[] = c.doFinal(bufferBytes);
String resultStr = Base64.encodeToString(result, false);
if (passwordInput.equalsIgnoreCase(resultStr)) {
    return true;
}

但改为使用:

byte result[] = c.doFinal(bufferBytes);
String resultStr = new String(result);
if (passwordInput.equals(resultStr)) {
    return true;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-21
    • 1970-01-01
    • 1970-01-01
    • 2020-11-13
    • 2019-09-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多