Android Okhttp 拦截器中加密 请求体 (DES加密解密)

最近公司为了项目安全 使用了https 所有接口要使用DES 加密 加密 RequestBody 的value值

心想 这不是很简单吗 直接在拦截器中获取到要上传的数据 然后加密 重新赋值 很简单嘛 但是实践起来 我真的气的想要骂娘 太坑了好吗。。。。无语直接就打到我的脸上

废话不多说 让我重温一下这些坑

第一步 在网络请求类里添加拦截器

在拦截器里对上传的数据进行操作

如果是post 请求 取出来request.body(); 循环 取出 encodedValue 加密后 重新再 addEncoded 添加进去 这里要注意 URLDecoder的解码

如果是get请求 先拿到 request.url() 然后再看这个url中包含不包含请求参数 url.encodedQuery() 如果这个不为空的话 就是接下来字符串截取->修改加密->重新拼接

然后进行网络请求

然后解密 ---->

和后台商量后 后台返回的数据只对 “data” 字段的value进行了加密 好 那我只对“data” 进行解密就好了

获取到 response 对返回的json进行解析 因为后台对“data”进行加密 无疑 data是String类型的 解析解密后 怎么将解密后的data重新安装到json中呢 ?

解密后的data是String类型的 但是原本想要表达的 “data” 该是什么类型呢 不知道什么类型 又该怎么准确的安到实体类里呢

我被这个“data”困阻了 一直在想 怎么直接去操作json串 我知道这也不是一个绝美精妙的办法 但是我脑容量毕竟不大 我觉得我能想到解决的办法已经很棒了 substring(0,1);毕竟 返回的json也就那么几种 { 、[ 、还有什么都没有的

那不就好办了吗 直接统称两类 jsonArray 和jsonObject 至此 我才终于有了完整的思路

我猜看到这里大家也到了耐心的极限了 但是整体的思路 使用的方法 上面已经基本都讲的差不多了 合格的程序员 应该脑海里也知道该怎么做了 有点凡尔赛那味了

上代码!!!!

public class OkhttpInstance {

private static OkHttpClient okHttpClient;
private static Response response;

public static synchronized OkHttpClient createInstance() {
    if (okHttpClient == null) {
        synchronized (OkhttpInstance.class) {
            if (okHttpClient == null) {
                okHttpClient = new OkHttpClient.Builder()
                        .connectTimeout(60, TimeUnit.SECONDS)      //设置连接超时
                        .readTimeout(60, TimeUnit.SECONDS)         //设置读超时
                        .writeTimeout(60, TimeUnit.SECONDS)        //设置写超时
                        .retryOnConnectionFailure(true)            //是否自动重连
                        .addInterceptor(interceptor)  //添加拦截器
                        .build();
            }
        }
    }
    return okHttpClient;
}

private static Interceptor interceptor = new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Request.Builder requestBuilder = request.newBuilder();

        //post请求加密
        if (request.body() instanceof FormBody) {
            FormBody.Builder newFormBody = new FormBody.Builder();//创建新表单
            FormBody oidFormBody = (FormBody) request.body();//请求表单
            //循环取出 request Body 注意FormBody 才会有size属性 FormBody可以满足大部分的请求
            for (int i = 0; i < oidFormBody.size(); i++) {
                String str = oidFormBody.encodedValue(i);//value
                String decode = URLDecoder.decode(str);//对value进行URLDecoder解码
                String s = oidFormBody.encodedName(i);//name
                String name = URLDecoder.decode(s);//对name进行URLDecoder解码 很重要 这两个都加上 不然取出请求体的时候有的请求体被URLDecoder编码 后台不知道你传过去的是什么 
                String encrypt = DesCipherUtil.encrypt(decode, HDUrl.PAS);//des加密 HDUrl.PAS 是我的密码 你跟后台商量定什么为密码
                newFormBody.addEncoded(name.trim(), encrypt.trim());//去空格 相当重要!!都是我踩过的坑
            }
            requestBuilder.method(request.method(), newFormBody.build());
        }

        request = requestBuilder.build();

// get请求加密
//还回加密的请求头
HttpUrl url = request.url();
String path = url.encodedPath();//
String query = url.encodedQuery();//请求参数
if (!TextUtils.isEmpty(query)) {

            StringBuffer sb = new StringBuffer();
            sb.append(HDUrl.DEFAULT).append(path).append("?");//HDUrl.DEFAULT是我的请求地址:https://192.16.2.88 我猜你知道我说的是什么
            Set<String> queryList = url.queryParameterNames();
            Iterator<String> iterator = queryList.iterator();
            for (int i = 0; i < queryList.size(); i++) {

                String queryName = iterator.next();
                sb.append(queryName).append("=");
                String queryKey = url.queryParameter(queryName);
                //对query的key进行加密
                if (TextUtils.isEmpty(queryKey) || null == queryKey || "null".equals(queryKey) || queryKey.length() == 0 || "".equals(queryKey)) {
                } else {
                    Log.e("tag", "queryKey-----------" + queryKey);
                    sb.append(DesCipherUtil.encrypt(queryKey, HDUrl.PAS));
                }
                if (iterator.hasNext()) {
                    sb.append("&");
                }
            }
            String newUrl = sb.toString();

// 进行加密后的get请求链接
Request.Builder url1 = request.newBuilder()
.url(newUrl);
request = url1.build();

        }
        response = chain.proceed(request);
        byte[] data = response.body().bytes();
        String s = new String(data);
        MediaType mediaType = response.body().contentType();
        try {
            Log.e("tag", "s-----------------------" + s);
            JSONObject jsonObject = new JSONObject(s);
            int code = 0;
            if (jsonObject.has("code")) {
                code = jsonObject.getInt("code");
            } else {
                code = jsonObject.getInt("errCode");
            }
            if (code == 200 || code == 0) {

// 当code=200/0时解密
if (jsonObject.has(“data”)) {
String code1 = jsonObject.getString(“data”);
String decrypt = DesCipherUtil.decrypt(code1, HDUrl.PAS);
jsonObject.remove(“data”);
jsonObject.put(“data”, decrypt);
Gson gson = new Gson();
//
DefaultBean defaultBean = gson.fromJson(s, DefaultBean.class);
if (decrypt.substring(0, 1).equals("[")) {
List arrData = gson.fromJson(decrypt, new TypeToken<List>() {
}.getType());
defaultBean.setData(arrData);
} else if (decrypt.substring(0, 1).equals("{")) {
Object objectData = gson.fromJson(decrypt, Object.class);
defaultBean.setData(objectData);
} else {
defaultBean.setData(decrypt);
}
s = new Gson().toJson(defaultBean);
}

            } else if (code == 10100) {
                //就代表token过期了
                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Looper.prepare();
                        UserInfo userInfo = (UserInfo) ShareprefencesUtils.getBean(App.getApplicationContent(), ShareprefencesUtils.USER_INFO);
                        userInfo.setAccess_token("");
                        ShareprefencesUtils.putBean(App.getApplicationContent(), ShareprefencesUtils.USER_INFO, userInfo);
                        Intent intent = new Intent(App.getApplicationContent(), SelectJoinActivity.class)
                                .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
                        App.getApplicationContent().startActivity(intent);
                        Toast.makeText(App.getApplicationContent(), "登录超时请重新登录", Toast.LENGTH_SHORT).show();
                        Looper.loop();
                    }
                });
                thread.start();
            }

        } catch (JSONException e) {
            e.printStackTrace();
        }
        return response.newBuilder()
                .body(ResponseBody.create(mediaType, s))
                .build();
    }
};

public static synchronized OkHttpClient getInstance() {
    return okHttpClient;
}

其实已经很容易看懂了 一些东西我就不做解释了 自己悟去吧 下面贴一下DES加密解密类

private DesCipherUtil() {
throw new AssertionError(“No DesCipherUtil instances for you!”);
}

static {
    // add BC provider

// Security.addProvider(new BouncyCastleProvider());
}

/**
 * 加密
 * 
 * @param encryptText 需要加密的信息
 * @param key 加密密钥
 * @return 加密后Base64编码的字符串
 */
@SuppressLint("NewApi")
public static String encrypt(String encryptText, String key) {

    if (encryptText == null || key == null) {
        throw new IllegalArgumentException("encryptText or key must not be null");
    }

    try {
        DESKeySpec desKeySpec = new DESKeySpec(key.getBytes());
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec);

        Cipher cipher = Cipher.getInstance("DES/ECB/PKCS7Padding", "BC");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] bytes = cipher.doFinal(encryptText.getBytes(Charset.forName("UTF-8")));
        return Base64.getEncoder().encodeToString(bytes);

    } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | NoSuchPaddingException
        | BadPaddingException | NoSuchProviderException | IllegalBlockSizeException e) {
        throw new RuntimeException("encrypt failed", e);
    }

}

/**
 * 解密
 * 
 * @param decryptText 需要解密的信息
 * @param key 解密密钥,经过Base64编码
 * @return 解密后的字符串
 */
public static  String decrypt(String decryptText, String key) {

    if (decryptText == null || key == null) {
        throw new IllegalArgumentException("decryptText or key must not be null");
    }

    try {
        DESKeySpec desKeySpec = new DESKeySpec(key.getBytes());
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec);

        Cipher cipher = Cipher.getInstance("DES/ECB/PKCS7Padding", "BC");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] bytes = new byte[0];
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            bytes = cipher.doFinal(Base64.getDecoder().decode(decryptText));
        }
        return new String(bytes, Charset.forName("UTF-8"));

    } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | NoSuchPaddingException
        | BadPaddingException | NoSuchProviderException | IllegalBlockSizeException e) {
        throw new RuntimeException("decrypt failed", e);
    }
}
public static void main(String[] args) {

}

这些都是我实实在在用到项目中的 有问题别质疑 我的代码没有问题 傲娇脸