Android Java iOS 三端RSA和AES加密处理
程序员文章站
2024-03-14 15:34:10
...
Android Java iOS 三端RSA和AES加密处理
-
之前写的一篇博客关于 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);
}
};
- 需要的小伙伴快去下载吧
- 资源地址