Android Java iOS 三端RSA和AES加密处理

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/yin13753884368/article/details/84380842

Android Java iOS 三端RSA和AES加密处理

  • Github

  • CSDN

  • 资源地址

  • 之前写的一篇博客关于 RSA和AES双向加密(Android 和 Java) 当时没有考虑iOS端,之后在协调过程中在AES解密上出现问题,用这种方式互相解出来的不一致,导致解密失败

  • 查阅资料发现 AES加密时不能用KeyGenerator、SecureRandom、SecretKey 生成,需要自己写一个方法生成16位的字符串

  • 还需要指定加密的算法、工作模式和填充方式

  • 需要自己生成AES密钥和AES偏移量

  • 最后放上代码


 	private static final String AES = "AES";
    private static final String STRING_FORMAT = "UTF-8";
    private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
    public static String CRYPT_KEY = getRandomString(16);
    public static String IV_STRING = getRandomString(16);

    /**
     * 加密
     *
     * @param aesKey  AESkey
     * @param ivKey   AES偏移量
     * @param content 明文
     * @return 密文
     */
    public static String encrypt(String aesKey, String ivKey, String content) {
        try {
            byte[] byteContent = content.getBytes(STRING_FORMAT);
            // 注意,为了能与 iOS 统一 这里的 key 不可以使用 KeyGenerator、SecureRandom、SecretKey 生成
            byte[] enCodeFormat = aesKey.getBytes();
            SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, AES);
            byte[] initParam = ivKey.getBytes();
            IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
            // 指定加密的算法、工作模式和填充方式
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
            byte[] encryptedBytes = cipher.doFinal(byteContent);
            // 同样对加密后数据进行 base64 编码
            return Base64Util.byte2Base64(encryptedBytes);
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 解密
     *
     * @param aesKey  AESkey
     * @param ivKey   AES偏移量
     * @param content 密文
     * @return 解密后的明文
     */
    public static String decrypt(String aesKey, String ivKey, String content) {
        try {
            byte[] encryptedBytes = Base64Util.base642Byte(content);
            byte[] enCodeFormat = aesKey.getBytes();
            SecretKeySpec secretKey = new SecretKeySpec(enCodeFormat, AES);
            byte[] initParam = ivKey.getBytes();
            IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
            byte[] result = cipher.doFinal(encryptedBytes);
            return new String(result, STRING_FORMAT);
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 随机生成字符串
     *
     * @param length 需要生成的位数
     * @return String
     */
    public static String getRandomString(int length) {
        String base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

与RSA结合使用方法

/**
 * APP端加密请求内容
 *
 * @param content 需要加密的内容
 * @return 返回map
 * @throws Exception
 */
public static Map<String, String> appEncrypt1(String content) throws Exception {
    LinkedHashMap<String, String> map = new LinkedHashMap<>();
    //将Base64编码后的(server端)公钥转换成PublicKey对象
    PublicKey serverPublicKey = RSAUtil.string2PublicKey(KeyUtil.SERVER_PUBLIC_KEY.replaceAll("\n", ""));
    //随机生成AES秘钥 AES偏移量
    String aesKeyStr = AESUtil2.CRYPT_KEY;
    String ivKeyStr = AESUtil2.IV_STRING;
    //用(server端)公钥加密AES秘钥 AES偏移量
    byte[] encryptAesKey = RSAUtil.publicEncrypt(aesKeyStr.getBytes("utf-8"), serverPublicKey);
    byte[] encryptAesIvKey = RSAUtil.publicEncrypt(ivKeyStr.getBytes("utf-8"), serverPublicKey);
    //用AES秘钥加密请求内容
    String encryptContentRequest = AESUtil2.encrypt(aesKeyStr, ivKeyStr, content);
    map.put("ak", Base64Util.byte2Base64(encryptAesKey));//加密后的aesKey
    map.put("iv", Base64Util.byte2Base64(encryptAesIvKey));//加密后的AES偏移量
    map.put("data", encryptContentRequest);//加密内容
    LogUtils.e("----AES加密秘钥 ----" + aesKeyStr);
    LogUtils.e("----AES加密秘钥偏移量 ----" + ivKeyStr);
    LogUtils.e("----AES加密数据 ---- ak==" + Base64Util.byte2Base64(encryptAesKey));
    LogUtils.e("----AES加密数据 ---- iv==" + Base64Util.byte2Base64(encryptAesIvKey));
    LogUtils.e("----AES加密数据 ---- data==" + encryptContentRequest);
    return map;
}


/**
 * APP解密服务器的响应内容
 *
 * @param content 需要解密的内容
 * @return 明文
 * @throws Exception
 */
public static String appDecrypt1(String content) throws Exception {
    JSONObject result = new JSONObject(content);
    String decryptAesKey = (String) result.get("ak");//加密后的aesKey
    String decryptAesIvKey = (String) result.get("iv");//加密后的AES偏移量
    String decryptContent = (String) result.get("data");//内容
    //将Base64编码后的APP私钥转换成PrivateKey对象
    PrivateKey appPrivateKey = RSAUtil.string2PrivateKey(KeyUtil.APP_PRIVATE_KEY.replace("\n", ""));
    //用APP私钥解密AES秘钥 AES偏移量
    byte[] aesKeyBytes = RSAUtil.privateDecrypt(Base64Util.base642Byte(decryptAesKey), appPrivateKey);
    byte[] aesIvKeyBytes = RSAUtil.privateDecrypt(Base64Util.base642Byte(decryptAesIvKey), appPrivateKey);
    //用AES秘钥解密请求内容
    String aesKey = new String(aesKeyBytes);
    String aesIvKey = new String(aesIvKeyBytes);
    String response = AESUtil2.decrypt(aesKey, aesIvKey, decryptContent);
    LogUtils.e("----AES解密秘钥 ----" + aesKey + "--- aesIvKey ---" + aesIvKey + "--- response ---" + response);
    return response;
}

在代码加密过程后,在retrofit设置拦截器里要替换为加密后的数据,由于默认会转义特殊字符,导致后台无法解密数据,报错,解决的方法如下:

  • FormBody.Builder 在加参数时 builder.addEncoded(URLEncoder.encode(key, “UTF-8”), URLEncoder.encode(value, “UTF-8”));

 private final Interceptor mInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Request.Builder newBuilder = request.newBuilder();
            RequestBody requestBody = request.body();
            if (HTTP_SWITCH) {
                //接口加密处理
                JSONObject jsonObject = new JSONObject();
                try {
                    jsonObject.put("curLoginAcc", StringUtils.null2Length0(UserPreferences.getInstance(MyApplication.getContext()).getUserAccount()));
                    FormBody body = (FormBody) requestBody;
                    if (body != null && body.size() > 0) {
                        for (int i = 0; i < body.size(); i++) {
                            jsonObject.put(body.encodedName(i), body.encodedValue(i));
                        }
                    }
                    Map<String, String> map = HttpEncryptUtil.appEncrypt1(jsonObject.toString());
                    FormBody.Builder builder = new FormBody.Builder();
                    if (map != null && !map.isEmpty()) {
                        Set<Map.Entry<String, String>> entrySet = map.entrySet();
                        if (entrySet != null && entrySet.size() > 0) {
                            Iterator<Map.Entry<String, String>> iterator = entrySet.iterator();
                            while (iterator.hasNext()) {
                                Map.Entry<String, String> entry = iterator.next();
                                if (entry != null) {
                                    String key = entry.getKey();
                                    String value = entry.getValue();
                        
									//处理转义的问题关键在这 URLEncoder.encode()

                                    builder.addEncoded(URLEncoder.encode(key, "UTF-8"), URLEncoder.encode(value, "UTF-8"));
                                }
                            }

                        }
                    }
                    newBuilder.method(request.method(), builder.build());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                if (requestBody instanceof FormBody) {
                    FormBody.Builder builder = new FormBody.Builder();
                    FormBody body = (FormBody) requestBody;
                    if (body != null && body.size() > 0) {
                        for (int i = 0; i < body.size(); i++) {
                            builder.addEncoded(body.encodedName(i), body.encodedValue(i));
                        }
                    }
                    //加公共参数
                    builder.add("curLoginAcc", StringUtils.null2Length0(UserPreferences.getInstance(MyApplication.getContext()).getUserAccount()));
                    newBuilder.method(request.method(), builder.build());
                }
            }
            Request build = newBuilder.build();
            return chain.proceed(build);
        }
    };

猜你喜欢

转载自blog.csdn.net/yin13753884368/article/details/84380842