Alt*_*rim 102 java encryption cryptography exception javax.crypto
我正在尝试实现基于密码的加密算法,但是我得到了这个例外:
javax.crypto.BadPaddingException:给定最终块未正确填充
可能是什么问题?(我是Java新手.)
这是我的代码:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
(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.
}
}
}
Run Code Online (Sandbox Code Playgroud)
Paŭ*_*ann 184
如果你试图用错误的密钥解密PKCS5填充的数据,然后取消它(它由Cipher类自动完成),你很可能会得到BadPaddingException(可能略低于255/256,大约99.61%) ),因为填充具有一个特殊的结构,在unpad期间验证,很少的键会产生有效的填充.
因此,如果您遇到此异常,请抓住它并将其视为"错误的密钥".
当您提供错误密码时也会发生这种情况,然后密码用于从密钥库获取密钥,或者使用密钥生成功能将密钥转换为密钥.
当然,如果您的数据在传输中损坏,也可能发生填充错误.
也就是说,您的计划有一些安全评论:
对于基于密码的加密,您应该使用SecretKeyFactory和PBEKeySpec,而不是将SecureRandom与KeyGenerator一起使用.原因是SecureRandom可能是每个Java实现的不同算法,为您提供不同的密钥.SecretKeyFactory以定义的方式进行密钥派生(如果选择正确的算法,则称为安全的方式).
不要使用ECB模式.它独立地加密每个块,这意味着相同的纯文本块也总是提供相同的密文块.
优选地使用安全操作模式,如CBC(密码块链接)或CTR(计数器).或者,使用也包括认证的模式,如GCM(伽罗瓦计数器模式)或CCM(具有CBC-MAC的计数器),参见下一点.
您通常不仅需要机密性,还需要身份验证,以确保邮件不被篡改.(这也可以防止对密码进行选择密文攻击,即有助于保密.)因此,在消息中添加MAC(消息认证码),或使用包含认证的密码模式(参见上一点).
DES的有效密钥大小仅为56位.这个关键空间非常小,可能会被专门的攻击者在几个小时内强行逼迫.如果您通过密码生成密钥,这将变得更快.此外,DES的块大小仅为64位,这在链接模式中增加了一些弱点.使用像AES这样的现代算法,其块大小为128位,密钥大小为128位(对于标准变体).
| 归档时间: |
|
| 查看次数: |
240230 次 |
| 最近记录: |