1.背景
在不用https的情况下,网络请求需要手动加密,加密的方式有很多,对称加密或者非对称加密,考虑到安全性的前提,非对称加密是必须的,但是如果传输的数据量很大,例如传输一张人脸图片,传输加上服务端解密会比较慢。
所以采取对称加密+非对称加密最佳,以下介绍RSA+AES的加密方式
2.实现方式
Android 持有服务端生成的RSA公钥,数据用随机生成的AES秘钥加密,AES秘钥用RSA公钥加密,加密后的AES秘钥通过请求头的方式传输给服务端,服务端返回的数据再用AES解密,请求完成。因为AES每次请求都是重新生成,保证了安全性,没有服务端RSA私钥就算拦截到了请求也解不开。
3.代码
-
Retrofit中添加拦截器
OkHttpClient.Builder okBuilder = new OkHttpClient.Builder().addInterceptor(new DataEncryptInterceptor());
retrofit = new Retrofit.Builder().client(okBuilder.build()).build();
-
拦截器代码实现
public class DataEncryptInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
//请求
Request request = chain.request();
MediaType mediaType = MediaType.parse("text/plain; charset=utf-8");
//随机生成AES秘钥
String aesKey = AESUtil.getAESKey();
try {
//获取未加密数据
RequestBody oldRequestBody = request.body();
Buffer requestBuffer = new Buffer();
oldRequestBody.writeTo(requestBuffer);
String oldBodyStr = requestBuffer.readUtf8();
requestBuffer.close();
//未加密数据用AES秘钥加密
String newBodyStr= EncryptionManager.getInstance().publicEncryptClient(oldBodyStr);
//AES秘钥用服务端RSA公钥加密
String key= EncryptionManager.getInstance().publicEncrypt(aesKey);
//构成新的request 并通过请求头发送加密后的AES秘钥
Headers headers = request.headers();
RequestBody newBody = RequestBody.create(mediaType, newBodyStr);
//构造新的request
request = request.newBuilder()
.headers(headers)
.addHeader("Device-Key", key)
.method(request.method(), newBody)
.build();
}catch (Exception e){
}
//响应
Response response = chain.proceed(request);
if (response.code() == 200) {
try {
//获取加密的响应数据
ResponseBody oldResponseBody = response.body();
String oldResponseBodyStr = oldResponseBody.string();
//加密的响应数据用AES秘钥解密
String newResponseBodyStr="";
if (!TextUtils.isEmpty(oldResponseBodyStr)){
newResponseBodyStr = AESUtil.aesDecrypt(oldResponseBodyStr,aesKey);
}
oldResponseBody.close();
//构造新的response
ResponseBody newResponseBody = ResponseBody.create(mediaType, newResponseBodyStr);
response = response.newBuilder().body(newResponseBody).build();
}catch (Exception e){
LogUtils.d("RetrofitLog","e"+e.getMessage());
}finally {
response.close();
}
}
//返回
return response;
}
}
4.其他
AES和RSA的秘钥生成和加解密就不写了,网上一大堆