javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher in tcp

荒凉一梦 提交于 2019-12-06 16:20:53

问题


I am using this AES Encrption and decryption method for encrypting my data. There is no problem with udp but when i use tcp i get this error "javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher"

AES Encryption/Decryption Code:

    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;
}

}

TCP SERVER CODE:

    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 CLIENT CODE:

    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();
    }
    }

For the Same code when the message is small it gets decrypted correctly. but when the message is long i get the illegalBlocksize Exception. I tried to use AES/CBC/PKCS5Padding so that the message gets padded and the blocksize comes in a multiple of 16. But still i get either the same error or BadPaddingException. if am specifying PKCS5Padding as the padding technique then the message should be padded correctly and shouldn't be giving this error. why isn't that working. What can i do to decrypt the data correctly. please help..


回答1:


The problem is that TCP gives you a stream. If you read a chunk and try to decrypt it, it may fail, because the size of the chunk may not be in multiples of 16 (or 128). AES works on 16 byte or 128 byte chunks of data. So, you may have to wait for a while till you gather that much amount of data before you decrypt.

Since UDP is message oriented, it doesn't face such problem.

@Kiara, Please use the Java8's built-in encoding and see how it works out. Refer here for documentation. Example:

String asB64 = Base64.getEncoder().encodeToString(data.getBytes("utf-8")); 

That was tested to work good with messages of lengths as much as 7 megabytes. It didn't introduce newlines into the encoded messages.




回答2:


AES is a block cipher and can only encrypt exactly 16 bytes to 16 bytes. If you want to encrypt arbitrary inputs, you need a mode of operation and a padding scheme. The default mode is usually ECB and the default padding scheme is PKCS#5 padding (actually PKCS#7 padding).

That means that a single encryption must also be decrypted in exactly the same way, because the padding must be removed during decryption. It is important that multiple ciphertexts don't overlap and are not broken up (chunked / wrapped).
That is what your newline characters are supposed to do during encryption of multiple messages, because you're reading the ciphertexts linewise at the receiving side.

The problem is that the default sun.misc.BASE64Encoder#encode method actually introduces newlines on its own. Every 76 characters there is a newline inserted, but the receiver cannot know which newline actually separates the message ciphertexts and which newline separates the wrapped lines in a single message ciphertext.

The easiest fix would be to remove the newlines after Base64-encoding:

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

This replaces all whitespace in a single message ciphertext.

Since you're using the private sun.misc.* classes, it is better to move to another Base64 implementations, because those classes don't have to be available in every JVM. You should use some known library like Apache's commons-codec which provides an implementation where you can disable wrapping/chunking:

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

which is equivalent to

String encryptedValue = Base64.encodeBase64(encVal);


来源:https://stackoverflow.com/questions/39498722/javax-crypto-illegalblocksizeexception-input-length-must-be-multiple-of-16-when

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!