# 敏感数据处理
# 校验数据合法性
当开发者通过getUserInfo接口请求到敏感数据时,返回的signature
字段是在小程序服务器端通过如下算法得到:
signature = sha1(`${rawData}${base64(session_key)}`)
1
开发者可以在自己的服务器端执行同样的算法,来校验数据是否合法。
# 解密敏感数据
- 对称解密使用的算法为
AES-128-CBC
,数据采用PKCS#5
填充。 - 对称解密的目标密文为
encryptedData
。 - 对称解密秘钥
aeskey = Base64_Decode(session_key)
,aeskey
长度为16Byte。 - 对称解密算法初始向量为
Base64_Decode(iv)
。
# 代码示例
代码示例中的 sessionKey
为会话密钥, 由 code2session 返回。
//nodejs语言
const crypto = require("crypto");
sessionKey = '36f764e22be7fc5edb07f56073a4b770';
iv = 'f210af090c830cd5c47e67eeb4f52001';
message = 'Ssy006/cEV4+a2wUWTGvHuXIkU+vX1KCNUkLntKKVXzggx6yfycO/RDkx55A8TvhI5EUGKJ8X4x3NBCypWlkvODaCSDw6uUBhqbDaRS9vH57Dk9nVcw+u2ANGU4PmW/WX2ihze8hDMpofD/pDfZCkEjnvmqkeZ+jPxq351bpDwTUJ+mae92iL9DuHd+xz6WC5cUx9HE8AbxUD18dGUwt2KcNNi9ePvgcvGZBEgZGG2s=';
function decrypt_with_aes() {
message = Buffer.from(message, 'base64');
const decipher = crypto.createDecipheriv(
'aes-128-cbc',
Buffer.from(sessionKey, 'hex'),
Buffer.from(iv, 'hex'),
);
let decrypted = decipher.update(message);
decrypted += decipher.final();
const data = decrypted.toString();
const json = JSON.parse(data);
return json;
}
console.log(decrypt_with_aes())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#python3语言
import base64
import json
from Crypto.Cipher import AES
def decrypt_with_aes():
session_key = '36f764e22be7fc5edb07f56073a4b770';
iv = "f210af090c830cd5c47e67eeb4f52001";
message = "Ssy006/cEV4+a2wUWTGvHuXIkU+vX1KCNUkLntKKVXzggx6yfycO/RDkx55A8TvhI5EUGKJ8X4x3NBCypWlkvODaCSDw6uUBhqbDaRS9vH57Dk9nVcw+u2ANGU4PmW/WX2ihze8hDMpofD/pDfZCkEjnvmqkeZ+jPxq351bpDwTUJ+mae92iL9DuHd+xz6WC5cUx9HE8AbxUD18dGUwt2KcNNi9ePvgcvGZBEgZGG2s=";
session_key = bytes.fromhex(session_key)
iv = bytes.fromhex(iv)
message = base64.b64decode(message)
print(session_key, len(session_key), type(session_key))
print(len(message))
decipher = AES.new(session_key, AES.MODE_CBC, iv)
decodedMessage = decipher.decrypt(message)
unpad = lambda s: s[0:-s[-1]]
decodedMessage = unpad(decodedMessage)
data = json.loads(decodedMessage)
return data
print(decrypt_with_aes())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//java语言
import org.junit.jupiter.api.Test;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class DecryptTest {
@Test
public void test_decrypt() throws Exception {
System.out.println(decrypt_with_aes());
}
public static String decrypt_with_aes() throws Exception {
String session_key = "36f764e22be7fc5edb07f56073a4b770";
String iv = "f210af090c830cd5c47e67eeb4f52001";
String message = "Ssy006/cEV4+a2wUWTGvHuXIkU+vX1KCNUkLntKKVXzggx6yfycO/RDkx55A8TvhI5EUGKJ8X4x3NBCypWlkvODaCSDw6uUBhqbDaRS9vH57Dk9nVcw+u2ANGU4PmW/WX2ihze8hDMpofD/pDfZCkEjnvmqkeZ+jPxq351bpDwTUJ+mae92iL9DuHd+xz6WC5cUx9HE8AbxUD18dGUwt2KcNNi9ePvgcvGZBEgZGG2s=";
Cipher cipher = Cipher.getInstance("AES/CBC/NOPADDING");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(hexToBytes(session_key), "AES"), new IvParameterSpec(hexToBytes(iv)));
byte[] r = cipher.doFinal(Base64.getDecoder().decode(message));
byte lastByte = r[r.length - 1];
if (lastByte <= 16) { // if has PKCS7Padding padding, do unpadding
byte[] rr = new byte[r.length - lastByte];
System.arraycopy(r, 0, rr, 0, rr.length);
r = rr;
}
return new String(r);
}
private static byte[] hexToBytes(String s) {
s = s.toLowerCase();
String hexVal = "0123456789abcdef";
byte[] out = new byte[s.length() / 2];
int n = s.length();
for (int i = 0; i < n; i += 2) {
int hn = hexVal.indexOf(s.charAt(i));
int ln = hexVal.indexOf(s.charAt(i + 1));
out[i / 2] = (byte) ((hn << 4) | ln);
}
return out;
}
}
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
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
// golang语言
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/hex"
"fmt"
"testing"
)
func decrypt_with_aes(message_ string, sessionKey_ string, iv_ string) (string, error) {
sessionKey, err := hex.DecodeString(sessionKey_)
if err != nil {
return "", err
}
iv, err := hex.DecodeString(iv_)
if err != nil {
return "", err
}
message, err := base64.StdEncoding.DecodeString(message_)
if err != nil {
return "", err
}
block, err := aes.NewCipher(sessionKey)
if err != nil {
return "", err
}
res := make([]byte, len(message))
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(res, message)
unpaddingLen := 0
if p := res[len(res)-1]; p <= 16 { // if has PKCS7Padding padding, do unpadding
unpaddingLen = int(p)
}
res = res[0 : len(res)-unpaddingLen]
return string(res), nil
}
func TestAES(t *testing.T) {
session_key := "36f764e22be7fc5edb07f56073a4b770"
iv := "f210af090c830cd5c47e67eeb4f52001"
message := "Ssy006/cEV4+a2wUWTGvHuXIkU+vX1KCNUkLntKKVXzggx6yfycO/RDkx55A8TvhI5EUGKJ8X4x3NBCypWlkvODaCSDw6uUBhqbDaRS9vH57Dk9nVcw+u2ANGU4PmW/WX2ihze8hDMpofD/pDfZCkEjnvmqkeZ+jPxq351bpDwTUJ+mae92iL9DuHd+xz6WC5cUx9HE8AbxUD18dGUwt2KcNNi9ePvgcvGZBEgZGG2s="
fmt.Println(decrypt_with_aes(message, session_key, iv))
}
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
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
← getUserInfo enterChat →