很多时候,我们都要对request 和response 进行加解密,这时候就需要对Http 重定向,自定义拦截器,将请求和返回值进行拦截,处理后在发送或者解析。下面会分为java 和kotlin 版本。
加密会分为 get 的参数加密 、post 的body 加密,加密的方式大部分都是使用RSA 加密。
直接看代码吧。
java版
public class DataEncryptInterceptor implements Interceptor {
private static final String TAG = DataEncryptInterceptor.class.getSimpleName();
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Request request = chain.request();
Request.Builder requestBuilder = request.newBuilder();
String requestMethod = request.method().toLowerCase().trim();
HttpUrl url = request.url();
//协议地址
String scheme = url.scheme();// http https
//域名
String host = url.host();// 127.0.0.1
//接口名
String path = url.encodedPath();// /test/upload/img
String key = PrefsUtil.getInstance().getString(Constants.PUBLIC_KEY, "");
//判断是否需要加密,如果次路径不需要加密,则返回原始request即可
if (path.isEmpty() || (!path.contains(ApiAddress.CHECK_ROOM_SECRET_OUT) && !path.contains(ApiAddress.CHECK_ENCRYPTION)) || TextUtils.isEmpty(key)) {
return chain.proceed(request);
}
//判断是get 还是post(get 和 delete 是一样的请求方式)
if (requestMethod.equals("get") || requestMethod.equals("delete")) {
if (url.encodedQuery() != null) {
try {
String queryparamNames = request.url().encodedQuery();
//如果参数是空,则不加密
if (queryparamNames == null || TextUtils.isEmpty(queryparamNames)) {
//构建新的请求
String newUrl = scheme + ":" + host + path;
request = request.newBuilder().url(newUrl).build();
} else {
//对参数进行RSA加密后 ,构建新请求
String newParams = RSAUtils.encrypt(queryparamNames, key);
//构建新的请求
String newUrl = scheme + ":" + host + path + "?" + newParams;
request = request.newBuilder().url(newUrl).build();
}
} catch (Exception e) {
e.printStackTrace();
return chain.proceed(request);
}
}
} else {
//post 请求
try {
//获取body 中内容
RequestBody oldRequestBody = request.body();
Buffer requestBuffer = new Buffer();
oldRequestBody.writeTo(requestBuffer);
String oldBodyStr = requestBuffer.readUtf8();
requestBuffer.close();
//fromBody 加密
if (request.body() instanceof FormBody) {
//随机AES密钥加密oldBodyStr
String encrypt = RSAUtils.encrypt(oldBodyStr, key);
Log.e(TAG, "the encrypt is" + encrypt);
MediaType mediaType = MediaType.parse("text/plain; charset=utf-8");
RequestBody newBody = RequestBody.create(mediaType, encrypt);
request = request.newBuilder()
.header("Content-Type", newBody.contentType().toString())
.header("Content-Length", String.valueOf(newBody.contentLength()))
.method(request.method(), newBody)
.build();
} else {
//生成随机AES密钥并用serverPublicKey进行RSA加密
url = request.url();
path = url.encodedPath();//
String query = url.encodedQuery();//请求参数
String encrypt = RSAUtils.encrypt(oldBodyStr, key);
// String newQuery = URLEncoder.encode(encrypt, "utf-8");
Log.e(TAG, "the encrypt is " + encrypt);
MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
//构造新的request
HashMap<String, Object> requestParams = DataService.createRequestParams();
requestParams.put("body", encrypt);
RequestBody requestBody1 = DataService.convertMapToBody(requestParams);
RequestBody requestBody = RequestBody.create(mediaType, encrypt);
Buffer requestBuffer1 = new Buffer();
requestBody1.writeTo(requestBuffer1);
String newBodyStr = requestBuffer1.readUtf8();
requestBuffer1.close();
Log.e(TAG, "the new body is" + newBodyStr);
request = request.newBuilder().post(requestBody1).build();
}
//response 拦截判断
Response response = chain.proceed(request);
if (response.code() == 200) {//只有约定的返回码才经过加密,才需要走解密的逻辑
//用AES密钥解密oldResponseBodyStr
ResponseBody oldResponseBody = response.body();
String oldResponseBodyStr = oldResponseBody.string();
RsaResponse rsaResponse = JSON.parseObject(oldResponseBodyStr, RsaResponse.class);
Log.e(TAG, "the response1 is" + rsaResponse.getResponse());
if (!TextUtils.isEmpty(rsaResponse.getResponse())){
String newResponseBodyStr = RSAUtils.decrypt(rsaResponse.getResponse(), key);
Log.e(TAG, "the new response is" + newResponseBodyStr);
oldResponseBody.close();
//构造新的response
MediaType mediaType = MediaType.parse("text/plain; charset=utf-8");
ResponseBody newResponseBody = ResponseBody.create(mediaType, newResponseBodyStr);
response = response.newBuilder().body(newResponseBody).build();
}
}
// response.close();
//返回
return response;
} catch (Exception e) {
e.printStackTrace();
return chain.proceed(request);
}
}
return chain.proceed(chain.request());
}
}
kotlin 版
class DataEncryptInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
val newBuilder = request.newBuilder()
val requestMethod = request.method().lowercase(Locale.getDefault()).trim { it <= ' ' }
var url = request.url()
val scheme = url.scheme() // http https
val host = url.host() // 127.0.0.1
var path = url.encodedPath() // /test/upload/img
//判断是get 还是post
if (requestMethod == "get" || requestMethod == "delete") {
if (url.encodedQuery() != null) {
}
} else {
return try {
val oldRequestBody = request.body()
val requestBuffer = Buffer()
oldRequestBody!!.writeTo(requestBuffer)
val oldBodyStr = requestBuffer.readUtf8()
requestBuffer.close()
if (request.body() is FormBody) {
//随机AES密钥加密oldBodyStr
val encrypt: String = RSAUtils.encrypt(oldBodyStr, key)
val mediaType = MediaType.parse("text/plain; charset=utf-8")
val newBody = RequestBody.create(mediaType, encrypt)
request = request.newBuilder()
.header("Content-Type", newBody.contentType().toString())
.header("Content-Length", newBody.contentLength().toString())
.method(request.method(), newBody)
.build()
} else {
//生成随机AES密钥并用serverPublicKey进行RSA加密
url = request.url()
path = url.encodedPath() //
val query = url.encodedQuery() //请求参数
val encrypt: String = RSAUtils.encrypt(oldBodyStr, key)
// String newQuery = URLEncoder.encode(encrypt, "utf-8");
Log.e(DataEncryptInterceptor.TAG, "the encrypt is $encrypt")
val mediaType = MediaType.parse("application/json; charset=utf-8")
//构造新的request
val requestParams: HashMap<String, Any> = DataService.createRequestParams()
requestParams["body"] = encrypt
val requestBody1: RequestBody = DataService.convertMapToBody(requestParams)
val requestBody = RequestBody.create(mediaType, encrypt)
val requestBuffer1 = Buffer()
requestBody1.writeTo(requestBuffer1)
val newBodyStr = requestBuffer1.readUtf8()
requestBuffer1.close()
request = request.newBuilder().post(requestBody1).build()
}
var response = chain.proceed(request)
if (response.code() == 200) { //只有约定的返回码才经过加密,才需要走解密的逻辑
//用AES密钥解密oldResponseBodyStr
val oldResponseBody = response.body()
val oldResponseBodyStr = oldResponseBody!!.string()
val rsaResponse: RsaResponse =
JSON.parseObject(oldResponseBodyStr, RsaResponse::class.java)
if (!TextUtils.isEmpty(rsaResponse.getResponse())) {
val newResponseBodyStr: String =
RSAUtils.decrypt(rsaResponse.getResponse(), key)
oldResponseBody!!.close()
//构造新的response
val mediaType = MediaType.parse("text/plain; charset=utf-8")
val newResponseBody = ResponseBody.create(mediaType, newResponseBodyStr)
response = response.newBuilder().body(newResponseBody).build()
}
}
// response.close();
//返回
response
} catch (e: Exception) {
e.printStackTrace()
chain.proceed(request)
}
}
return chain.proceed(chain.request())
}
}
RSAUtils
package com.oculus.rayvision.cloudxr.ovr.utils;
import android.nfc.Tag;
import android.text.TextUtils;
import android.util.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.json.JSONArray;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class RSAUtils {
public static final String rsa = "公钥";
/**
* 密钥长度 于原文长度对应 以及越长速度越慢
*/
private final static int KEY_SIZE = 1024;
private static final String TAG = RSAUtils.class.getSimpleName();
/**
* RSA公钥加密
*
* @param str 加密字符串
* @param publicKey 公钥
* @return 密文
* @throws Exception 加密过程中的异常信息
*/
public static String encrypt(String str, String publicKey) throws Exception {
//base64编码的公钥
Log.e(TAG, "the str is" + str);
Log.e(TAG, "the publick key is" + publicKey);
byte[] decoded = Base64.getMimeDecoder().decode(publicKey);
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
//RSA加密
// Cipher cipher = Cipher.getInstance("RSA");
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] bytes = cipher.doFinal(str.getBytes());
// String res = new String(bytes);
Log.e(TAG, "s" + Base64.getEncoder().encodeToString(bytes));
String s = Base64.getEncoder().encodeToString(cipher.doFinal(str.getBytes(StandardCharsets.UTF_8)));
Log.e(TAG, "ss=" + s);
return s;
}
/**
* RSA公钥解密
*
* @param text 加密字符串
* @param publicKeyText 私钥
* @return 明文
* @throws Exception 解密过程中的异常信息
*/
public static String decrypt(String text, String publicKeyText) {
if (TextUtils.isEmpty(text)) {
return "";
}
String value = "";
try {
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.getMimeDecoder().decode(publicKeyText));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
byte[] decode = Base64.getMimeDecoder().decode(text);
byte[] result = cipher.doFinal(decode);
value = new String(result);
} catch (Exception e) {
e.printStackTrace();
}
return value;
}
public static String decryptOld(String str, String privateKey) {
//64位解码加密后的字符串
String outStr = null;
try {
//
byte[] inputByte = Base64.getDecoder().decode(str);
//base64编码的私钥
byte[] decoded = Base64.getDecoder().decode(privateKey);
RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
//RSA解密
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, priKey);
outStr = new String(cipher.doFinal(inputByte), StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "decypt exception is" + e.getMessage());
}
return outStr;
}
public static String baseConvertStr(String str) {
if (null != str) {
Base64.Decoder decoder = Base64.getDecoder();
try {
String gbk = new String(decoder.decode(str.getBytes()), "GBK");
Log.e(TAG, "the gbk is " + gbk);
gbk = gbk.replaceAll("-----BEGIN PUBLIC KEY-----", "");
gbk = gbk.replaceAll("-----END PUBLIC KEY-----", "");
return gbk;
} catch (UnsupportedEncodingException e) {
return null;
}
}
return null;
}
}