AES对称加解密
高级加密标准(英语:Advanced Encryption Standard,缩写:AES),是目前对称密钥加密中比较通用的一种加密方式,也是高德云店在进行传输数据对称加密时的选择。
1 简介
使用场景
高德调用商家或者商家调用高德的请求业务参数biz_content以及响应data在默认情况下均为明文。开启加密后,请求和返回的业务字段在网络上传输时将会由明文内容变为密文内容,可以大大提升接口内容传输的安全性。目前只有部分对内容敏感的交互接口要求使用AES加解密,请参考具体接口文档或咨询高德业务方。
AES对称密钥与RSA公私钥的关系
预览
AES是对称加密算法,加密和解密使用相同的密钥,用于保证报文敏感信息在传输过程中不被泄漏,不强制使用
RSA是非对称加密算法,加签和验签使用一组互相匹配的公私钥密钥对,用于保证报文在信息传输过程中不被篡改,以及校验请求来源,目前接口交互强制使用
2 商家调用高德
商家调用高德时,如果和高德业务方确认后需要对接口进行AES加密传输,则需要完成以下步骤
对请求业务参数biz_content字符串进行AES加密运算
请求高德时携带额外表单参数need_encrypt=true
接收高德响应后,对响应的结构体data内容进行AES解密(经过加密的data内容为字符串)
注:RSA签名不受AES加解密影响,商家需要先将biz_content内容先进行加密,加密后的密文再参与签名sign的生成
3 高德调用商家
高德调用商家时,如果和高德业务方确认后需要对接口进行AES加密传输,则需要完成以下步骤
接收高德请求后,将业务参数biz_content字符串进行AES解密,得到业务参数明文
响应返回高德时,对响应的结构体data内容进行AES加密(将data内容转换为字符串后进行加密)
注:RSA验签不受AES加解密影响,商家需要先用接收到的biz_content密文进行验签,然后再对biz_content内容进行解密
4 代码示例
Java版本
1import org.apache.commons.codec.binary.Base64;
2
3import javax.crypto.Cipher;
4import javax.crypto.spec.IvParameterSpec;
5import javax.crypto.spec.SecretKeySpec;
6import java.security.GeneralSecurityException;
7
8/**
9 * 描述:aes加解密示例,仅供参考
10 * 本示例中使用到jdk security包提供的AES加密算法能力
11 *
12 * @authoer 高小德
13 */
14public class EncryptUtils {
15
16 private static final String AES_ALG = "AES";
17
18 /**
19 * AES算法
20 */
21 private static final String AES_CBC_PCK_ALG = "AES/CBC/PKCS5Padding";
22
23 private static final byte[] AES_IV = initIv(AES_CBC_PCK_ALG);
24
25 //test
26 public static void main(String[] args) throws Exception {
27 //aes密钥,请联系高德业务方或开发人员获取aes密钥,需要和rsa签名公私钥区分开
28 String aeskey = "7ECF0A2CAC368600C76FFAF7DDCB253F";
29 String charset = "UTF-8";
30
31 //解密示例
32 String content = "weKsNqlOJGfg9c2ehh9PEAwa5us07q7kIsJ51ZD+4Y3H8MmBPuSIIy6zIIDUfwzw8f+gNncJRr9gnarFZvB2MmAT5InhUVRze0SaU7RWc6byrnR3zkPlr0jEboVZFXCB";
33 System.out.println(aesDecrypt(content, aeskey, charset));
34
35 //加密示例
36 String data = "{{\"shop_id\":\"1067\",\"status\":\"1\"}}";
37 System.out.println(aesEncrypt(data, aeskey, charset));
38 }
39
40 /**
41 * AES加密
42 *
43 * @param content
44 * @param aesKey
45 * @param charset
46 * @return
47 * @throws Exception
48 */
49 private static String aesEncrypt(String content, String aesKey, String charset)
50 throws Exception {
51
52 try {
53 Cipher cipher = Cipher.getInstance(AES_CBC_PCK_ALG);
54
55 IvParameterSpec iv = new IvParameterSpec(AES_IV);
56 cipher.init(Cipher.ENCRYPT_MODE,
57 new SecretKeySpec(Base64.decodeBase64(aesKey.getBytes()), AES_ALG), iv);
58
59 byte[] encryptBytes = cipher.doFinal(content.getBytes(charset));
60 return new String(Base64.encodeBase64(encryptBytes));
61 } catch (Exception e) {
62 throw new Exception(e);
63 }
64
65 }
66
67 /**
68 * AES解密
69 *
70 * @param content
71 * @param key
72 * @param charset
73 * @return
74 * @throws Exception
75 */
76 private static String aesDecrypt(String content, String key, String charset)
77 throws Exception {
78 try {
79 Cipher cipher = Cipher.getInstance(AES_CBC_PCK_ALG);
80 IvParameterSpec iv = new IvParameterSpec(initIv(AES_CBC_PCK_ALG));
81 cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(key.getBytes()),
82 AES_ALG), iv);
83
84 byte[] cleanBytes = cipher.doFinal(Base64.decodeBase64(content.getBytes()));
85 return new String(cleanBytes, charset);
86 } catch (Exception e) {
87 throw new Exception(e);
88 }
89 }
90
91 /**
92 * 初始向量的方法, 全部为0.
93 *
94 * @param fullAlg
95 * @return
96 * @throws GeneralSecurityException
97 */
98 private static byte[] initIv(String fullAlg) {
99
100 try {
101 Cipher cipher = Cipher.getInstance(fullAlg);
102 int blockSize = cipher.getBlockSize();
103 byte[] iv = new byte[blockSize];
104 for (int i = 0; i < blockSize; ++i) {
105 iv[i] = 0;
106 }
107 return iv;
108 } catch (Exception e) {
109 int blockSize = 16;
110 byte[] iv = new byte[blockSize];
111 for (int i = 0; i < blockSize; ++i) {
112 iv[i] = 0;
113 }
114 return iv;
115 }
116 }
117}
118
注:AES密钥以及其他语言版本的AES加解密工具请联系高德业务方或开发人员获取
附1 加密算法明细
加密算法 标准加密算法 初始向量 描述
AES AES/CBC/PKCS5Padding 128位(16字节)全0值 AES密钥长度为128位
_
对称密钥aesKey采用BASE64格式编码,所以在进行加解密时需要先将对称密钥进行BASE64解码后使用
AES算法采用CBC模式进行加解密,初始向量定义为128位(16字节)全0值
加密后得到字节数组需要先做 base64 编码,然后再新建字符串(由于 base64 后的字节一定是 ASCII 范围内,所以最后一步 new String 的时候无需指定字符集),同理解密前的内容需要先做 base64 解码,用于传输的密文内容永远是经过base64编码过的

