1.背景
在不用https的情況下,網(wǎng)絡請求需要手動加密,加密的方式有很多,對稱加密或者非對稱加密,考慮到安全性的前提,非對稱加密是必須的,但是如果傳輸?shù)臄?shù)據(jù)量很大,例如傳輸一張人臉圖片,傳輸加上服務端解密會比較慢。
所以采取對稱加密+非對稱加密最佳,以下介紹RSA+AES的加密方式
2.實現(xiàn)方式
Android 持有服務端生成的RSA公鑰,數(shù)據(jù)用隨機生成的AES秘鑰加密,AES秘鑰用RSA公鑰加密,加密后的AES秘鑰通過請求頭的方式傳輸給服務端,服務端返回的數(shù)據(jù)再用AES解密,請求完成。因為AES每次請求都是重新生成,保證了安全性,沒有服務端RSA私鑰就算攔截到了請求也解不開。
3.代碼
-
Retrofit中添加攔截器
OkHttpClient.Builder okBuilder = new OkHttpClient.Builder().addInterceptor(new DataEncryptInterceptor());
retrofit = new Retrofit.Builder().client(okBuilder.build()).build();
-
攔截器代碼實現(xiàn)
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 {
//獲取未加密數(shù)據(jù)
RequestBody oldRequestBody = request.body();
Buffer requestBuffer = new Buffer();
oldRequestBody.writeTo(requestBuffer);
String oldBodyStr = requestBuffer.readUtf8();
requestBuffer.close();
//未加密數(shù)據(jù)用AES秘鑰加密
String newBodyStr= EncryptionManager.getInstance().publicEncryptClient(oldBodyStr);
//AES秘鑰用服務端RSA公鑰加密
String key= EncryptionManager.getInstance().publicEncrypt(aesKey);
//構成新的request 并通過請求頭發(fā)送加密后的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 {
//獲取加密的響應數(shù)據(jù)
ResponseBody oldResponseBody = response.body();
String oldResponseBodyStr = oldResponseBody.string();
//加密的響應數(shù)據(jù)用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的秘鑰生成和加解密就不寫了,網(wǎng)上一大堆