继续获取 javax.crypto.IllegalBlockSizeException:使用填充密码解密时,输入长度必须是 16 的倍数
Keep getting javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
在套接字之间的 java 中编码 AES-192 算法时,我不断收到该异常,而且我不知道如何修复它。我认为这一定与我在其他 post 中读到的服务器解码方式有关,但我无法正确理解。我的 java 版本是 13,以备不时之需。感谢您的帮助。
*注意:有些已实现的库可能未被使用,来自以前的尝试使其正常工作
服务器代码
import java.net.*;
import java.io.*;
import java.util.*;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class Bob {
private Socket socket = null;
private ServerSocket bob = null;
private DataInputStream in = null;
public Bob(int port) {
try {
bob = new ServerSocket(port);
socket = bob.accept();
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
String ciphertext = "";
while(!ciphertext.equals("Stop")){
try{
ciphertext = in.readUTF();
System.out.println("Received ciphertext: " + ciphertext);
String plaintext = decrypt(ciphertext);
System.out.println("Decrypted plaintext: " + plaintext + "\n");
}catch(Exception e){
System.out.println(e);
}
}
socket.close();
in.close();
}
catch(IOException i)
{
System.out.println(i);
}
}
public static String decrypt(String encrypted) {
try {
int ivSize = 16;
int keySize = 24;
String key = "i5q5jZFd73kuK3wG2jTCvtWp";
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
byte[] encryptedIvTextBytes = encrypted.getBytes();
byte[] iv = new byte[ivSize];
System.arraycopy(encryptedIvTextBytes, 0, iv, 0, iv.length);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
int ciphertextLength = encryptedIvTextBytes.length - ivSize;
byte[] ciphertextB = new byte[ciphertextLength];
System.arraycopy(encryptedIvTextBytes,ivSize,ciphertextB,0,ciphertextLength);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec);
byte[] original = cipher.doFinal(Base64.getDecoder().decode(ciphertextB));
eturn new String(original);
} catch (Exception e) {
System.out.println(e);
}
return null;
}
public static void main(String args[]) {
Bob bob = new Bob(3125);
}
}
客户端代码
import java.net.*;
import java.io.*;
import javax.crypto.*;
import java.security.*;
import java.util.*;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Base64;
public class Alice {
private Socket socket = null;
private DataOutputStream out = null;
private BufferedReader in = null;
public Alice(String address, int port) {
try {
socket = new Socket(address, port);
in = new BufferedReader(new InputStreamReader(System.in));
out = new DataOutputStream(socket.getOutputStream());
} catch(UnknownHostException u) {
System.out.println(u);
} catch(IOException i) {
System.out.println(i);
}
String plaintext = "";
while(!plaintext.equals("Stop")){
try {
System.out.println("Introduce plaintext:");
plaintext = in.readLine();
String ciphertext = encrypt(plaintext);
System.out.println("Encrypted: " + ciphertext + "\n");
out.writeUTF(ciphertext);
} catch(IOException i) {
System.out.println(i);
}
}
try {
socket.close();
in.close();
out.close();
} catch(IOException i) {
System.out.println(i);
}
}
public static String encrypt(String value) {
try {
String key = "i5q5jZFd73kuK3wG2jTCvtWp";
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
int ivSize = 16;
byte[] iv = new byte[ivSize];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParameterSpec);
byte[] encrypted = cipher.doFinal(value.getBytes());
byte[] encryptedAndIV = new byte[ivSize + encrypted.length];
System.arraycopy(iv, 0, encryptedAndIV, 0, ivSize);
System.arraycopy(encrypted, 0, encryptedAndIV, ivSize, encrypted.length);
return new String(Base64.getEncoder().encode(encryptedAndIV));
} catch (Exception e) {
throw new RuntimeException("Error occured while encrypting data", e);
}
}
public static void main(String args[]) {
Alice alice = new Alice("localhost", 3125);
}
}
您的问题出在您的解密例程中。通常,在 CBC 中,您必须遵循
加密;
- 加密消息和 returns 字节
- 使用
size=IV.lenght+encrypted.lenght
将 IV 添加到更大的字节数组中
- 通过复制
IV||encrypted
将加密字节附加到较大的字节中
- 将字节编码为 base64(或类似的)
base64(IV||encrypted
)
- 发送消息
解密;
- 获取消息
- 将消息从 base64 解码为字节
- 从字节的开头提取 IV
- 从字节中提取加密字节
- 加密字节以获取消息
在您的代码中,您没有在解密前解码字节以提取 IV,而是在解密过程中进行的。
ByteBuffer buffer = ByteBuffer.wrap(new Base64().decode(encryptedText));
//get the IV from the bytes
byte[] iv = new byte[ivSize];
buffer.get(iv, 0, iv.length);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
//get the encrypted bytes
byte[] encryptedTextBytes = new byte[buffer.capacity() - iv.length];
buffer.get(encryptedTextBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec);
byte[] original = cipher.doFinal(encryptedTextBytes);
在套接字之间的 java 中编码 AES-192 算法时,我不断收到该异常,而且我不知道如何修复它。我认为这一定与我在其他 post 中读到的服务器解码方式有关,但我无法正确理解。我的 java 版本是 13,以备不时之需。感谢您的帮助。
*注意:有些已实现的库可能未被使用,来自以前的尝试使其正常工作
服务器代码
import java.net.*;
import java.io.*;
import java.util.*;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class Bob {
private Socket socket = null;
private ServerSocket bob = null;
private DataInputStream in = null;
public Bob(int port) {
try {
bob = new ServerSocket(port);
socket = bob.accept();
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
String ciphertext = "";
while(!ciphertext.equals("Stop")){
try{
ciphertext = in.readUTF();
System.out.println("Received ciphertext: " + ciphertext);
String plaintext = decrypt(ciphertext);
System.out.println("Decrypted plaintext: " + plaintext + "\n");
}catch(Exception e){
System.out.println(e);
}
}
socket.close();
in.close();
}
catch(IOException i)
{
System.out.println(i);
}
}
public static String decrypt(String encrypted) {
try {
int ivSize = 16;
int keySize = 24;
String key = "i5q5jZFd73kuK3wG2jTCvtWp";
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
byte[] encryptedIvTextBytes = encrypted.getBytes();
byte[] iv = new byte[ivSize];
System.arraycopy(encryptedIvTextBytes, 0, iv, 0, iv.length);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
int ciphertextLength = encryptedIvTextBytes.length - ivSize;
byte[] ciphertextB = new byte[ciphertextLength];
System.arraycopy(encryptedIvTextBytes,ivSize,ciphertextB,0,ciphertextLength);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec);
byte[] original = cipher.doFinal(Base64.getDecoder().decode(ciphertextB));
eturn new String(original);
} catch (Exception e) {
System.out.println(e);
}
return null;
}
public static void main(String args[]) {
Bob bob = new Bob(3125);
}
}
客户端代码
import java.net.*;
import java.io.*;
import javax.crypto.*;
import java.security.*;
import java.util.*;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Base64;
public class Alice {
private Socket socket = null;
private DataOutputStream out = null;
private BufferedReader in = null;
public Alice(String address, int port) {
try {
socket = new Socket(address, port);
in = new BufferedReader(new InputStreamReader(System.in));
out = new DataOutputStream(socket.getOutputStream());
} catch(UnknownHostException u) {
System.out.println(u);
} catch(IOException i) {
System.out.println(i);
}
String plaintext = "";
while(!plaintext.equals("Stop")){
try {
System.out.println("Introduce plaintext:");
plaintext = in.readLine();
String ciphertext = encrypt(plaintext);
System.out.println("Encrypted: " + ciphertext + "\n");
out.writeUTF(ciphertext);
} catch(IOException i) {
System.out.println(i);
}
}
try {
socket.close();
in.close();
out.close();
} catch(IOException i) {
System.out.println(i);
}
}
public static String encrypt(String value) {
try {
String key = "i5q5jZFd73kuK3wG2jTCvtWp";
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
int ivSize = 16;
byte[] iv = new byte[ivSize];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParameterSpec);
byte[] encrypted = cipher.doFinal(value.getBytes());
byte[] encryptedAndIV = new byte[ivSize + encrypted.length];
System.arraycopy(iv, 0, encryptedAndIV, 0, ivSize);
System.arraycopy(encrypted, 0, encryptedAndIV, ivSize, encrypted.length);
return new String(Base64.getEncoder().encode(encryptedAndIV));
} catch (Exception e) {
throw new RuntimeException("Error occured while encrypting data", e);
}
}
public static void main(String args[]) {
Alice alice = new Alice("localhost", 3125);
}
}
您的问题出在您的解密例程中。通常,在 CBC 中,您必须遵循
加密;
- 加密消息和 returns 字节
- 使用
size=IV.lenght+encrypted.lenght
将 IV 添加到更大的字节数组中
- 通过复制
IV||encrypted
将加密字节附加到较大的字节中
- 将字节编码为 base64(或类似的)
base64(IV||encrypted
) - 发送消息
解密;
- 获取消息
- 将消息从 base64 解码为字节
- 从字节的开头提取 IV
- 从字节中提取加密字节
- 加密字节以获取消息
在您的代码中,您没有在解密前解码字节以提取 IV,而是在解密过程中进行的。
ByteBuffer buffer = ByteBuffer.wrap(new Base64().decode(encryptedText));
//get the IV from the bytes
byte[] iv = new byte[ivSize];
buffer.get(iv, 0, iv.length);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
//get the encrypted bytes
byte[] encryptedTextBytes = new byte[buffer.capacity() - iv.length];
buffer.get(encryptedTextBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec);
byte[] original = cipher.doFinal(encryptedTextBytes);