Java给定最终块未正确填充

我正在尝试实现基于密码的加密算法,但出现此异常:

  • 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;

}

}

(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.

}

}

}

回答:

如果尝试使用错误的密钥解密填充了PKCS5的数据,然后取消填充(由Cipher类自动完成),则很可能会收到BadPaddingException(可能略小于255/256,约为99.61% ),因为填充具有特殊的结构,该结构会在取消填充期间得到验证,并且只有很少的键会产生有效的填充。

因此,如果你收到此异常,请捕获它并将其视为“错误密钥”。

如果你提供了错误的密码,然后将其用于从密钥库中获取密钥,或者使用密钥生成功能将其转换为密钥,也会发生这种情况。

当然,如果你的数据在传输中被破坏,填充也可能发生。

也就是说,有关你的方案有一些安全说明:

  • 对于基于密码的加密,应该使用SecretKeyFactory和PBEKeySpec而不是将SecureRandom与KeyGenerator一起使用。原因是SecureRandom在每个Java实现上可能是不同的算法,为你提供了不同的密钥。SecretKeyFactory以定义的方式进行密钥派生(如果选择正确的算法,则认为是安全的)。

  • 不要使用ECB模式。它独立地加密每个块,这意味着相同的纯文本块也始终提供相同的密文块。

最好使用安全的操作模式,例如CBC(密码块链接)或CTR(计数器)。或者,使用也包括身份验证的模式,例如GCM(Galois计数器模式)或CCM(带有CBC-MAC的计数器),请参阅下一点。

  • 通常,你不仅需要保密性,而且还要求身份验证,以确保消息不会被篡改。(这还可以防止对密文进行选择的密文攻击,即有助于提高机密性。)因此,在邮件中添加MAC(消息身份验证代码),或使用包含身份验证的密文模式(请参见上一点)。

  • DES的有效密钥大小仅为56位。这个密钥空间很小,可以由专门的攻击者在几个小时内强行使用。如果你通过密码生成密钥,则速度会更快。此外,DES的块大小仅为64位,这在链接模式中增加了更多弱点。请改用AES等现代算法,该算法的块大小为128位,密钥大小为128位(对于标准变体)。

以上是 Java给定最终块未正确填充 的全部内容, 来源链接: utcz.com/qa/398212.html

回到顶部