url請求時,參數中的+在服務器接收時為空格,導致AES加密報出javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher


報錯的意思的是使用該種解密方式出入長度應為16bit的倍數,但實際的錯誤卻不是這個,錯誤原因根本上是因為在http請求是特殊字符編碼錯誤,具體就是base64生成的+號,服務器接收時成了空格,然后導致base64解碼出的字節數組有改變。

下面來還原並分析一下具體原因:

請求代碼:

    @Test
    public void testHttp() throws Exception {
        //16進制字節數組,單純的為了生成含有+的base64位字符串,是在試了好多遍都沒試到+,只能把我錯誤例子的byte數組轉成16進制,為我的機智點個贊
        String src = "34aa8bc0adaccbe45ac8c7e43d25955f4d3b51a189339af3d5b968b49764f4def4b81ab285a461504a5cb930c08055f96e875e2b4be390f6708ae686b13e8ff3bed9e9455c638c3809e4c51db05ac3f496be28772829270998eddb9ec6c08c4a0cc1d23e59c6ebe8b73b75013ba9eee5";
        byte[] bytes = Hex.decodeHex(src);
        String base64Str = Base64.encodeBase64String(bytes);
        System.out.println("發送時的字符串:"+base64Str);
        for(int i=0;i<bytes.length;i++) {
            System.out.println(bytes[i]);
        }
        String httpUrl = "http://10.20.20.184:10086/dbzx/hello?src="+base64Str;
        HttpRequest.doGet(httpUrl);
    }

打印結果(部分結果):

發送時的字符串:NKqLwK2sy+RayMfkPSWVX007UaGJM5rz1blotJdk9N70uBqyhaRhUEpcuTDAgFX5bodeK0vjkPZwiuaGsT6P877Z6UVcY4w4CeTFHbBaw/SWvih3KCknCZjt257GwIxKDMHSPlnG6+i3O3UBO6nu5Q==
52
-86
-117
-64
-83
-84
-53
-28
90
-56
-57
-28

 

服務端代碼:

package com.dbzx.controller;

import org.apache.commons.codec.binary.Base64;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.dbzx.common.ResultModel;

@RestController
@RequestMapping("dbzx")
public class HelloController {
    
    @RequestMapping("/hello")
    public ResultModel hello(String src) {
        System.out.println("接收到的字符串:"+src);
        byte[] bytes = Base64.decodeBase64(src);
        for(int i=0;i<bytes.length;i++) {
            System.out.println(bytes[i]);
        }
        return ResultModel.ok();
    }
}

打印結果(部分結果):

接收到的字符串:NKqLwK2sy RayMfkPSWVX007UaGJM5rz1blotJdk9N70uBqyhaRhUEpcuTDAgFX5bodeK0vjkPZwiuaGsT6P877Z6UVcY4w4CeTFHbBaw/SWvih3KCknCZjt257GwIxKDMHSPlnG6 i3O3UBO6nu5Q==
52
-86
-117
-64
-83
-84
-55
22
-78
49
-7
15

通過兩端的結果對比可以發現發送前是+,服務器接收的是空格,這是因為有些特殊字符在http請求時是無法編碼的,其實base64就是解決類似問題得,只是越來越多的特殊字符,導致它出錯。

有些人說base64會把+和空格轉成相同的字節碼,不會出錯,但是我們來對比一下字節碼。

 

可以看到,在第7行開始不對照。

而原本字符串(NKqLwK2sy+)+在第10個位置,跟據base64的規則,4個base64轉成的字符串,代表3個原本的字符串,而上圖第七個字節,需要"y+"共同構造,這就是出錯的原因。既是aes解碼出錯的原因。

至於16的倍數,理論上只用是偶數位的字節數都滿足,顯示錯誤出在其他方面,這個例子就是字節碼出錯了。

解決的方法有多種:

一、最直接的解決方式,把字符串中的空格,轉化成+

str = str.replace(" ", "+");

二、換一種傳遞參數的方式,保證沒有特殊字符,只有數字和字母。

  在我的項目里是為了保aes加密后的數據傳輸,加密后是byte[],所以我把結果變成16進制的字符串輸出,這樣接收參數沒有改變。

  

String token = Hex.encodeHexString(resultBytes);//發送方轉成16進制字符串

byte[] tokenBytes = Hex.decodeHex(token);//接收方16進制解碼

三、發送發url編碼,接收方直接接收不用url解碼。

  其實最開始我是用了url編碼的,但是結果也是空格,我就放棄了,后來偶然發現,可以直接接收單無需解碼。當然,服務端不同可能結果不一樣。

token = URLEncoder.encode(token,"utf-8");//發送方Url編碼

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM