加密对接说明
<p>[TOC]</p>
<h5>加密对接说明</h5>
<ul>
<li>加密方式:BASE64AES</li>
<li>加密秘钥:用户秘钥(secretkey)的前16位</li>
<li>加密解密方:
请求:客户将校验请求参数(param)加密后请求到平台,由平台解密处理
响应:平台将产品响应参数(data)加密响应给客户,由客户解密处理</li>
<li>加密解密代码示例:查看本页章节 <code>代码示例</code></li>
<li>若需要加密对接请联系运营人员进行配置</li>
</ul>
<h5>加密对接产品说明</h5>
<p>人像比对、身份证OCR、驾驶证OCR、行驶证OCR、人脸1:1对比、活体检测请求参数无需加密,响应需要解密。
其他所有产品请求参数需要加密,响应需要解密。</p>
<h5>请求加密</h5>
<p>下面将以号码实时状态检测为例,对请求加密和响应解密进行说明。</p>
<h6>加密内容</h6>
<p>将明文对接的校验请求参数(param)的整个JSON对象进行加密。号码实时状态检测的校验请求参数如下:</p>
<table>
<thead>
<tr>
<th>参数名</th>
<th>是否必填</th>
<th>类型</th>
<th><div style="width: 400px"/>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>phone</td>
<td>是</td>
<td>string</td>
<td>手机号,11位</td>
</tr>
<tr>
<td>servicecode</td>
<td>是</td>
<td>string</td>
<td>服务编码,4位</td>
</tr>
</tbody>
</table>
<h6>加密示例</h6>
<pre><code>secretkey:5ayct8yng8cujwitkce0tsk9pb6b5da7
请求加密原文:{&quot;servicecode&quot;:&quot;1002&quot;,&quot;phone&quot;:&quot;15001090000&quot;}
请求加密密文:2l26DAyRxFq+WLv+xavg1vB3KS8JhX+TCwSiJG0LBc6Zn/klmNKBC7x1KEqWS7YK</code></pre>
<h6>请求示例</h6>
<pre><code>{
&quot;authinfo&quot;: {
&quot;appid&quot;: &quot;607785267fb42ad9b5bb701ada446512&quot;,
&quot;sign&quot;: &quot;eb514ea44c6586664d04240ea51be20b&quot;,
&quot;userkey&quot;: &quot;36e2a500839a49653de14fc3d7a24812&quot;,
&quot;timestamp&quot;: &quot;20190523151159&quot;
},
&quot;param&quot;: &quot;2l26DAyRxFq+WLv+xavg1vB3KS8JhX+TCwSiJG0LBc6Zn/klmNKBC7x1KEqWS7YK&quot;
}</code></pre>
<h6>加密内容错误说明</h6>
<p>若应用产品设置的是“加密对接”,请求的是未加密的内容 或 未正确加密的内容,响应为308:校验参数加密内容错误。
若应用产品设置的是“明文对接”,请求的是加密的内容 或 未正确加密的内容,响应为212:校验参数格式错误。</p>
<h5>响应解密</h5>
<h6>解密内容</h6>
<p>将验真结果(data)的字符串进行解密。号码实时状态检测的产品响应参数如下:</p>
<table>
<thead>
<tr>
<th>参数名</th>
<th>是否必填</th>
<th>类型</th>
<th><div style="width: 400px"/>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>state</td>
<td>是</td>
<td>string</td>
<td>验真状态码</td>
</tr>
<tr>
<td>desc</td>
<td>是</td>
<td>string</td>
<td>验真状态码描述</td>
</tr>
</tbody>
</table>
<h6>解密示例</h6>
<pre><code>secretkey:5ayct8yng8cujwitkce0tsk9pb6b5da7
响应加密密文:BBrdzf+JY213XeqQvU12kSPpqMOEq7IZoetJXdXTjUk=
响应解密原文:{&quot;state&quot;:&quot;1&quot;,&quot;desc&quot;:&quot;正常&quot;}</code></pre>
<h6>响应示例</h6>
<pre><code>{
&quot;code&quot;: &quot;000&quot;,
&quot;msgid&quot;: &quot;914911552623822824&quot;,
&quot;message&quot;: &quot;请求成功&quot;,
&quot;data&quot;: &quot;BBrdzf+JY213XeqQvU12kSPpqMOEq7IZoetJXdXTjUk=&quot;
}</code></pre>
<h5>代码示例</h5>
<h6>Java</h6>
<pre><code>import com.alibaba.fastjson.JSONObject;
import org.springframework.util.StringUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class Base64AESUtil {
public static void main(String[] args) throws Exception {
String secretKey = &quot;5ayct8yng8cujwitkce0tsk9pb6b5da7&quot;.substring(0, 16);
JSONObject params = new JSONObject();
params.put(&quot;phone&quot;, &quot;15001090000&quot;);
params.put(&quot;servicecode&quot;, &quot;1002&quot;);
String paramsSrc = params.toJSONString();
System.out.println(&quot;请求加密原文:&quot; + paramsSrc); //请求加密原文:{&quot;servicecode&quot;:&quot;1002&quot;,&quot;phone&quot;:&quot;15001090000&quot;}
System.out.println(&quot;请求加密秘文:&quot; + aesEncrypt(paramsSrc, secretKey)); //请求加密秘文:2l26DAyRxFq+WLv+xavg1vB3KS8JhX+TCwSiJG0LBc6Zn/klmNKBC7x1KEqWS7YK
JSONObject data = new JSONObject();
data.put(&quot;state&quot;, &quot;1&quot;);
data.put(&quot;desc&quot;, &quot;正常&quot;);
String dataDecryptResult = aesEncrypt(data.toJSONString(), secretKey);
System.out.println(&quot;响应加密秘文:&quot; + dataDecryptResult); //响应加密秘文:BBrdzf+JY213XeqQvU12kSPpqMOEq7IZoetJXdXTjUk=
System.out.println(&quot;响应解密原文:&quot; + aesDecrypt(dataDecryptResult, secretKey)); //响应解密原文:{&quot;state&quot;:&quot;1&quot;,&quot;desc&quot;:&quot;正常&quot;}
}
private static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
Cipher cipher = Cipher.getInstance(&quot;AES/CBC/NoPadding&quot;);
int blockSize = cipher.getBlockSize();
byte[] dataBytes = content.getBytes(&quot;utf-8&quot;);
int plaintextLength = dataBytes.length;
if (plaintextLength % blockSize != 0) {
plaintextLength += blockSize - plaintextLength % blockSize;
}
byte[] plaintext = new byte[plaintextLength];
System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
SecretKeySpec keySpec = new SecretKeySpec(encryptKey.getBytes(), &quot;AES&quot;);
IvParameterSpec ivSpec = new IvParameterSpec(encryptKey.getBytes());
cipher.init(1, keySpec, ivSpec);
return cipher.doFinal(plaintext);
}
//加密
public static String aesEncrypt(String content, String encryptKey) throws Exception {
return StringUtils.isEmpty(content) || StringUtils.isEmpty(encryptKey) ? null : (new BASE64Encoder()).encode(aesEncryptToBytes(content, encryptKey));
}
private static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {
Cipher cipher = Cipher.getInstance(&quot;AES/CBC/NoPadding&quot;);
SecretKeySpec keySpec = new SecretKeySpec(decryptKey.getBytes(), &quot;AES&quot;);
IvParameterSpec ivSpec = new IvParameterSpec(decryptKey.getBytes());
cipher.init(2, keySpec, ivSpec);
byte[] decryptBytes = cipher.doFinal(encryptBytes);
String result = new String(decryptBytes);
if (StringUtils.hasText(result)) {
result = result.trim();
}
return result;
}
//解密
public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
return StringUtils.isEmpty(encryptStr) || StringUtils.isEmpty(decryptKey) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
}
private static byte[] base64Decode(String base64Code) throws Exception {
return StringUtils.isEmpty(base64Code) ? null : (new BASE64Decoder()).decodeBuffer(base64Code);
}
}</code></pre>
<h6>Python</h6>
<pre><code>#!/usr/bin/env python
# -*- coding:utf-8 -*-
from Crypto.Cipher import AES
import json
import base64
class Base64AesUtil:
def __init__(self, key):
self.key = key
self.mode = AES.MODE_CBC
# 加密
def encrypt(self, text):
import base64
crypto = AES.new(self.key, self.mode, self.key)
length = 16 # 用于下面取余
count = len(text.encode('utf-8'))
if count % length != 0:
add = length - (count % length)
else:
add = 0
text1 = text + ('\0' * add) # 其它语言nopadding时,python还是需要‘\0’或'\x00'这里注意与其它语言对接注意
return str(base64.b64encode(crypto.encrypt(text1)), encoding='utf-8')
# 解密
def decrypt(self, text):
base_text = base64.b64decode(text)
crypto = AES.new(self.key, self.mode, self.key)
return crypto.decrypt(base_text).decode('utf-8').rstrip('\0')
if __name__ == '__main__':
secretKey = &quot;5ayct8yng8cujwitkce0tsk9pb6b5da7&quot;[0:16]
params = {&quot;servicecode&quot;: &quot;1002&quot;, &quot;phone&quot;: &quot;15001090000&quot;}
aes_encrypt = Base64AesUtil(secretKey) # 初始化密钥
# ensure_ascii需要设置为False,Java的fastjson的toJSONString方法没有空格需要替换掉
params_src = json.dumps(params, ensure_ascii=False).replace(&quot; &quot;, &quot;&quot;)
print(&quot;请求加密原文:&quot;, params_src) # 请求加密原文: {&quot;servicecode&quot;:&quot;1002&quot;,&quot;phone&quot;:&quot;15001090000&quot;}
print(&quot;请求加密秘文:&quot;, aes_encrypt.encrypt(params_src)) # 请求加密秘文: 2l26DAyRxFq+WLv+xavg1vB3KS8JhX+TCwSiJG0LBc6Zn/klmNKBC7x1KEqWS7YK
data = {&quot;state&quot;: &quot;1&quot;, &quot;desc&quot;: &quot;正常&quot;}
data_src = json.dumps(data, ensure_ascii=False).replace(&quot; &quot;, &quot;&quot;)
data_decrypt_result = aes_encrypt.encrypt(data_src)
print(&quot;响应加密秘文:&quot;, data_decrypt_result) # 响应加密秘文: BBrdzf+JY213XeqQvU12kSPpqMOEq7IZoetJXdXTjUk=
print(&quot;响应解密原文:&quot;, aes_encrypt.decrypt(data_decrypt_result)) # 响应解密原文: {&quot;state&quot;:&quot;1&quot;,&quot;desc&quot;:&quot;正常&quot;}</code></pre>