gpt4 book ai didi

java - 给定最终 block 未正确填充

转载 作者:IT老高 更新时间:2023-10-28 11:26:37 25 4
gpt4 key购买 nike

我正在尝试实现基于密码的加密算法,但我得到了这个异常:

javax.crypto.BadPaddingException: Given final block not properly padded

可能是什么问题?

这是我的代码:

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

最佳答案

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

因此,如果您遇到此异常,请将其捕获并将其视为“错误 key ”。

当您提供错误的密码时也会发生这种情况,然后使用该密码从 keystore 中获取 key ,或者使用 key 生成函数将其转换为 key 。

当然,如果您的数据在传输过程中损坏,也会发生错误填充。

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

  • 对于基于密码的加密,您应该使用 SecretKeyFactory 和 PBEKeySpec 而不是使用带有 KeyGenerator 的 SecureRandom。原因是 SecureRandom 可能是每个 Java 实现上的不同算法,为您提供不同的 key 。 SecretKeyFactory 以定义的方式执行 key 派生(如果您选择正确的算法,这种方式被认为是安全的)。

  • 不要使用 ECB 模式。它独立加密每个 block ,这意味着相同的纯文本 block 也总是给出相同的密文 block 。

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

  • 您通常不仅需要保密,还需要身份验证,以确保消息不被篡改。 (这也可以防止对您的密码进行选择密文攻击,即有助于保密。)因此,在您的消息中添加一个 MAC(消息身份验证代码),或使用包含身份验证的密码模式(请参阅前一点)。

  • DES 的有效 key 大小仅为 56 位。这个 key 空间非常小,可以在几个小时内被专门的攻击者暴力破解。如果您通过密码生成 key ,这将变得更快。此外,DES 的 block 大小仅为 64 位,这增加了链接模式的一些弱点。改用像 AES 这样的现代算法,它的 block 大小为 128 位, key 大小为 128 位(对于最常见的变体,也存在 196 和 256 的变体)。

关于java - 给定最终 block 未正确填充,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8049872/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com