BadPaddingException在执行对称加密解密时



我在按照以下逻辑进行解密时得到异常。请建议我在以下代码片段的任何问题。加密很好,可以加密。

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: pad块损坏org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(未知源)

不是Java的家伙,但是你需要解码从Base64到字节数组,在你解密它的时候把它传递给密码,而不是在你试图解密它之后。

Base64编码是将字节流编码成ascii字符,用于传输。在传输的接收端,您需要首先将base64编码再次转换为字节流。

在解密之后,你必须将解密后的字节数组转换成字符串。

总而言之,解密必须撤销加密方法的步骤。

加密方法:

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

解密方法:

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

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

  • 首先不要单独使用AES和CBC !!漏洞:不深入细节,这意味着某人可以解密您的加密值非常有效如果您的系统给出最小的提示(甚至是时差)加密消息是否被正确填充。不要因为同样的原因使用我在下面写的代码。
  • 使用经过认证的加密方案或算法
  • 最好找一个有信誉的库来做这件事,然后使用它,而不是自己写。
  • 您需要为每个加密消息创建一个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();
}
}
}

我同意PhazorP上面的评论。

  • 不要单独使用AES与CBC
  • 使用经过认证的加密方案或算法

我建议您使用经过验证的加密算法。这是我不久前写的一篇简短的博客文章,可能会有所帮助。

如果你想看的话,这里有一些用于AES-GCM的java代码。

最新更新