当前位置: 首页 > 知识库问答 >
问题:

BadPaddingException:给定的最终块没有正确填充-奇怪的错误

爱琪
2023-03-14
public String decrypt(String text) throws Exception {

    String key = "SiadajerSiadajer"; // 128 bit key
    // Create key and cipher
    Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
    Cipher cipher = Cipher.getInstance("AES");
    // encrypt the text
    byte[]encrypted = text.getBytes();
    cipher.init(Cipher.DECRYPT_MODE, aesKey);
    String decrypted = new String(cipher.doFinal(encrypted)); //Here is the error

    return decrypted;


}
function encrypt($data, $size)
{
    $length = $size - strlen($data) % $size;
    return $data . str_repeat(chr($length), $length);
}

function decrypt($data)
{
    return substr($data, 0, -ord($data[strlen($data) - 1]));
}
$key = "SiadajerSiadajer";
$iv_size = 16; // 128 bits
$iv = openssl_random_pseudo_bytes($iv_size, $strong);
$name = openssl_encrypt(encrypt($name, 16), 'AES-256-CBC', $key, 0, $iv);

现在在php部分,我的代码是:

$key = "SiadajerSiadajer";
$iv_size = 16; // 128 bits
$iv = openssl_random_pseudo_bytes($iv_size, $strong);
$EIV = base64_encode($iv);
$name = openssl_encrypt(encrypt($name, 16), 'AES-256-CBC', $key, 0, $EIV);

它给我一个警告:警告:openssl_encrypt():IV传递的是24字节长,比所选密码预期的16字节长,在第68行的C:\xampp2\htdocs\standardfinalinserting.php中截断

在Java部分,我的解密方法与我的问题的答案完全相同,但在运行后,它给我一个错误:Java.security.invalidkeyexception:行上非法的密钥大小:

所以这就是我的整个主课。它包含您的整个Java代码示例

public class Main {

    private byte[] padKey(byte[] key) {
        byte[] paddedKey = new byte[32];
        System.arraycopy(key, 0, paddedKey, 0, key.length);
        return paddedKey;
    }

    private byte[] unpad(byte[] data) {     
        byte[] unpaddedData = new byte[data.length - data[data.length - 1]];
        System.arraycopy(data, 0, unpaddedData, 0, unpaddedData.length);
        return unpaddedData;
    }

    public String decrypt(String encodedJoinedData) throws Exception {

        // Base64-decode the joined data
        byte[] joinedData = Base64.decode(encodedJoinedData); 

        // Get IV and encrypted data
        byte[] iv = new byte[16];
        System.arraycopy(joinedData, 0, iv, 0, iv.length);
        byte[] encryptedData = new byte[joinedData.length - iv.length];
        System.arraycopy(joinedData, iv.length, encryptedData, 0, encryptedData.length);

        // Pad key
        byte[] key = padKey("SiadajerSiadajer".getBytes()); 
        Key aesKey = new SecretKeySpec(key, "AES");

        // Specify CBC-mode
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); 
        cipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec); //HERE IS THE ERROR

        // Decrypt data
        byte[] decryptedData = cipher.doFinal(encryptedData);

        // Remove custom padding
        byte[] unpaddedData = unpad(decryptedData);         

        return new String(unpaddedData);
    }

    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
         String encodedJoinedData = "RB6Au33KGOF1/z3BQKqievUmh81Y8q4uw7s4vEs9xurQmNZAKwmhRQtS9wGYKQj8cJaPpK2xaDzx3RppQ8PsM/rQ9/p0Lme+x75dozBEbmFn6Q9eCXOCiCivVsKzZ8Vz";
            String decryptedData = new Main().decrypt(encodedJoinedData);
            System.out.println(decryptedData + " - " + decryptedData.length());



     }



}

运行代码会导致错误:

Exception in thread "main" java.security.InvalidKeyException: Illegal key size
    at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1039)
    at javax.crypto.Cipher.implInit(Cipher.java:805)
    at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
    at javax.crypto.Cipher.init(Cipher.java:1396)
    at javax.crypto.Cipher.init(Cipher.java:1327)
    at com.dd.escuel.Main.decrypt(Main.java:43)
    at com.dd.escuel.Main.main(Main.java:57)

共有1个答案

薛博艺
2023-03-14

Java代码存在一些问题:

>

  • 在PHP代码中使用AES-256,因此,密钥的长度必须为32字节。较短的键自动右加零。这发生在PHP代码中,因为您的键siadajersiadajer的长度只有16字节。键填充也必须在Java代码中完成。为此,可以使用以下Java-method:

    private byte[] padKey(byte[] key) {
        byte[] paddedKey = new byte[32];
        System.arraycopy(key, 0, paddedKey, 0, key.length);
        return paddedKey;
    }
    

    对于cipher.getinstance(“aes”),默认情况下选择ecb-mode和pkcs5paddingcbc-mode必须在Java-code中显式指定

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    
    byte[]encryptedData = Base64.decode(text); 
    
    $encodedIV = base64_encode($iv);
    
    byte[] iv = Base64.decode(ivEncoded);
    IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); 
    ...
    cipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);
    

    在PHP-methodopenSSL_encrypt中,第四个参数$options被设置为0,这意味着使用默认填充(PKCS7)。此外,在PHP-methodencrypt中实现了一种自定义填充(顺便说一句:方法的名称不合适,因为它不加密),因此它被填充了两次。因此,在解密之后,必须删除Java代码中的自定义填充(可能包含空白):

    byte[] unpaddedData = unpad(decryptedData);
    

    private byte[] unpad(byte[] data) {     
        byte[] unpaddedData = new byte[data.length - data[data.length - 1]];
        System.arraycopy(data, 0, unpaddedData, 0, unpaddedData.length);
        return unpaddedData;
    }
    

    总共:

    public String decrypt(String text, String ivEncoded) throws Exception {
    
        // Pad key
        byte[] key = padKey("SiadajerSiadajer".getBytes()); 
        Key aesKey = new SecretKeySpec(key, "AES");
    
        // Base64 decode data
        byte[]encryptedData = Base64.decode(text); 
    
        // Base64 decode iv
        byte[] iv = Base64.decode(ivEncoded);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); 
    
        // Specify CBC-mode
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
        cipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);
    
        // Decrypt
        byte[] decryptedData = cipher.doFinal(encryptedData);
    
        // Remove custom padding
        byte[] unpaddedData = unpad(decryptedData);         
    
        return new String(unpaddedData);
    }
    
    $data = 'This is a plain text which needs to be encrypted...';
    $key = "SiadajerSiadajer";
    
    $encodedIV = 'Dg+Zs3mqIJeDOOEPMT5F4Q==';
    $name = '8dXjeQhx2WSswQOQXLcyMKNpa5s413yI2Ku8WiIB/xtA2pEjrKcl5kWtrOh9k4A12Jl0N/z6tH67Wybhp/OwTi1NtiJOZxl3w6YQufE29oU=';
    

    如果该输出用作Java-methoddecrypt的输入,则解密数据等于纯文本。

    关于PHP代码,我建议删除自定义或默认(PKCS7)填充(如果可以选择的话)。后者可以通过使用标志openSSL_zero_padding作为openSSL_encrypt方法中的第四个参数来实现(注意:该标志并不表示“pad with zero-values”,而是表示“no padding”)。如果保留自定义填充,则至少应将PHP-methodsencryptdecrypt分别重命名为padunpad(或类似的内容)。

    正如在注释中已经指出的,gcm-模式可能比-cbc模式更好。但是,在编码之前了解一些基本知识是很有用的,例如cbc-和GCM-模式之间的区别,这里和这里对GCM-mode的解释,以及GCM-mode带来的缺陷(GCM是安全的,但前提是您必须遵循某些指导原则,例如,对使用相同密钥加密的每个消息使用uniqe IV/nonce)。

    您可以使用php方法openssl_get_cipher_methods来查找PHP中支持的允许的AES模式。这里对此有更详细的解释。对于AES-256和AES模式gcm,必须指定aes-256-gcm(用小写(!)字母)。大概,这就是为什么你会得到“未知密码算法”--错误。

    编辑:

    您可以使用以下PHP-code进行加密(它是问题中的PHP-code的稍微修改版本):

    <?php
    function pad($data, $size) {
        $length = $size - strlen($data) % $size;
        return $data . str_repeat(chr($length), $length);
    }
    function unpad($data) {
        return substr($data, 0, -ord($data[strlen($data) - 1]));
    }
    $data = 'This is a plain text which needs to be encrypted...';
    $key = "SiadajerSiadajer";
    $iv_size = 16; 
    $iv = openssl_random_pseudo_bytes($iv_size, $strong);
    $encryptedData = openssl_encrypt(pad($data, 16), 'AES-256-CBC', $key,  0, $iv);
    print base64_encode($iv)."\n".$encryptedData."\n";
    
    <?php
    function pad($data, $size) {
        $length = $size - strlen($data) % $size;
        return $data . str_repeat(chr($length), $length);
    }
    function unpad($data) {
        return substr($data, 0, -ord($data[strlen($data) - 1]));
    }
    $data = 'This is a plain text which needs to be encrypted...';
    $key = "SiadajerSiadajer";
    $iv_size = 16; 
    $iv = openssl_random_pseudo_bytes($iv_size, $strong);
    $encryptedData = openssl_encrypt(pad($data, 16), 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
    $joinedData = $iv.$encryptedData;
    $encodedJoinedData = base64_encode($joinedData);
    print $encodedJoinedData."\n";
    

    Jave-methoddecrypt变为:

    public String decrypt(String encodedJoinedData) throws Exception {
    
        // Base64-decode the joined data
        byte[] joinedData = Base64.decode(encodedJoinedData); 
    
        // Get IV and encrypted data
        byte[] iv = new byte[16];
        System.arraycopy(joinedData, 0, iv, 0, iv.length);
        byte[] encryptedData = new byte[joinedData.length - iv.length];
        System.arraycopy(joinedData, iv.length, encryptedData, 0, encryptedData.length);
    
        // Pad key
        byte[] key = padKey("SiadajerSiadajer".getBytes()); 
        Key aesKey = new SecretKeySpec(key, "AES");
    
        // Specify CBC-mode
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); 
        cipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);
    
        // Decrypt data
        byte[] decryptedData = cipher.doFinal(encryptedData);
    
        // Remove custom padding
        byte[] unpaddedData = unpad(decryptedData);         
    
        return new String(unpaddedData);
    }
    

    Java-methodmain的示例如下:

    public static void main(String[] args) throws Exception {
        String encodedJoinedData = "RB6Au33KGOF1/z3BQKqievUmh81Y8q4uw7s4vEs9xurQmNZAKwmhRQtS9wGYKQj8cJaPpK2xaDzx3RppQ8PsM/rQ9/p0Lme+x75dozBEbmFn6Q9eCXOCiCivVsKzZ8Vz";
        String decryptedData = new Main().decrypt(encodedJoinedData);
        System.out.println(decryptedData + " - " + decryptedData.length());
    }
    

    用法如下:

    $data = 'This is a plain text which needs to be encrypted...';
    
    String encodedJoinedData = "RB6Au33KGOF1/z3BQKqievUmh81Y8q4uw7s4vEs9xurQmNZAKwmhRQtS9wGYKQj8cJaPpK2xaDzx3RppQ8PsM/rQ9/p0Lme+x75dozBEbmFn6Q9eCXOCiCivVsKzZ8Vz";
    
    $encryptedData = openssl_encrypt(pad($data, 16), 'AES-256-CBC', $key,  OPENSSL_RAW_DATA, $iv);
    
    $encryptedData = openssl_encrypt($data, 'AES-256-CBC', $key,  OPENSSL_RAW_DATA, $iv);
    

    并移除pad-和unpad-方法。

    在Java代码中替换行

    // Remove custom padding
    byte[] unpaddedData = unpad(decryptedData);         
    
    return new String(unpaddedData);
    

    return new String(decryptedData);
    

  •  类似资料:
    • 我想加密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

    • 问题内容: 我正在尝试实现基于密码的加密算法,但出现此异常: javax.crypto.BadPaddingException:给定的最终块未正确填充 可能是什么问题? 这是我的代码: (JUnit测试) 问题答案: 如果尝试使用错误的密钥解密填充了PKCS5的数据,然后取消填充(由Cipher类自动完成),则很可能会收到BadPaddingException(可能略小于255/256,约为99.

    • 我正在加密字符串并将其存储在客户端的cookie中。。但是,当我从js向java代码发送完全加密的字符串时,它给出了前面提到的异常。 我用于加密和解密的代码是: 你能告诉我问题是什么吗??我尝试过stackoverflow上提到的解决方案。com和其他一些解决方案,但都不起作用。。我收到这个错误是因为我将加密字符串发送到JS,而它正在更改字符串的填充吗?

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