当前位置: 首页 > 面试题库 >

Java给定最终块未正确填充

宋晋
2023-03-14
问题内容

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

  • 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位(对于标准变体)。



 类似资料:
  • 我想加密EnteredDetails(java bean)类型的arraylist,并将其序列化到一个文件中。我正在关注AES-128位加密的链接:http://www . code 2 learn . com/2011/06/encryption-and-decryption-of-data-using . html 要使用aes class的encrypt方法,我必须将arrarylist转换

  • 问题内容: 我需要有关此错误的帮助:给最终块未正确填充。从标题中可以看到,我正在使用AES。 这是错误的行代码: 这是完整的代码: } 问题答案: 根据您的评论,您几乎可以使加密工作。 您需要将IV生成代码从您的加密/解密方法移动到其他地方,就像这样 然后将该ivspec传递到加密和解密方法中(使它们看起来像),这样您就可以为加密和解密使用相同的iv。 另外,不要调用decryptedByteAr

  • 首先,我会告诉你我的主要目标是什么。在客户端使用AES加密部分内容,然后使用RSA公钥加密重要的AES规范,并将AES加密数据和RSA加密的AES规范发送到服务器端。所以在服务器端,我将使用RSA私钥解密AES密钥规范,然后使用这些AES规范,我将解密AES加密数据。通过测试加密和解密,我成功地使RSA部分工作。在此实现RSa之前,我必须使AES art工作。 对于客户端,我使用crypto-js

  • 问题内容: 根据该Jetty指南中有关使用Keytool和OpenSSL的步骤3b(最后一步),我正在执行以下命令: 当我运行命令时,我得到: 你知道如何解决吗? 问题答案: 就我而言,我使用下载的Windows openSSL完成了一些步骤,而其他步骤则使用了CentOs6框上已经存在的openSSL。当我在CentOs / linux机器上执行所有步骤时,错误消失了。 次要的或许是注意linu

  • 我正在尝试编写方法来加密或解密字符串(大部分是数字)。它适用于某些文本(例如-'1010000011'、'1010000012'、'1010000013'),但也适用于其他文本(例如-'1010000014'、'1010000018'): javax.crypto.BadPadding异常:给定最后一个块没有正确填充 这是我的代码: 要加密的字符串从文件中读取,并在加密后写入其他文件。这些加密的文

  • 我正在做一个简单的加密文件传输系统,现在停止运行时异常: 我试图用一个字符串调试我的代码,用相同的密钥加密和解密,它是有效的。然而,当我试图从文件传输流时,这个异常总是出现。 以下是双方的代码。首先,他们将通过RSA交换对称密钥(AES密钥),然后通过AES加密传输大型文件。我们可以关注每段代码的最后一部分,其中文件通过AES密钥进行加密和解密。 服务器端: 客户端: