文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Go 实现aes-256-gcm加解密处理过程

2023-09-04 18:19

关注

【知识点】

包含php的知识点:str_pad、sha1、pack、base64_encode、base64_decode、strlen、substr、openssl_decrypt、openssl_encrypt。

包含的go知识点:

sha1        哈希加密,要注意下返回的是字节数组

string([]byte)        字节数组转换成字符串,注意这里转换的二进制字符串,很多乱码

hex.EncodeToString        字节数组转成16进制,示例中有用到来转换sha1得到的值

strconv.ParseUint        字符串转换为无符号int类型,对应php的pack方法

base64.StdEncoding.DecodeString        base64解码,对应php的base64_decode

base64.StdEncoding.EncodeString        base64编码,对应php的base64_encode

strings.Replace        替换字符串,用于替换base64字符串的安全字符-和_

rand        随机字符串

crypto/cipher   aes加解密模块

参考:aes-256-gcm_python3_php7_golang_mb5fe94870638be的技术博客_51CTO博客

【需求背景】

在对接美团小游戏的时候,支付成功通知,使用了【sha1】的签名还有【aes-256-gcm】的加密数据。官方只有php7.1以上的例子,但是项目使用了golang,需要转换下。

接口文档:

文档上的php-demo例子:

//PHP demo(版本使用7.1以上)function createKey($appId, $appSecret) {$aaa = base64_encode(str_pad(sha1($appId.'&'.$appSecret,true), 32,pack('V', 0)));return $aaa;}function encryptSHA1Str($secretKey, $encryptData) {$aaa = $encryptData.$secretKey;$sign = sha1($aaa);return $sign;}function decryptWithAESGCM256($secretKey, $encryptData) {$decodeEncrypt = urlsafe_b64decode($encryptData);$decodeSecret = base64_decode($secretKey);$data = openssl_decrypt(substr($decodeEncrypt, 16, -16), 'aes-256-gcm', $decodeSecret, 1, substr($decodeEncrypt, 0, 16), substr($decodeEncrypt, -16, 16));return $data;}function urlsafe_b64decode($string) {$data = str_replace(array('-','_'),array('+','/'),$string);$mod4 = strlen($data) % 4;if ($mod4) {$data .= substr('====', $mod4);}return base64_decode($data);}

 【GO代码示例】

package mainimport ("crypto/aes""crypto/cipher""crypto/sha1""encoding/base64""errors""fmt""io""math/rand""strconv""strings")func main(){secretKey := GenSecretKey("appid12456","appsecret123456")data :="{\"bizOrderId\":\"55001151519674220220723112146446\",\"mgcId\":\"234112419424942\",\"mgcOrderId\":\"106631144674\",\"payStatus\":\"OK\",\"price\":\"100\"}\n"encryptData,_ := SetCallbackData(secretKey,data)//得到加密后的base64字符串fmt.Println(encryptData)decryptData,_ := GetCallbackData(secretKey,encryptData)//得到解密后的json字符串fmt.Println(decryptData)}//实现php的sha1()方法,返回的是byte转换的字符串,如果需要转成16进制,可以使用hex.EncodeToStringfunc GetSha1(str string) string {h := sha1.New()io.WriteString(h, str)return string(h.Sum(nil))}//右边补全字符串实现方法,主要实现php的str_pad()方法func StrPadRight(input string, padLength int, padString string) string {output := ""inputLen := len(input)if inputLen >= padLength {return input}ll := padLength - inputLenfor i := 1; i <= ll; i = i + len(padString) {output += padString}return input + output}//生成密钥func GenSecretKey(appId string, appSecret string) (secretKey string) {key := appId + "&" + appSecretsha1_str := GetSha1(key)str10 := "0"pack64, _ := strconv.ParseUint(str10, 10, 32)//对应php的pack()方法,字符串转换为uint类型fmt.Println(pack64)pack32 := uint32(pack64)str_pad := StrPadRight(sha1_str, 32, string(pack32))secretKey = base64.StdEncoding.EncodeToString([]byte(str_pad))return secretKey}func GetCallbackData(secretKey string, encryptData string) (result_str string, err error) {decodeSecretKeyByte, _ := base64.StdEncoding.DecodeString(secretKey)decodeSecretKey := string(decodeSecretKeyByte)//$data = openssl_decrypt(substr($decodeEncrypt, 16, -16), 'aes-256-gcm', $decodeSecret, 1, substr($decodeEncrypt, 0, 16), substr($decodeEncrypt, -16, 16));orderSuccessPayInfoByte, err2 := DecodeAesGcm(encryptData, decodeSecretKey,"")result_str = string(orderSuccessPayInfoByte)if err2 != nil {return result_str, errors.New("decode error")}return result_str, err}func SetCallbackData(secretKey string, data string) (result_str string, err error) {decodeSecretKeyByte, _ := base64.StdEncoding.DecodeString(secretKey)decodeSecretKey := string(decodeSecretKeyByte)orderSuccessPayInfoByte, err2 := EncodeAesGcm(data, decodeSecretKey,"")result_str = string(orderSuccessPayInfoByte)if err2 != nil {return result_str, errors.New("encode error")}return result_str, err}//url安全模式decode字符串func UrlSafeB64decode(str string) (result []byte) {str = strings.Replace(str, "-", "+", -1)str = strings.Replace(str, "_", "/", -1)mod4 := len(str) % 4if mod4 != 0 {str = str + "===="[0:mod4]}result, _ = base64.StdEncoding.DecodeString(str)return result}//base64字符串,替换转换为安全模式func UrlSafeB64encode(str string) (result string) {str = strings.Replace(str, "+", "-", -1)str = strings.Replace(str, "/", "_", -1)return str}//使用aes-256-gcm方式解密字符串,主要针对php的openssl_decrypt()方法,注意在php7.1后增加了tag和add参数func DecodeAesGcm(encryptData string, hex_key string,hex_add string) ([]byte, error) {tagSize :=16//nonceSize,tag的长度,用于open时候生成tag,默认12key := []byte(hex_key)add := []byte(hex_add)block, err := aes.NewCipher(key) //生成加解密用的blockif err != nil {return []byte(""), err}//根据不同加密算法,也有不同tag长度的方法设定和调用,比如NewGCMWithTagSize、newGCMWithNonceAndTagSizeaesgcm, err := cipher.NewGCMWithNonceSize(block, tagSize)if err != nil {return []byte(""), err}decodeEncryptStr := UrlSafeB64decode(encryptData)ciphertext := decodeEncryptStrif len(ciphertext) <= aesgcm.NonceSize() { // 长度应该>ivreturn []byte(""), errors.New("string: too short") //解密失败}iv := ciphertext[:aesgcm.NonceSize()]        //分离出IVciphertext = ciphertext[aesgcm.NonceSize():] // 密文,tag是调用open方法时候通过密文和前面new时候传的size来进行截取的plaintext, err := aesgcm.Open(nil, iv, ciphertext, add)return plaintext, err}//使用aes-256-gcm加密数据,主要针对php的openssl_encrypt()方法,注意在php7.1后增加了tag和add参数func EncodeAesGcm(data string, hex_key string, hex_add string) (result string, error error) {tagSize :=16 //nonceSize,tag的长度,用于open时候生成tag,默认12key := []byte(hex_key)add := []byte(hex_add)block, err := aes.NewCipher(key) //生成加解密用的blockif err != nil {return result, err}//根据不同加密算法,也有不同tag长度的方法设定和调用,比如NewGCMWithTagSize、newGCMWithNonceAndTagSizeaesgcm, err := cipher.NewGCMWithNonceSize(block, tagSize)if err != nil {return result, err}plaintext := []byte(data)iv := make([]byte, tagSize)            // NonceSize=12rand.Read(iv)         //获取随机值ciphertext := aesgcm.Seal(iv, iv, plaintext, add) //加密,密文为:iv+密文+tagresult = base64.StdEncoding.EncodeToString(ciphertext)result = UrlSafeB64encode(result)return result, nil // 生成的BS64}

来源地址:https://blog.csdn.net/yjr_aaron/article/details/126015480

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯