继续获取 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);