java - BadPaddingException 仅包含 "o"、 "b"、 "c"等字母

标签 java exception encryption cryptography

我正在制作一个程序,该程序可以通过 Socket 处理消息加密。但是,当我的消息中包含“o”、“b”或“c”和其他字母时,我会在解密时刻收到该异常。

Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
    at com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:975)
    at com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1056)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:853)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
    at javax.crypto.Cipher.doFinal(Cipher.java:2164)
    at teste1.Decrypt.decrypt(Decrypt.java:15)
    at teste1.Server.main(Server.java:24)

是的,我的消息已包含所有字符,因此我不认为某些字符在传输过程中丢失。所以我真的不知道问题是什么,因为我尝试改变很多东西,但我继续收到这个异常。

解密类:

package teste1;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;

public class Decrypt{

    String IV = "AAAAAAAAAAAAAAAA";

    public String decrypt(String str, String keys) throws Exception{
        Cipher decrypt = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");
        SecretKeySpec key = new SecretKeySpec(keys.getBytes("UTF-8"), "AES");
        decrypt.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(IV.getBytes("UTF-8")));
        return new String(decrypt.doFinal(str.getBytes()),"UTF-8");
    }

}

如果也想要加密类:

package teste1;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class Encrypt {

    String IV = "AAAAAAAAAAAAAAAA";

    public byte[] encrypt(String menE, String keys) throws Exception {
        Cipher encrypt = Cipher.getInstance("AES/EBC/PKCS5Padding", "SunJCE");
        SecretKeySpec key = new SecretKeySpec(keys.getBytes("UTF-8"), "AES");
        encrypt.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(IV.getBytes("UTF-8")));
        return encrypt.doFinal(menE.getBytes());
    }
}

最佳答案

发生这种情况是因为字符串改变了你的字节,你真的应该使用 Base64 如果字符串是必须的。

如果您想测试运行此代码:

byte[] aByte = {-45};
System.out.println(Arrays.toString(new String(aByte, StandardCharsets.UTF_8).getBytes(StandardCharsets.UTF_8)));

它将输出:[-17, -65, -67](不是 -45)。

无论如何,给你一些提示:

  • 您无法使用“ECB”加密并使用“CBC”解密。
  • IV不应该是一个常数。您应该为每条消息生成一个新的 IV 并将其与消息一起发送。
  • 不要指定“UTF-8”使用StandardCharsets.UTF_8(请注意,如果使用android:StandardCharsets.UTF-8是API 19+ 所以你应该有一个常量 Charset.forName("UTF-8"))

以下是一些有关如何使用 Base64 执行此操作的示例代码:

public byte[] encrypt(String message, String key, String iv) throws Exception {
        Cipher encrypt = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");
        SecretKeySpec secretKey = new SecretKeySpec(Base64.getDecoder().decode(key), "AES");
        encrypt.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(Base64.getDecoder().decode(iv)));
        return encrypt.doFinal(/*Get bytes from your message*/message.getBytes(StandardCharsets.UTF_8));
    }

    public String decrypt(String encryptedMessage, String key, String iv) throws Exception{
        Cipher decrypt = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");
        SecretKeySpec secretKey = new SecretKeySpec(Base64.getDecoder().decode(key), "AES");
        decrypt.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(Base64.getDecoder().decode(iv)));
        return new String(decrypt.doFinal(Base64.getDecoder().decode(encryptedMessage)), StandardCharsets.UTF_8);
    }

并运行它

//your message
    String message = "Hello World!";
    //generate a new AES key. (an AES key is just a random sequence 16 bytes)
    SecureRandom random = new SecureRandom();
    byte[] aesKey = new byte[16];
    random.nextBytes(aesKey);
    //generate a new initialization vector (iv) which is also a random sequence of 16 bytes.
    byte[] iv = new byte[16];
    random.nextBytes(iv);

    String aesKeyAsString = Base64.getEncoder().encodeToString(aesKey);
    String ivAsString = Base64.getEncoder().encodeToString(iv);
    //encrypt
    byte[] encrypted = encrypt(message, aesKeyAsString, ivAsString);
    //enocde your encrypted byte[] to String
    String encryptedString = Base64.getEncoder().encodeToString(encrypted);
    //decrypt
    String decrypted = decrypt(encryptedString, aesKeyAsString, ivAsString);
    //print your results
    System.out.println("Encrypted: " + encryptedString + " Decrypted: " + decrypted);

输出:

加密:|加密字符串取决于生成的 key 和 iv|解密:世界你好!

您还可以使用更有效的方法,使用 byte[] 而不是字符串,但这是您的选择。

关于java - BadPaddingException 仅包含 "o"、 "b"、 "c"等字母,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55384527/

相关文章:

java - Google Play 服务查找我的位置很慢

c++ - C++中的对象销毁

c# - VB.net 中奇怪的调试器行为

c# - ASP引发MySQL异常的解决方法

java - 不使用 String 或 Charset 的 UTF-8 字符数组到字节数组

Java CryptoCipher 不消耗所有输入字节

C# 与 Java - 通用列表

java - 压缩大量pdf文件并下载 : OutOfMemoryError: Java heap space

java - 一个使用 Java 解决对数数学问题的程序

Python - 如何打印有多少网站支持每个密码套件请求