星河

醉后不知天在水,满船清梦压星河

Golang AES-128/GCM + BASE64 加密

mingzaily / 2021-03-15


需求背景:接入网络游戏防沉迷系统,其中请求体body需要进行加密,和签名

加密

func GCMEncrypt(secretKey, originalText string) (string, error) {
	// 密钥需要解码
	key, _ := hex.DecodeString(secretKey)
	block, err := aes.NewCipher(key)
	if err != nil {
		return "", err
	}

	aesGcm, err := cipher.NewGCM(block)
	if err != nil {
		return "", err
	}
	
	// 向量
	nonce := make([]byte, aesGcm.NonceSize())
	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
		return "", err
	}

	cipherText := aesGcm.Seal(nonce, nonce, []byte(originalText), nil)

	// encode as base64 string
	encoded := base64.StdEncoding.EncodeToString(cipherText)
	return encoded, nil
}

签名

func (s *encryptService) Sign(headers, body map[string]string) string {
	var data string
	var keys []string
	// key排序
	for k := range headers {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	// 拼接
	for _, k := range keys {
		data = data + k + headers[k]
	}
	data = s.appSecret + data + gconv.String(body)

	// 对字符串进行sha256哈希
	h := sha256.New()
	h.Write([]byte(data))
	sum := h.Sum(nil)
	return hex.EncodeToString(sum)
}

使用

// 参数初始化
headers := map[string]string{
	"appId":      "xxxxxxxx",
	"bizId":      "xxxxxxxx",
	"timestamps": strconv.Itoa(int(time.Now().UnixNano() / 1e6)),
}
// 请求体加密
jsonByte, _ := json.Marshal(req)
cipher, _ := GCMEncrypt(string(jsonByte), 'xxxxxxxxx') // 第二个参数是密钥
body := map[string]string{
	"data": cipher,
}
// 生成签名
headers["sign"] = Encrypt.Sign(headers, body)
headers["Content-Type"] = "application/json"
.....发http请求