zoukankan      html  css  js  c++  java
  • 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编码
    就算这个世道烂成一堆粪坑,那也不是你吃屎的理由
  • 相关阅读:
    YARN的设计
    在(MRv1)中JobTracker工作方式
    经典 MapReduce框架(MRv1)
    进程与线程的简单解释
    Java序列化的机制和原理
    ibatis源码学习4_参数和结果的映射原理
    ibatis源码学习3_源码包结构
    ibatis源码学习2_初始化和配置文件解析
    ibatis源码学习1_整体设计和核心流程
    spring中的设计模式
  • 原文地址:https://www.cnblogs.com/whalesea/p/11396071.html
Copyright © 2011-2022 走看看