Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/394.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 给定的最终块未正确填充_Java_Exception_Encryption_Cryptography_Javax.crypto - Fatal编程技术网

Java 给定的最终块未正确填充

Java 给定的最终块未正确填充,java,exception,encryption,cryptography,javax.crypto,Java,Exception,Encryption,Cryptography,Javax.crypto,我正在尝试实现基于密码的加密算法,但遇到以下例外情况: javax.crypto.BadPaddingException:给定的最后一个块未正确填充 有什么问题吗 这是我的密码: public class PasswordCrypter { private Key key; public PasswordCrypter(String password) { try{ KeyGenerator generator;

我正在尝试实现基于密码的加密算法,但遇到以下例外情况:

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测试)

公共类密码密码测试{
private static final byte[]MESSAGE=“羊驼太棒了!”.getBytes();
私有密码加密程序[]密码加密程序;
专用字节[][]加密消息;
@以前
公共作废设置(){
passwordCrypters=新的passwordCrypters[]{
新密码密码器(“passwd”),
新密码密码器(“passwd”),
新密码密码器(“其他密码”)
};
encryptedMessages=新字节[passwordCrypters.length][];
for(int i=0;i
根据您使用的加密算法,在加密字节数组之前,您可能必须在末尾添加一些填充字节,以便字节数组的长度是块大小的倍数:

具体来说,在您的案例中,您选择的填充模式是PKCS5,如下所述:

(我假设您在尝试加密时遇到问题)

您可以在实例化密码对象时选择填充模式。支持的值取决于您使用的安全提供程序


顺便问一下,您确定要使用对称加密机制来加密密码吗?单向散列不是更好吗?如果您真的需要能够解密密码,DES是一个相当弱的解决方案,如果您需要使用对称算法,您可能会对使用AES之类的更强大的解决方案感兴趣。

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

因此,如果出现此异常,请捕获它并将其视为“错误的键”。

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

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

也就是说,您的计划中有一些安全问题:

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

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

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

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

  • DES的有效密钥大小只有56位。该密钥空间非常小,可以在几个小时内由专用攻击者强制执行。如果您通过密码生成密钥,这将更快。 此外,DES的块大小只有64位,这在链接模式中增加了一些弱点。 改用AES等现代算法,其块大小为128位,密钥大小为 128位(对于标准变体)


我遇到这个问题是因为操作系统,对于JRE实现的不同平台很简单

new SecureRandom(key.getBytes())
将在Windows中获得相同的值,而在Linux中则不同。所以在Linux中需要改为

SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(key.getBytes());
kgen.init(128, secureRandom);

“SHA1PRNG”是使用的算法,您可以参考有关算法的更多信息。

当您为签名密钥输入错误的密码时,这也可能是一个问题。

因此,您可以发布尝试加密/解密的代码吗?(并检查您尝试解密的字节数组是否不大于块大小)我对Java和密码学非常陌生
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(key.getBytes());
kgen.init(128, secureRandom);