# 数据加解密
对于敏感数据,小游戏会对数据进行加密,开发者需要在服务端进行解密。
# 解密算法
- 对称解密使用的算法为 AES-128-CBC,数据采用 PKCS#7 填充。
- 对称解密的目标密文为 Base64_Decode(encryptedData)。
- 对称解密秘钥 aeskey = Base64_Decode(session_key), aeskey 是 16 字节。
- 对称解密算法初始向量为 Base64_Decode(iv),其中 iv 由数据接口返回。
# 解密步骤
- 对 encryptedData 进行 Base64 解码,得到密文数据
- 对 iv 进行 Base64 解码,得到初始向量
- 对 session_key 进行 Base64 解码,得到 AES 密钥
- 使用 AES-128-CBC 模式和 PKCS#7 填充方式,以及上述密钥和初始向量对密文进行解密
- 解析解密后的 JSON 数据
# 示例代码(Golang)
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/json"
"fmt"
)
type DataCrypt struct {
AppID string
SessionKey string
}
func NewDataCrypt(miniAppID, sessionKey string) *DataCrypt {
return &DataCrypt{
AppID: miniAppID,
SessionKey: sessionKey,
}
}
func (w *DataCrypt) DecryptData(encryptedData, iv string) (string, error) {
if w.SessionKey == "" {
return "", fmt.Errorf("ErrIllegalAesKey")
}
if encryptedData == "" {
return "", fmt.Errorf("ErrIllegalBuffer")
}
if iv == "" {
return "", fmt.Errorf("ErrIllegalIv")
}
aesKey, err := base64.StdEncoding.DecodeString(w.SessionKey)
if err != nil {
return "", fmt.Errorf("DecodeBase64")
}
aesIV, err := base64.StdEncoding.DecodeString(iv)
if err != nil {
return "", fmt.Errorf("DecodeBase64")
}
if len(aesKey) != 16 && len(aesKey) != 32 {
return "", fmt.Errorf("ErrIllegalAesKey")
}
if len(aesIV) != 16 {
return "", fmt.Errorf("ErrIllegalIv")
}
aesCipher, err := base64.StdEncoding.DecodeString(encryptedData)
if err != nil {
return "", fmt.Errorf("DecodeBase64")
}
if len(aesCipher) == 0 || len(aesCipher)%16 != 0 {
return "", fmt.Errorf("ErrIllegalBuffer")
}
block, err := aes.NewCipher(aesKey)
if err != nil {
return "", fmt.Errorf("IllegalAesKey")
}
blockMode := cipher.NewCBCDecrypter(block, aesIV)
decrypted := make([]byte, len(aesCipher))
blockMode.CryptBlocks(decrypted, aesCipher)
unpaddedData, err := pkcs7Unpad(decrypted)
if err != nil {
return "", err
}
var dataObj map[string]interface{}
err = json.Unmarshal(unpaddedData, &dataObj)
if err != nil {
return "", fmt.Errorf("IllegalBuffer")
}
watermark, ok := dataObj["watermark"].(map[string]interface{})
if !ok {
return "", fmt.Errorf("IllegalBuffer")
}
appIDFromWatermark, ok := watermark["appid"].(string)
if !ok || appIDFromWatermark != w.AppID {
return "", fmt.Errorf("IllegalBuffer")
}
return string(unpaddedData), nil
}
func pkcs7Unpad(data []byte) ([]byte, error) {
length := len(data)
if length == 0 {
return nil, fmt.Errorf("pkcs7: input data is empty")
}
unpadding := int(data[length-1])
for i := length - unpadding; i < length; i++ {
if data[i] != byte(unpadding) {
return nil, fmt.Errorf("pkcs7: invalid padding")
}
}
return data[:(length - unpadding)], nil
}
func DecryptDemo() (string, error){
miniAppID := "tapmxxxxxxxx"
sessionKey := "xxxxxx"
encryptedData := "xxxxxx"
iv := "xxxxxx"
pc := NewDataCrypt(miniAppID, sessionKey)
return pc.DecryptData(encryptedData, iv)
}