我尝试实现基于密码的加密算法,但遇到以下异常:
javax.crypto.BadPaddingException:给定的最终块未正确填充
有什么问题吗?
下面是我的代码:
public class PasswordCrypter {
private Key key;
public PasswordCrypter(String password) {
try{
KeyGenerator generator;
generator = KeyGenerator.getInstance("DES");
SecureRandom sec = new SecureRandom(password.getBytes());
generator.init(sec);
key = generator.generateKey();
} catch (Exception e) {
e.printStackTrace();
}
}
public byte[] encrypt(byte[] array) throws CrypterException {
try{
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(array);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public byte[] decrypt(byte[] array) throws CrypterException{
try{
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(array);
} catch(Exception e ){
e.printStackTrace();
}
return null;
}
}
(The JUnit测试)
public class PasswordCrypterTest {
private static final byte[] MESSAGE = "Alpacas are awesome!".getBytes();
private PasswordCrypter[] passwordCrypters;
private byte[][] encryptedMessages;
@Before
public void setUp() {
passwordCrypters = new PasswordCrypter[] {
new PasswordCrypter("passwd"),
new PasswordCrypter("passwd"),
new PasswordCrypter("otherPasswd")
};
encryptedMessages = new byte[passwordCrypters.length][];
for (int i = 0; i < passwordCrypters.length; i++) {
encryptedMessages[i] = passwordCrypters[i].encrypt(MESSAGE);
}
}
@Test
public void testEncrypt() {
for (byte[] encryptedMessage : encryptedMessages) {
assertFalse(Arrays.equals(MESSAGE, encryptedMessage));
}
assertFalse(Arrays.equals(encryptedMessages[0], encryptedMessages[2]));
assertFalse(Arrays.equals(encryptedMessages[1], encryptedMessages[2]));
}
@Test
public void testDecrypt() {
for (int i = 0; i < passwordCrypters.length; i++) {
assertArrayEquals(MESSAGE, passwordCrypters[i].decrypt(encryptedMessages[i]));
}
assertArrayEquals(MESSAGE, passwordCrypters[0].decrypt(encryptedMessages[1]));
assertArrayEquals(MESSAGE, passwordCrypters[1].decrypt(encryptedMessages[0]));
try {
assertFalse(Arrays.equals(MESSAGE, passwordCrypters[0].decrypt(encryptedMessages[2])));
} catch (CrypterException e) {
// Anything goes as long as the above statement is not true.
}
try {
assertFalse(Arrays.equals(MESSAGE, passwordCrypters[2].decrypt(encryptedMessages[1])));
} catch (CrypterException e) {
// Anything goes as long as the above statement is not true.
}
}
}
7条答案
按热度按时间nkkqxpd91#
如果您尝试使用错误的密钥解密PKCS 5填充的数据,然后取消填充(这是由Cipher类自动完成的),您很可能会得到BadPaddingException(可能略小于255/256,大约99.61%),因为填充有一个特殊的结构,在取消填充期间进行验证,很少有密钥会产生有效的填充。
所以,如果你得到这个异常,抓住它,并把它当作“错误的键”。
当您提供错误的密码时,也会发生这种情况,然后使用该密码从密钥存储库获取密钥,或者使用密钥生成函数将其转换为密钥。
当然,如果数据在传输过程中损坏,也可能发生填充错误。
也就是说,关于您的方案有一些安全注意事项:
最好使用安全的mode of operation,如CBC(密码块链接)或CTR(计数器)。或者,使用还包括身份验证的模式,如GCM(伽罗瓦计数器模式)或CCM(带CBC-MAC的计数器),见下一点。
pgvzfuti2#
当您为签名密钥输入错误的密码时,这也可能是一个问题。
67up9zun3#
根据您使用的加密算法,您可能需要在加密字节数组之前在末尾添加一些填充字节,以便字节数组的长度是块大小的倍数:
特别是在您的情况下,您选择的填充模式是PKCS5,如下所述:http://www.rsa.com/products/bsafe/documentation/cryptoj35html/doc/dev_guide/group_CJ_SYM__PAD.html
(我假设您在尝试加密时遇到了这个问题)
您可以在示例化Cipher对象时选择填充架构。支持的值取决于您使用的安全提供程序。
顺便说一下,你确定要使用对称加密机制来加密密码吗?单向哈希不是更好吗?如果你真的需要能够解密密码,DES是一个相当弱的解决方案,如果你需要使用对称算法,你可能会对使用更强的东西(如AES)感兴趣。
djp7away4#
我遇到这个问题是由于操作系统的原因,简单到不同的平台关于JRE的实现。
将在Windows中获得相同的值,而在Linux中则不同。因此在Linux中需要更改为
“SHA1PRNG”是使用的算法,您可以参考这里了解有关算法的更多信息。
xn1cxnb45#
javax.crypto.BadPaddingException:给定的最后一个块未正确填充。
如果在解密过程中使用了错误密钥,则可能出现此类问题。
对于我自己来说,当我使用错误的密钥进行解密时会发生这种情况。它总是大小写敏感的。所以请确保您在加密时使用了相同的密钥...:)
ukqbszuj6#
如果你确定所有的配置都是正确的,那么你可能会因为发送一个空值作为一个加密的解密或者一个平面文本来加密而得到这个异常。
py49o6xq7#
如果在生成密钥库时收到此警告
你可能需要删除应用程序属性文件中的属性
secret
。光这些属性就够了
对我很有效。