首先痨下为什么使用RSA加密,或者说RSA加密的使用场景。
在爬虫工程师泛滥的时代,明文传输数据已经变得极为不安全。现在前端主流的方法是AES对称加密生成密钥,通过AES密钥去加密请求参数,再通过RSA非对称加密的公钥去对AES私钥加密。将加密过后的参数和密钥上传至服务器。服务端的guys要做的工作是通过RSA私钥解密AES密钥,用解密过后的AES密钥再去解密参数。说的太累赘,直接上图。(此图纯属抄袭)
(Base64处理没有实际意义,RSA处理后的AES密钥串容易乱码)
为什么不用纯RAS加密数据呢?肯定有小白会问,其实百度下就知道,由于RSA加解密速度慢,不适合大量数据文件加密。AES加密速度很快。(速度快的貌似都不太安全)所这里我们结合AES和RSA加密,兼顾效率和安全。
如何生成RSA公钥私钥,我就不啰嗦了,百度上面挺多的。
描述了RAS加密的使用场景,有人会问,httpParamsIntercepter和RSA加密有什么关系吗?android目前最牛的网络请求框架retrofit这个应该没人质疑,而他的强大之处是可以自定义各种拦截器,转换器来处理request和response。有了这样强大的工具我们为什么要在每次处理联网请求的时候手动加上加密处理。于是我将加密放到参数拦截器里面统一处理。废话这么多还是直接上代码。(非大神,只具借鉴意义)
FormBody oldFormBody = (FormBody) request.body();
paramsMap.clear();
for(int i = 0;i<oldFormBody.size();i++){
String value = oldFormBody.encodedValue(i);
String decodeValue = URLDecoder.decode(value, "utf-8");
paramsMap.put(oldFormBody.encodedName(i), decodeValue);
}
//判断是否需要RSA加密
if (paramsMap.containsKey(Constant.RSA_ENCRYPT) && paramsMap.get(Constant.RSA_ENCRYPT).equals(Constant.NEED_RSA_ENCRYPT)){
paramsMap.remove(Constant.RSA_ENCRYPT);
HashMap<String, String> encrypt = EncryptUtils.encrypt(paramsMap, publicKey);
paramsMap.clear();
paramsMap.putAll(encrypt);
}
URLDecoder在这里的意义是防止浏览器转译,到后台解密之后形成乱码。因为浏览器默认是gb2312编码。
下面是混合加密解密工具类
public static HashMap<String,String> encrypt(Map<String, String> requestMap, String strKey) {
HashMap<String,String> map = new HashMap<>();
try {
String key = AESUtils.generateKeyString();
RSAPublicKey publicKey = RSAUtils.loadPublicKey(strKey);
String rsaAesKey = RSAUtils.encryptByPublicKey(key, publicKey);
String params = new Gson().toJson(requestMap);
String context_ = AESUtils.encrypt(params, key);
map.put(Constant.RSA_AES_LEY,rsaAesKey);
map.put(Constant.CONTEXT,context_);
return map;
} catch (Exception e) {
e.printStackTrace();
return map;
}
}
public static String decode(BaseInfo baseInfo, Context context) {
String result = "";
try {
String key = baseInfo.getKey();
String content = baseInfo.getContent();
String publicKeyFromAssets = RSAUtils.getPublicKeyFromAssets(context);
RSAPublicKey publicKey = RSAUtils.loadPublicKey(publicKeyFromAssets);
String rsaAesKey = RSAUtils.decryptByPublicKey(key, publicKey);
return AESUtils.decrypt(content, rsaAesKey);
} catch (Exception e) {
e.printStackTrace();
return result;
}
}
AES和RSA工具类应该不需要贴代码了。网上挺多的,抄袭不太好。
这里需要注意的是我这里使用RSA加密AESkey,字节数不会超过限制,如果你要用RSA加密大量数据,我建议你还是采用分段加密,解密。