java 执行对称加密解密时出现BadPaddingException

pkbketx9  于 2023-01-24  发布在  Java
关注(0)|答案(2)|浏览(244)

我得到异常,而按照下面的逻辑进行解密。请建议我在下面的代码片段的任何问题。加密是罚款和能够加密。

public String encryptDataSymmetric(String dataTobeEncrypted) {
    String encryptedData = null;
    try {
        Charset CHARSET = Charset.forName("UTF8");
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        SecureRandom securerandom = new SecureRandom();
        KeyGenerator keygenerator = KeyGenerator.getInstance("AES");
        keygenerator.init(192, securerandom);
        SecretKey key = keygenerator.generateKey();
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        // cipher.init(Cipher.ENCRYPT_MODE, key, ivspec);
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(new byte[cipher.getBlockSize()]));
        encryptedData = DatatypeConverter.printBase64Binary(cipher.doFinal(dataTobeEncrypted.getBytes(CHARSET)))
                .trim();
        System.out.println("---encryptedData-----" + encryptedData);
    } catch (Exception ex) {
        ex.printStackTrace();
    }

    return encryptedData;
}

public String decryptDataSymmetric(String dataTobeDecrypted) {
    String decryptedData = null;
    try {
        Charset CHARSET = Charset.forName("UTF8");
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        SecureRandom securerandom = new SecureRandom();
        KeyGenerator keygenerator = KeyGenerator.getInstance("AES");
        keygenerator.init(192, securerandom);
        SecretKey key = keygenerator.generateKey();
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(new byte[cipher.getBlockSize()]));
        decryptedData = new String(
                DatatypeConverter.parseBase64Binary(new String(cipher.doFinal(dataTobeDecrypted.getBytes()))));
        System.out.println("---decryptedData----" + decryptedData);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return decryptedData;
}

javax.crypto.BadPaddingException:填充块在org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(未知源)处损坏

qyswt5oh

qyswt5oh1#

不是一个Java爱好者,但是你需要从Base64解码到字节数组,在你解密它的时候,在把它传递给密码之前,而不是在你试图解密它之后。
Base64编码是将字节流编码为ascii字符,以便于传输。在传输的接收端,需要先将base64编码转换为字节流。
解密之后,你必须把解密后的字节数组转换成字符串。
总之,解密必须撤消加密方法的步骤。
加密方法:

  • 通过UTf8从字符串转换为纯字节数组
  • 通过密码将普通字节数组转换为加密字节数组
  • 通过base64编码将加密字节数组转换为可打印/可序列化字符串

解密方法:

  • 通过base64解码将可打印/序列化字符串转换为加密字节数组
  • 通过密码将加密字节数组转换为纯字节数组
  • 通过UTF从字节到字符串调用将纯字节数组转换为字符串。

话虽如此,你的代码还是有一些问题。我能够把这个Java示例代码放在一起,只演示我在这里要说明的几点。

*首先,不要将AES与CBC单独使用!!!它容易受到Padding Oracle攻击。无需详细说明,这意味着如果您的系统给出加密消息是否正确填充的哪怕是最轻微的提示(甚至是时间差),就可以非常有效地解密您的加密值。出于同样的原因,不要使用我在下面编写的代码。

  • 使用验证加密方案或算法。
  • 最好是找到一个有信誉的库,这样做,并使用,而不是写自己的。
  • 你需要为每一条加密的消息创建一个IV。IV必须由加密功能强大的随机生成器生成。下面的代码试图做到这一点。
  • 您将IV与加密消息(密文)一起发送(或存储)。IV不是秘密。
  • 在下面的代码中,密钥是随机生成的,然后传递给加密和解密方法。你需要做同样的事情,创建你将使用一次的密钥。然后找到一个安全的方法(保险库类型的结构/服务)来存储你使用的密钥。
  • 你需要考虑和制定计划,你要做什么,如果关键不知何故得到了妥协?看看密钥到期方案,滑动键等...
  • 在下面的代码中,我不是一个Java开发人员,我试图用我能找到的最简单和标准的方法来演示。
/*
DO NOT USE THIS CODE! It is vulnerable to Padding Oracle Attack!
Instead use an Authenticated Encryption scheme or algorithm.
This code is written for demonstration purpose only!! Not secure!!
*/
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.io.Console;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.util.Base64;

public class Main {

public static String encryptDataSymmetric(String dataTobeEncrypted, SecretKey key) {
    String encryptedData = null;
    try {
        Charset CHARSET = Charset.forName("UTF8");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        
        SecureRandom securerandom = new SecureRandom();
        byte[] ivBytes = new byte[cipher.getBlockSize()];
        securerandom.nextBytes(ivBytes);
        IvParameterSpec iv = new IvParameterSpec(ivBytes); 
        cipher.init(Cipher.ENCRYPT_MODE, key, iv);
        byte[] cipherText = cipher.doFinal(dataTobeEncrypted.getBytes(CHARSET));

        System.out.println("---IV----" + Base64.getEncoder().encodeToString(ivBytes));
        
        byte[] ivAndCipherText = new byte[ivBytes.length + cipherText.length];
        
        System.arraycopy(ivBytes, 0, ivAndCipherText, 0, ivBytes.length);
        System.arraycopy(cipherText, 0, ivAndCipherText, ivBytes.length, cipherText.length);
        encryptedData = Base64.getEncoder().encodeToString(ivAndCipherText);
        System.out.println("---encryptedData-----" + encryptedData);
    } catch (Exception ex) {
        ex.printStackTrace();
    }

    return encryptedData;
}

public static String decryptDataSymmetric(String cipherBase64Encoded, SecretKey key) {
    String encryptedData = null;
    try {
        Charset CHARSET = Charset.forName("UTF8");
         Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        
        byte[] ivAndCipherText = Base64.getDecoder().decode(cipherBase64Encoded);
        
        byte[] iv = new byte[cipher.getBlockSize()];
        System.arraycopy(ivAndCipherText, 0, iv, 0, iv.length);

        byte[] cipherText = new byte[ivAndCipherText.length - iv.length];
        System.arraycopy(ivAndCipherText, iv.length, cipherText, 0, cipherText.length);
        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
        return new String(cipher.doFinal(cipherText),CHARSET);
    } catch (Exception ex) {
        ex.printStackTrace();
    }

    return encryptedData;
}

    public static void main(String args[]) {
        try {
            SecureRandom securerandom = new SecureRandom();
            KeyGenerator keygenerator = KeyGenerator.getInstance("AES");
            keygenerator.init(192, securerandom);
            SecretKey key = keygenerator.generateKey();
            System.out.println("---key---" + key.getEncoded());
        
        
            String str = "Hello bye";
            //Console.Write(decryptDataSymmetric(encryptDataSymmetric(str)));
            System.out.println(str);
            String encrypted = encryptDataSymmetric(str, key);
            String plainText = decryptDataSymmetric(encrypted, key);
            System.out.println("plaintext: " + plainText);
            System.out.println("The end!");
        } catch (Exception ex) {
        ex.printStackTrace();
    }
    }
}
jaql4c8m

jaql4c8m2#

我同意PhazorP上面的评论。

  • 请勿单独使用AES和CBC
  • 使用验证加密方案或算法。

我鼓励你使用一个经过认证的加密算法,这是我不久前写的一个简短的博客article,可能会有帮助。
如果你想看一下,这里也有一些AES-GCM的java代码。

相关问题