123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- package comm
- import (
- "crypto/aes"
- "crypto/cipher"
- "crypto/rsa"
- "crypto/sha1"
- "crypto/sha256"
- "crypto/x509"
- "encoding/base64"
- "encoding/pem"
- "errors"
- "fmt"
- "hash"
- "io"
- "math"
- "crypto/rand"
- mrand "math/rand"
- "strconv"
- "strings"
- "time"
- )
- // 实现php的sha1()方法,返回的是byte转换的字符串,如果需要转成16进制,可以使用hex.EncodeToString
- func 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 - inputLen
- for i := 1; i <= ll; i = i + len(padString) {
- output += padString
- }
- return input + output
- }
- // url安全模式decode字符串
- func UrlSafeB64decode(str string) (result []byte) {
- str = strings.Replace(str, "-", "+", -1)
- str = strings.Replace(str, "_", "/", -1)
- mod4 := len(str) % 4
- if 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,默认12
- key := []byte(hex_key)
- add := []byte(hex_add)
- block, err := aes.NewCipher(key) //生成加解密用的block
- if err != nil {
- return []byte(""), err
- }
- //根据不同加密算法,也有不同tag长度的方法设定和调用,比如NewGCMWithTagSize、newGCMWithNonceAndTagSize
- aesgcm, err := cipher.NewGCMWithNonceSize(block, tagSize)
- if err != nil {
- return []byte(""), err
- }
- decodeEncryptStr := UrlSafeB64decode(encryptData)
- ciphertext := decodeEncryptStr
- if len(ciphertext) <= aesgcm.NonceSize() { // 长度应该>iv
- return []byte(""), errors.New("string: too short") //解密失败
- }
- iv := ciphertext[:aesgcm.NonceSize()] //分离出IV
- ciphertext = 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,默认12
- key := []byte(hex_key)
- add := []byte(hex_add)
- block, err := aes.NewCipher(key) //生成加解密用的block
- if err != nil {
- return result, err
- }
- //根据不同加密算法,也有不同tag长度的方法设定和调用,比如NewGCMWithTagSize、newGCMWithNonceAndTagSize
- aesgcm, err := cipher.NewGCMWithNonceSize(block, tagSize)
- if err != nil {
- return result, err
- }
- plaintext := []byte(data)
- iv := make([]byte, tagSize) // NonceSize=12
- rand.Read(iv) //获取随机值
- ciphertext := aesgcm.Seal(iv, iv, plaintext, add) //加密,密文为:iv+密文+tag
- result = base64.StdEncoding.EncodeToString(ciphertext)
- result = UrlSafeB64encode(result)
- return result, nil // 生成的BS64
- }
- func GenSecretKey(appId string, appSecret string) string {
- key := appId + "&" + appSecret
- sha1_str := GetSha1(key)
- str10 := "0"
- pack64, _ := strconv.ParseUint(str10, 10, 32) //对应php的pack()方法,字符串转换为uint类型
- pack32 := uint32(pack64)
- str_pad := StrPadRight(sha1_str, 32, fmt.Sprintf("%d", pack32))
- return base64.StdEncoding.EncodeToString([]byte(str_pad))
- }
- // 加密
- func Encode(secretKey string, data []byte) (string, error) {
- decodeSecretKeyByte, _ := base64.StdEncoding.DecodeString(secretKey)
- c, e := EncodeAesGcm(string(data), string(decodeSecretKeyByte), "")
- if e != nil {
- return "", e
- }
- return c, nil
- }
- // 加密
- func Decode(secretKey string, encryptData string) ([]byte, 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));
- p, e := DecodeAesGcm(encryptData, decodeSecretKey, "")
- if e != nil {
- return nil, e
- }
- return p, nil
- }
- func decryptOAEP(pritKey []byte, cipherdata []byte, label []byte) ([]byte, error) {
- block, _ := pem.Decode(pritKey)
- if block == nil {
- err := fmt.Errorf("failed to parse certificate PEM")
- return nil, err
- }
- priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) // ASN.1 PKCS#1 DER encoded form.
- if err != nil {
- return nil, err
- }
- h := sha256.New()
- return DecryptOAEPLong(h, rand.Reader, priv, cipherdata, label)
- }
- func EncryptOAEPLong(hash hash.Hash, random io.Reader, public *rsa.PublicKey, msg []byte, label []byte) ([]byte, error) {
- msgLen := len(msg)
- step := public.Size() - 2*hash.Size() - 2
- var encryptedBytes []byte
- for start := 0; start < msgLen; start += step {
- finish := start + step
- if finish > msgLen {
- finish = msgLen
- }
- encryptedBlockBytes, err := rsa.EncryptOAEP(hash, random, public, msg[start:finish], label)
- if err != nil {
- return nil, err
- }
- encryptedBytes = append(encryptedBytes, encryptedBlockBytes...)
- }
- return encryptedBytes, nil
- }
- func DecryptOAEPLong(hash hash.Hash, random io.Reader, private *rsa.PrivateKey, msg []byte, label []byte) ([]byte, error) {
- msgLen := len(msg)
- step := private.PublicKey.Size()
- var decryptedBytes []byte
- for start := 0; start < msgLen; start += step {
- finish := start + step
- if finish > msgLen {
- finish = msgLen
- }
- decryptedBlockBytes, err := rsa.DecryptOAEP(hash, random, private, msg[start:finish], label)
- if err != nil {
- return nil, err
- }
- decryptedBytes = append(decryptedBytes, decryptedBlockBytes...)
- }
- return decryptedBytes, nil
- }
- func encryptOAEP(pubkey []byte, msg []byte, label []byte) ([]byte, error) {
- block, _ := pem.Decode(pubkey)
- if block == nil {
- err := fmt.Errorf("failed to parse certificate PEM")
- return nil, err
- }
- pub, err := x509.ParsePKIXPublicKey(block.Bytes)
- if err != nil {
- return nil, err
- }
- rsaPublicKey := pub.(*rsa.PublicKey)
- h := sha256.New() // sha1.New() or md5.New()
- return EncryptOAEPLong(h, rand.Reader, rsaPublicKey, msg, label)
- }
- func radomInt() int32 {
- mrand.Seed(time.Now().UnixNano())
- return mrand.Int31n(math.MaxInt32)
- }
|