概要
经过短暂的休养生息后,我的头发又迎来了新的挑战,这次的课题是RSA+AES加密,具体原理可以看这篇文章,点此跳转,本文不在赘述。
作者商务合作及技术交流QQ704191499
整体架构流程
整个流程没有难度特别高的地方,毕竟对我们来说,所有的前端加密都是形同虚设,主要是繁琐程度比较高,正所谓伤害性不大,侮辱性极强!
一、抓包原始数据
本案例中的平台所有功能都使用同一接口,所有传参、返回都进行了RSA+AES双重加密,导致我们用浏览器控制台或者抓包软件无法得知请求的功能、传参等有用信息。
所以为了知道哪些请求是用来获取我们需要的数据,我选择找到其加密解密代码段,插入打印到控制台代码。
要从这些连名称都随机的脚本文件中找到加密解密的代码段属实是不容易。我这边是一个个打开然后搜索encryptKey,因为这是请求传参的键,顺着请求肯定可以找到加密解密的代码,比较幸运的是,请求和加密解密都在一个脚本里,只要加上打印代码就行了。
加上打印到控制台的代码后顺利可以看见加密前的传参,以及解密后的返回了。至于为什么打印加上123,因为方便搜索我打印的内容哈哈。
二、获取RSA公钥
既然可以RSA加密,那就必须要有公钥,我打印了加密工具发现其中有一个setPublicKey的函数。
那么顺着这个线索,再到每个脚本文件中搜索setPublicKey这个函数就可以得到公钥了。
打印到控制台然后复制下来就行了。
三、模拟请求
为了模拟请求,我仔细阅读了脚本中的加密流程(因为当时不懂RSA+AES加密原理),发现传参逻辑如下:随机生成16位AES秘钥,使用AES秘钥将原始数据加密,放在请求中的encryptData里,再将AES秘钥用RSA公钥加密,放在请求中的encryptKey里,最后加上一个固定参数,格式如下图。
代码如下,感谢Hutool。
String publicKey = "xxx";
String key = RandomUtil.randomString(16);
AES aes = SecureUtil.aes(key.getBytes());
RSA rsa = SecureUtil.rsa(null, publicKey);
HttpUtil.createPost("https://xxx/api/")
.form("encryptKey", rsa.encryptBase64(key, KeyType.PublicKey))
.form("encryptData", aes.encryptBase64(param))
.form("encryptType", "RA")
.execute();
四、解密加密数据
同样是阅读了脚本中的解密流程,发现其实就是用之前自己随机的16位AES秘钥解密,那么就简单了,一个方法把加密传参、解密返回搞定。
String publicKey = "xxx";
Function<String, String> request = param -> {
String key = RandomUtil.randomString(16);
AES aes = SecureUtil.aes(key.getBytes());
RSA rsa = SecureUtil.rsa(null, publicKey);
String body = HttpUtil.createPost("https://xxx/api/")
.form("encryptKey", rsa.encryptBase64(key, KeyType.PublicKey))
.form("encryptData", aes.encryptBase64(param))
.form("encryptType", "RA")
.execute()
.body();
return aes.decryptStr(body);
};
吐槽
好了到这里就结束了,不得不吐槽一下,阅读没有注释的源码属实是有点痛苦了,加上不了解这个加密方案吃了不少苦,希望大家以后发现不了解的加密方案是先查找学习,而不是像我一样直接读源码,引以为戒(哭)。当然了,要是人家自己定义加密方案那就只能阅读源码了,祝你好运。