# 安全校验
# API调试参数
- URL: 获取游戏入口Url,商务沟通后提供
- merchant_id: 商务沟通后提供
- secretkey: 商务沟通后提供
# 加密解密方式
2.1. 请求和响应数据格式
平台访问游戏方API的结构:
header:
x-game-merchant-id:"123"
原始数据:
{
"merchant_id":"123"
"account":"123456"
"currency":"USD"
}
加解密使用的secretKey: D2434fgdgfdgfg12
则首先对这个json串进行加密,假设有以下加密结果:
加密后发送:
{
"data": 加密后的数据(HykjzxldgwfSIYc6nyvlUxkqmCR8TEzeyYVxQmAXvk6ZzHtu38ReQml6F9oMI2cc)
}
游戏方返回给平台方的结构:
{
"errno" string 请查阅文档的错误码
"errmsg" string 错误描述
"data": 加密后的数据(HykjzxldgwfSIYc6nyvlUxkqmCR8TEzeyYVxQmAXvk6ZzHtu38ReQml6F9oMI2cc)
}
响应data解密结果: {"account":"123456","merchant_id":"123", "currency":"USD"}
# 代码SDK(JAVA)
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Base64;
/**
* CIA Java AES/CBC/PKCS5Padding 加密
*/
public class AESUtil {
public static String Encrypt(String sSrc, String sKey) {
String password = sKey.substring(0, 16);
try {
if (password == null) {
System.out.print("Key为空null");
return null;
}
// 判断Key是否为16位
if (password.length() != 16) {
System.out.print("Key长度不是16位");
return null;
}
byte[] raw = password.getBytes("utf-8");
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//"算法/模式/补码方式"
IvParameterSpec iv = new IvParameterSpec(password.getBytes());//使用CBC模式,需要一个向量iv,可增加加密算法的强度
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(sSrc.getBytes());
String encrypteds = Base64.getEncoder().encodeToString(encrypted);
return URLDecoder.decode(URLEncoder.encode(encrypteds, "UTF-8"), "UTF-8");// 通过Base64转码返回
} catch (Exception ex) {
System.out.println(ex);
return null;
}
}
public static String Decrypt(String URLDecoders, String sKey) {
String password = sKey.substring(0, 16);
try {
// 判断Key是否正确
if (password == null) {
System.out.print("Key为空null");
return null;
}
// 判断Key是否为16位
if (password.length() != 16) {
System.out.print("Key长度不是16位");
return null;
}
byte[] raw = password.getBytes("utf-8");
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec iv = new IvParameterSpec(password.getBytes());
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] encrypted1 = Base64.getDecoder().decode(URLDecoders);//先用base64解密
try {
byte[] original = cipher.doFinal(encrypted1);
String originalString = new String(original);
return originalString;
} catch (Exception e) {
System.out.println(e.toString());
return null;
}
} catch (Exception ex) {
System.out.println(ex.toString());
return null;
}
}
public static void main(String[] args) {
String jsonString = "{\"game_name\":\"百家乐\",\"desk_name\":\"百家乐002\"}";
String en = Encrypt(jsonString, "uZlAJM2YgUHBQqtUQuoCNCGGoeMdbd4hw6u1tmWL");
System.out.println("加密:" + en);
String decr = Decrypt(en, "uZlAJM2YgUHBQqtUQuoCNCGGoeMdbd4hw6u1tmWL");
System.out.println("解密:" + decr);
}
}
# 代码SDK(golang)
package secret
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
)
func AesEncrypt(sSrc string, sKey string) (string, error) {
if len(sKey) < 16 {
return "", fmt.Errorf("Key长度不是16字节")
}
password := sKey[:16]
key := []byte(password)
plaintext := []byte(sSrc)
// 判断Key长度是否为16字节
if len(key) != 16 {
return "", fmt.Errorf("Key长度不是16字节")
}
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
// 判断输入字符串是否为空
if len(plaintext) == 0 {
return "", fmt.Errorf("输入字符串为空")
}
// PKCS5Padding 填充
blockSize := block.BlockSize()
padding := blockSize - len(plaintext)%blockSize
padText := make([]byte, len(plaintext)+padding)
copy(padText, plaintext)
for i := len(plaintext); i < len(padText); i++ {
padText[i] = byte(padding)
}
ciphertext := make([]byte, len(padText))
iv := []byte(password)
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext, padText)
encoded := base64.StdEncoding.EncodeToString(ciphertext)
return encoded, nil
}
func AesDecrypt(decoders string, sKey string) (string, error) {
if len(sKey) < 16 {
return "", fmt.Errorf("Key长度不是16字节")
}
password := sKey[:16]
key := []byte(password)
enc, err := base64.StdEncoding.DecodeString(decoders)
if err != nil {
return "", err
}
// 判断Key长度是否为16字节
if len(key) != 16 {
return "", fmt.Errorf("Key长度不是16字节")
}
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
if len(enc) == 0 {
return "", fmt.Errorf("输入字符串为空")
}
if len(enc)%aes.BlockSize != 0 {
return "", fmt.Errorf("输入字符串长度不是块大小的倍数")
}
iv := []byte(password)
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(enc, enc)
// 去除PKCS5Padding填充
padding := int(enc[len(enc)-1])
if padding > 0 && padding <= aes.BlockSize {
enc = enc[:len(enc)-padding]
}
return string(enc), nil
}