一、前言
公司APP开发模式为手机端登录逻辑使用原生安卓开发,内部业务功能使用html5开发,客户安全要求明文不能传输敏感信息、传输数据不可修改,防止造成越权访问问题。基于这个要求我设计前后端交互对整个过程进行全部的加密处理,然后在加载和处理的时候进行解密处理。这个时候就必须设计一套java和js可以通用的加密和解密方式。这里我们采用了AES加解密。
二、java加解密工具
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
| import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64; import java.security.SecureRandom;
public class AESUtils {
private static final String KEY = "9936667890hijklm";
// 偏移量,AES 128位数据块对应偏移量为16位 public static final String VIPARA = "3424578890abcdef"; // AES 128位数据块对应偏移量为16位
// AES:加密方式 CBC:工作模式 PKCS5Padding:填充模式 private static final String CBC_PKCS5_PADDING = "AES/CBC/PKCS5Padding";
private static final String AES = "AES";
// 编码方式 public static final String CODE_TYPE = "UTF-8";
/** * AES 加密操作 * * @param content * 待加密内容 * @param key * 加密密钥 * @return 返回Base64转码后的加密数据 */ public static String encrypt(String content, String key) {
if (content == null || "".equals(content)) { return content; }
try { /* * 新建一个密码编译器的实例,由三部分构成,用"/"分隔,分别代表如下 1. 加密的类型(如AES,DES,RC2等) 2. * 模式(AES中包含ECB,CBC,CFB,CTR,CTS等) 3. 补码方式(包含nopadding/PKCS5Padding等等) * 依据这三个参数可以创建很多种加密方式 */ Cipher cipher = Cipher.getInstance(CBC_PKCS5_PADDING);
// 偏移量 IvParameterSpec zeroIv = new IvParameterSpec(VIPARA.getBytes(CODE_TYPE));
byte[] byteContent = content.getBytes(CODE_TYPE);
// 使用加密秘钥 SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(CODE_TYPE), AES); // SecretKeySpec skeySpec = getSecretKey(key);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, zeroIv);// 初始化为加密模式的密码器
byte[] result = cipher.doFinal(byteContent);// 加密
return Base64.encodeBase64String(result).replaceAll("\r\n", "");// 通过Base64转码返回 } catch (Exception ex) { ex.printStackTrace(); }
return null;
}
/** * AES 解密操作 * * @param content * @param key * @return */ public static String decrypt(String content, String key) { if (content == null || "".equals(content)) { return content; }
try { // 实例化 Cipher cipher = Cipher.getInstance(CBC_PKCS5_PADDING); IvParameterSpec zeroIv = new IvParameterSpec(VIPARA.getBytes(CODE_TYPE));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(CODE_TYPE), AES); // SecretKeySpec skeySpec = getSecretKey(key); cipher.init(Cipher.DECRYPT_MODE, skeySpec, zeroIv);
byte[] result = cipher.doFinal(Base64.decodeBase64(content));
return new String(result, CODE_TYPE); } catch (Exception ex) { ex.printStackTrace(); }
return null; }
/** * 生成加密秘钥 * * @return */ private static SecretKeySpec getSecretKey(final String key) { // 返回生成指定算法密钥生成器的 KeyGenerator 对象 KeyGenerator kg = null;
try { kg = KeyGenerator.getInstance(AES);
// AES 要求密钥长度为 128 kg.init(128, new SecureRandom(key.getBytes()));
// 生成一个密钥 SecretKey secretKey = kg.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), AES);// 转换为AES专用密钥 } catch (Exception ex) { ex.printStackTrace(); }
return null; }
public static String Encrypt(String content) { String key = KEY; String s = encrypt(content, key); return s.replaceAll("/", "ut8fut8fut8f").replaceAll("[+]", "ut7fut7fut7f"); }
public static String Decrypt(String content) { String key = KEY; content = content.replaceAll("ut8fut8fut8f", "/").replaceAll("ut7fut7fut7f", "+"); return decrypt(content, key); }
public static void main(String[] args) { System.out.println(Encrypt("r6jjXhILAOds")); System.out.println(Decrypt("72FJcuL7eXwNGLmNut8fut8fut8fLqQhA=="));
System.out.println(Encrypt("632600185488")); System.out.println(Decrypt("qdlut8fut8fut8fo4uGeB0co849grtG3g==")); System.out.println(Decrypt("qdlut8fut8fut8fo4uGeB0co849grtG3g=="));
}
}
|
三、js加解密工具
从官网下载 crypto-js.js ,改造工具类增加如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| CryptoJS.wno = { Encrypt: function(data){ var key = CryptoJS.enc.Utf8.parse('9936667890hijklm'); var iv = CryptoJS.enc.Utf8.parse('3424578890abcdef'); var encrypted =CryptoJS.AES.encrypt(data,key, { iv:iv, mode:CryptoJS.mode.CBC, padding:CryptoJS.pad.Pkcs7 }); return encrypted.toString().replace(/[/]/g,'ut8fut8fut8f').replace(/[+]/g,'ut7fut7fut7f'); }, Decrypt: function(encrypted){ encrypted = encrypted.replace(/ut8fut8fut8f/g,'/').replace(/ut7fut7fut7f/g,'+'); var key = CryptoJS.enc.Utf8.parse('9936667890hijklm'); var iv = CryptoJS.enc.Utf8.parse('3424578890abcdef'); var decrypted =CryptoJS.AES.decrypt(encrypted,key, { iv:iv, mode:CryptoJS.mode.CBC, padding:CryptoJS.pad.Pkcs7 }); return decrypted.toString(CryptoJS.enc.Utf8); }
}
|
四、测试
Java加密使用: AESUtils.Encrypt(String content);
Java解密使用: AESUtils.Decrypt(String content);
Js加密使用: CryptoJS.wno.Encrypt(String content);
Js解密使用: CryptoJS.wno.Decrypt(String content);
五、常用方法
5.1 java
1 2 3 4 5 6 7
| 解密 planId = AESUtils.Decrypt(planId); args1 = AESUtils.Decrypt(paramterMap.get(key)[0]);
加密 result = "{\"info\":\""+AESUtils.Encrypt(result)+"\"}"; result = new String("{\"info\":\""+AESUtils.Encrypt(JSON.toJSONString(map))+"\"}");
|
5.2 js
1 2 3 4 5 6
| 解密 var info = data.info; var data = JSON.parse(CryptoJS.wno.Decrypt(info));
加密 param = {"uid" : CryptoJS.wno.Encrypt('112233'), "dt_start" : CryptoJS.wno.Encrypt('2021-06-01')};
|