当前位置: 首页 > 知识库问答 >
问题:

IllegalBlocksizeException:在tcp中使用填充密码解密时,输入长度必须是16的倍数

杜俊楚
2023-03-14
    public class AESEncDec {

     private static final String ALGO = "AES";
    private static final byte[] keyValue =  new byte[] { 'T', 'h', 'e', 'B','e', 's', 't','S', 'e', 'c', 'r','e', 't', 'K', 'e', 'y' };


public static String encrypt(String Data) throws Exception {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.ENCRYPT_MODE, key);
        byte[] encVal = c.doFinal(Data.getBytes());
        String encryptedValue = new BASE64Encoder().encode(encVal);
        System.err.println("encVal: "+encryptedValue.length());

        return encryptedValue;
    }

    public static String decrypt(String encryptedData) throws Exception {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.DECRYPT_MODE, key);
        byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
        byte[] decValue = c.doFinal(decordedValue);
        //byte[] decValue = c.doFinal(encryptedData.getBytes());
        String decryptedValue = new String(decValue);
        System.err.println("decVal: "+decryptedValue.length());

        return decryptedValue;
    }
    private static Key generateKey() throws Exception {
        Key key = new SecretKeySpec(keyValue, ALGO);
        return key;
}

}
    class TCPServer
    {
      public static void main(String argv[]) throws Exception
      {
          AESEncDec edData= new AESEncDec();
           // AES edData= new AES();

         String msg="Message_";
         String clientSentence="";
         String capitalizedSentence;
         ServerSocket welcomeSocket = new ServerSocket(6789);
         Socket connectionSocket = welcomeSocket.accept();
          for (int i = 0; i < 10; i++) 
         {
            clientSentence=edData.encrypt(msg+i)+"\n";
            DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
            outToClient.writeBytes(clientSentence);
            Thread.sleep(100);
         }
      }
}

TCP客户端代码:

    class TCPClient {

    public static void main(String argv[]) throws Exception {

        AESEncDec edData= new AESEncDec();
        String modifiedSentence;
        String DecData="";
        Socket clientSocket = new Socket("localhost", 6789);
        while(true){
         BufferedReader inFromServer = new BufferedReader(new  InputStreamReader(clientSocket.getInputStream()));
         modifiedSentence = inFromServer.readLine();
         DecData=edData.decrypt(modifiedSentence);
         System.out.println("FROM SERVER: " + DecData);   
        }

        //clientSocket.close();
    }
    }

对于相同的代码,当消息很小时,它会被正确解密。但是当消息很长时,我会得到illegalBlocksize异常。我尝试使用aes/cbc/pkcs5padding来填充消息,并且blocksize是16的倍数。但我还是得到了相同的错误或BadPaddingException。如果am指定PKCS5Padding作为填充技术,那么应该正确填充消息,而不应该给出此错误。为什么不起作用。我可以做什么来正确地解密数据。请帮忙。

共有1个答案

晁璞
2023-03-14

AES是一种分组密码,只能加密16到16字节。如果要加密任意输入,则需要操作模式和填充方案。默认模式通常是ECB,默认填充方案是PKCS#5填充(实际上是PKCS#7填充)。

这意味着单个加密也必须以完全相同的方式解密,因为必须在解密期间删除填充。重要的是,多个密文不能重叠,也不能分开(分块/包装)。
在加密多个消息时,换行符应该这样做,因为您在接收端以线性方式读取密文。

问题是默认的sun.misc.base64encoder#encode方法实际上会自己引入换行符。每76个字符插入一个换行,但是接收者无法知道哪个换行实际上分隔了消息密文,哪个换行分隔了单个消息密文中的包装行。

String encryptedValue = new BASE64Encoder().encode(encVal).replaceAll("\\s", "");

这将替换单个消息密文中的所有空白。

由于您使用的是私有的sun.misc.*类,因此最好转移到另一个Base64实现,因为这些类不必在每个JVM中都可用。您应该使用一些已知的库,如Apache的commons-codec,它提供了一个可以禁用包装/分块的实现:

String encryptedValue = Base64.encodeBase64(encVal, false);

相当于

String encryptedValue = Base64.encodeBase64(encVal);
 类似资料: