package crypt import ( "bytes" "crypto/aes" "crypto/cipher" "crypto/hmac" "crypto/md5" "crypto/rand" "crypto/sha1" "crypto/sha256" "encoding/base64" "encoding/hex" "encoding/json" "errors" "fmt" "hash/crc32" "io" "net/url" "os" "reflect" "sort" "strconv" "strings" "91porn-server/common/crypt/ecb" sli "91porn-server/common/slice" "github.com/dgrijalva/jwt-go" ) // CreateToken 生成Token算法 func CreateToken(secret string, tokenClaims map[string]interface{}) (tokeness string, err error) { if secret == "" { return "", errors.New("secret is empty") } claims := jwt.MapClaims(tokenClaims) token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString([]byte(secret)) } func keyFunc(secret string) jwt.Keyfunc { return func(token *jwt.Token) (interface{}, error) { return []byte(secret), nil } } // ParseToken 解析Token func ParseToken(secret string, tokeness string) (map[string]interface{}, error) { if secret == "" || tokeness == "" { return nil, errors.New("secret or tokeness is empty") } token, err := jwt.Parse(tokeness, keyFunc(secret)) if err != nil { return nil, err } //验证token,如果token被修改过则为false if !token.Valid { return nil, errors.New("token is invalid") } claimsToken, ok := token.Claims.(jwt.MapClaims) if !ok { return nil, errors.New("cannot convert claim to MapClaim") } return claimsToken, nil } // StructToStr 结构体转json 先对结构体按照字典顺序排序 并返回字符串 func StructToStr(obj interface{}) (string, error) { if obj == nil { return "", errors.New("obj is not nil") } data := make(map[string]interface{}) bytes, err := json.Marshal(obj) if err != nil { return "", err } if err = json.Unmarshal(bytes, &data); err != nil { return "", err } return MapToStr(data) } func JsonStr2Str(str string, key ...string) string { if str == "" { return "" } mapstr, err := JSON2Map(str) if err != nil { return "" } sortStr, err := MapToStrSkipObject(mapstr, key...) if err != nil { return "" } return sortStr } func Obj2Obj(src, dest interface{}) error { data, err := json.Marshal(src) if err != nil { return err } return json.Unmarshal(data, dest) } // MapToStr 对map按照字典顺序排序 并返回字符串 func MapToStr(data map[string]interface{}) (string, error) { if len(data) == 0 { return "", errors.New("data is nil or empty") } newData := make(map[string]interface{}) keys := make([]string, 0, len(data)) for k := range data { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { newData[k] = data[k] } b, err := json.Marshal(newData) if err != nil { return "", err } return string(b), nil } // MapToStr 对map按照字典顺序排序 并返回字符串 对value是对象 map list 类型的key 过滤掉 func MapToStrSkipObject(data map[string]interface{}, key ...string) (string, error) { if len(data) == 0 { return "", errors.New("data is nil or empty") } newData := make(map[string]interface{}) keys := make([]string, 0, len(data)) for k := range data { if sli.Contains(key, k) { continue } t := reflect.TypeOf(data[k]) if t != nil { tkind := t.Kind() if tkind == reflect.Map || tkind == reflect.Slice || tkind == reflect.Array || tkind == reflect.Struct { continue } keys = append(keys, k) } } sort.Strings(keys) for _, k := range keys { newData[k] = data[k] } b, err := json.Marshal(newData) if err != nil { return "", err } return string(b), nil } // JSON2Struct json转struct func JSON2Struct(str string, obj interface{}) error { return json.Unmarshal([]byte(str), &obj) } // JSONArray2Struct json转struct func JSONArray2Struct(str []string, obj interface{}) []interface{} { data := make([]interface{}, len(str)) for i, v := range str { _ = JSON2Struct(v, &obj) data[i] = obj } return data } // JSON2Map json转map func JSON2Map(str string) (map[string]interface{}, error) { var mapResult map[string]interface{} return mapResult, json.Unmarshal([]byte(str), &mapResult) } // StructToStrNormal 结构体转str func StructToStrNormal(obj interface{}) (string, error) { str, err := json.Marshal(obj) if err != nil { return "", err } return string(str), nil } func UrlValueToStr(values url.Values, exclude string) (string, string) { if values == nil { return "", "" } var buf bytes.Buffer var sign string keys := make([]string, 0, len(values)) for k := range values { if k == exclude { sign = strings.Join(values[k], "") continue } keys = append(keys, k) } sort.Strings(keys) for i, k := range keys { if i != 0 { buf.WriteString("&") } buf.WriteString(k) buf.WriteString("=") buf.WriteString(strings.Join(values[k], "")) } return buf.String(), sign } // 对参数进行排序后 拼接成url字符串 只对一级字符串类型的参数做处理 func MapToUrlOnlyStr(data map[string]interface{}) string { if len(data) == 0 { return "" } var buf bytes.Buffer keys := make([]string, len(data)) i := 0 for k := range data { keys[i] = k i++ } sort.Strings(keys) for i, k := range keys { if i != 0 { buf.WriteString("&") } buf.WriteString(k) buf.WriteString("=") if v, ok := data[k].(string); ok { buf.WriteString(v) } } return buf.String() } // MapToStr 对map按照字典顺序排序 并返回字符串url 拼接的字段 func MapToUrlStr(data map[string]interface{}) string { if len(data) == 0 { return "" } var buf bytes.Buffer keys := make([]string, len(data)) i := 0 for k := range data { keys[i] = k i++ } sort.Strings(keys) for i, k := range keys { if i != 0 { buf.WriteString("&") } buf.WriteString(k) buf.WriteString("=") if v, ok := data[k].(string); ok { buf.WriteString(v) continue } t := reflect.TypeOf(data[k]) if t != nil && t.Kind() == reflect.Map { if v, ok := data[k].(map[string]interface{}); ok { buf.WriteString("{") str := MapToUrlStr(v) buf.WriteString(str) buf.WriteString("}") } } if t != nil && (t.Kind() == reflect.Slice || t.Kind() == reflect.Array) { arraybyte, _ := json.Marshal(data[k]) buf.WriteString(string(arraybyte)) } } return buf.String() } // MapToURL 集合转URL func MapToURL(m map[string]string) string { if len(m) == 0 { return "" } v := url.Values{} for k := range m { v.Set(k, string(m[k])) } return v.Encode() } func Strcut2UrlValue(obj interface{}) (string, error) { t := reflect.TypeOf(obj) v := reflect.ValueOf(obj) if t.Kind() != reflect.Struct { return "", errors.New("obj must be struct type") } u := url.Values{} for i := 0; i < t.NumField(); i++ { var value string tag := t.Field(i).Tag.Get("json") switch t.Field(i).Type.Kind() { case reflect.String: value = v.Field(i).String() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: value = strconv.Itoa(int(v.Field(i).Int())) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: value = strconv.FormatUint(v.Field(i).Uint(), 10) case reflect.Slice, reflect.Array: buf := bytes.Buffer{} b, _ := json.Marshal(v.Field(i).Interface()) t := strings.TrimRight(strings.TrimLeft(string(b), "["), "]") array := strings.Split(t, ",") if len(array) == 0 { value = "" } if len(array) == 1 { value = array[0] } else { for i, v := range array { if i == 0 { buf.WriteString(v) continue } buf.WriteString("&") buf.WriteString(tag) buf.WriteString("=") buf.WriteString(v) value = buf.String() } } } u.Add(tag, value) } dcodeurl, err := url.QueryUnescape(u.Encode()) return dcodeurl, err } // StrToMd5 字符串转md5 func StrToMd5(str string) string { data := []byte(str) return ByteToMd5(data) } // ByteToMd5 数组转md5 func ByteToMd5(data []byte) string { md5Ctx := md5.New() md5Ctx.Write(data) cipherStr := md5Ctx.Sum(nil) return hex.EncodeToString(cipherStr) } // FileToMd5 文件转MD5 func FileToMd5(fileName string) string { file, err := os.Open(fileName) if err != nil { return "" } //defer file.Close() md5Ctx := md5.New() if _, err := io.Copy(md5Ctx, file); err != nil { return "" } cipherStr := md5Ctx.Sum(nil) return hex.EncodeToString(cipherStr) } // HashCode 对一个字符串生成唯一的hasHcode 码 func HashCode(src string) int { v := int(crc32.ChecksumIEEE([]byte(src))) if v < 0 { return -v } return v } // HexToString converts func HexToString(data []byte) string { return hex.EncodeToString(data) } // StrToSha256 字符串转sha256 func StrToSha256(str string) string { shaCtx := sha256.New() shaCtx.Write([]byte(str)) shaBytes := shaCtx.Sum(nil) cipherStr := hex.EncodeToString(shaBytes[:]) return cipherStr } // StrToSha1 字符串转sha1 func StrToSha1(str string, secret string) []byte { h := hmac.New(sha1.New, []byte(secret)) h.Write([]byte(str)) return h.Sum(nil) } // StrToSha1 字符串转sha1 转16进制后 func StrToHmacSha1(str, secret string) string { return hex.EncodeToString(StrToSha1(str, secret)) } // StrToHmacSha256 加密 字符串转sha256加密字符串 func StrToHmacSha256(str string, secret string) string { h := hmac.New(sha256.New, []byte(secret)) h.Write([]byte(str)) cipherStr := hex.EncodeToString(h.Sum(nil)) return cipherStr } func PKCS7Padding(ciphertext []byte, blockSize int) []byte { padding := blockSize - len(ciphertext)%blockSize padtext := bytes.Repeat([]byte{byte(padding)}, padding) return append(ciphertext, padtext...) } func PKCS7UnPadding(origData []byte) []byte { length := len(origData) unpadding := int(origData[length-1]) return origData[:(length - unpadding)] } // AesEncrypt AES加密 func AesEncrypt(origData, key string) ([]byte, error) { origDataByte := []byte(origData) return CoreAesEncrypt(origDataByte, key) } // AesDecrypt AES解密 func AesDecrypt(crypted, key string) (string, error) { cryptedByte := []byte(crypted) return CoreAesDecrypt(cryptedByte, key) } // CoreAesEncrypt AES加密 func CoreAesEncrypt(origData []byte, key string) ([]byte, error) { keybyte := []byte(key) block, err := aes.NewCipher(keybyte) if err != nil { return nil, err } blockSize := block.BlockSize() origData = PKCS7Padding(origData, blockSize) blockMode := cipher.NewCBCEncrypter(block, keybyte[:blockSize]) crypted := make([]byte, len(origData)) blockMode.CryptBlocks(crypted, origData) return crypted, nil } // https://core.telegram.org/api/end-to-end#sending-and-receiving-messages-in-a-secret-chat func CoreAesEncryptEx(plain []byte, nonceLen int, key string) ([]byte, error) { nonce := make([]byte, nonceLen) _, err := io.ReadFull(rand.Reader, nonce) if err != nil { return nil, err } var largeShaRaw []byte largeShaRaw = append(largeShaRaw, []byte(key)...) largeShaRaw = append(largeShaRaw, nonce...) largeShaRawMid := len(largeShaRaw) / 2 msgKeyLarge := sha256.Sum256(largeShaRaw) msgKey := msgKeyLarge[8:24] //16 bytes var shaRawA []byte shaRawA = append(shaRawA, msgKey...) shaRawA = append(shaRawA, largeShaRaw[:largeShaRawMid]...) sha256a := sha256.Sum256(shaRawA) //32 bytes var shaRawB []byte shaRawB = append(shaRawB, largeShaRaw[largeShaRawMid:]...) shaRawB = append(shaRawB, msgKey...) sha256b := sha256.Sum256(shaRawB) //32 bytes var aesKey []byte //32 bytes AES-256 aesKey = append(aesKey, sha256a[:8]...) //a: 8 bytes aesKey = append(aesKey, sha256b[8:24]...) //b: 16 bytes aesKey = append(aesKey, sha256a[24:32]...) //a: 8 bytes var aesIV []byte // 16 bytes aesIV = append(aesIV, sha256b[:4]...) //b: 4 bytes aesIV = append(aesIV, sha256a[12:20]...) //a: 8 bytes aesIV = append(aesIV, sha256b[28:]...) //b: 4 bytes block, err := aes.NewCipher(aesKey) if err != nil { return nil, err } blockSize := block.BlockSize() ciphertext := PKCS7Padding(plain, blockSize) mode := cipher.NewCBCEncrypter(block, aesIV) cipher := make([]byte, nonceLen+len(ciphertext)) copy(cipher, nonce) mode.CryptBlocks(cipher[nonceLen:], ciphertext) return cipher, nil } // CoreAesDecryptEx 是 CoreAesEncryptEx 的逆运算。 // 入参 crypt 前 nonceLen 字节为随机 nonce,其余为 CBC 密文;密钥派生与加密端完全一致。 // 由于 crypt 可能来自不可信输入(如客户端伪造的票据),这里对长度和分组边界做了保护,避免切片或 CBC 解密 panic。 func CoreAesDecryptEx(crypt []byte, nonceLen int, key string) ([]byte, error) { if nonceLen < 0 || len(crypt) < nonceLen { return nil, errors.New("CoreAesDecryptEx: ciphertext shorter than nonce") } nonce := make([]byte, nonceLen) copy(nonce, crypt) var largeShaRaw []byte largeShaRaw = append(largeShaRaw, []byte(key)...) largeShaRaw = append(largeShaRaw, nonce...) largeShaRawMid := len(largeShaRaw) / 2 msgKeyLarge := sha256.Sum256(largeShaRaw) msgKey := msgKeyLarge[8:24] //16 bytes var shaRawA []byte shaRawA = append(shaRawA, msgKey...) shaRawA = append(shaRawA, largeShaRaw[:largeShaRawMid]...) sha256a := sha256.Sum256(shaRawA) //32 bytes var shaRawB []byte shaRawB = append(shaRawB, largeShaRaw[largeShaRawMid:]...) shaRawB = append(shaRawB, msgKey...) sha256b := sha256.Sum256(shaRawB) //32 bytes var aesKey []byte //32 bytes AES-256 aesKey = append(aesKey, sha256a[:8]...) //a: 8 bytes aesKey = append(aesKey, sha256b[8:24]...) //b: 16 bytes aesKey = append(aesKey, sha256a[24:32]...) //a: 8 bytes var aesIV []byte // 16 bytes aesIV = append(aesIV, sha256b[:4]...) //b: 4 bytes aesIV = append(aesIV, sha256a[12:20]...) //a: 8 bytes aesIV = append(aesIV, sha256b[28:]...) //b: 4 bytes block, err := aes.NewCipher(aesKey) if err != nil { return nil, err } realData := crypt[nonceLen:] blockSize := block.BlockSize() if len(realData) == 0 || len(realData)%blockSize != 0 { return nil, errors.New("CoreAesDecryptEx: ciphertext is not a multiple of block size") } blockMode := cipher.NewCBCDecrypter(block, aesIV) origData := make([]byte, len(realData)) blockMode.CryptBlocks(origData, realData) // 用带校验的 PKCS7 去填充:错误密钥/损坏数据几乎必然产生非法填充,这里返回错误而非 panic, // 也顺带充当一次完整性校验(共享的 PKCS7UnPadding 在非法填充时会越界 panic,故不复用)。 return pkcs7UnpadSafe(origData, blockSize) } // pkcs7UnpadSafe 校验并剥离 PKCS7 填充,非法填充返回错误而不 panic。 func pkcs7UnpadSafe(data []byte, blockSize int) ([]byte, error) { length := len(data) if length == 0 || length%blockSize != 0 { return nil, errors.New("invalid PKCS7 padding: bad length") } pad := int(data[length-1]) if pad <= 0 || pad > blockSize || pad > length { return nil, errors.New("invalid PKCS7 padding: bad size") } for _, b := range data[length-pad:] { if int(b) != pad { return nil, errors.New("invalid PKCS7 padding: inconsistent bytes") } } return data[:length-pad], nil } // CoreAesDecrypt AES解密 func CoreAesDecrypt(crypted []byte, key string) (s string, err error) { defer func() { if r := recover(); r != nil { err = fmt.Errorf("CoreAesDecrypt is panic. crypted:%s,key:%s", string(crypted), key) return } }() keybyte := []byte(key) block, err := aes.NewCipher(keybyte) if err != nil { return "", err } blockSize := block.BlockSize() if blockSize < 0 { return "", errors.New("blockSize less than zero") } blockMode := cipher.NewCBCDecrypter(block, keybyte[:blockSize]) origData := make([]byte, len(crypted)) blockMode.CryptBlocks(origData, crypted) origData = PKCS7UnPadding(origData) return string(origData), nil } // XorEnc func XorEnc(src string, xorKey string) string { var result string j := 0 bt := []rune(src) xor := []rune(xorKey) for i := 0; i < len(bt); i++ { s := strconv.FormatInt(int64(bt[i]^xor[j]), 10) result = result + s j = 1 % len(xor) } return result } // XorDec func XorDec(src string, xorKey string) string { var result string j := 0 bt := []rune(src) xor := []rune(xorKey) for i := 0; i < len(bt); i++ { s := strconv.FormatInt(int64(bt[i]^xor[j]), 10) result = result + s j = i % len(xor) } return result } func XorDecode(src, key string) string { srcByte, _ := base64.StdEncoding.DecodeString(src) keyByte, _ := base64.StdEncoding.DecodeString(key) srcByte = xor(srcByte, keyByte) return base64.StdEncoding.EncodeToString(srcByte) } func XorEncode(src, key string) string { return XorDecode(src, key) } func xor(src []byte, key []byte) []byte { for i := 0; i < len(src); i++ { src[i] ^= key[i%len(key)] } return src } func XORLength(src []byte, key []byte, length int) []byte { for i := 0; i < length; i++ { src[i] ^= key[i%len(key)] } return src[:length] } // ECB PKCS5 加密 func AESECBEncrypt(src, key []byte) []byte { block, err := aes.NewCipher(key) if err != nil { fmt.Printf("txn put fail: %v", err) return nil } ecbMod := ecb.NewECBEncrypter(block) content := PKCS5Padding(src, block.BlockSize()) des := make([]byte, len(content)) ecbMod.CryptBlocks(des, content) return des } // ECB PKCS5 解密 func AESECBDecrypt(encrypted, key []byte) []byte { block, err := aes.NewCipher(key) if err != nil { fmt.Printf("decrypt fail: %v", err) return nil } ecbMod := ecb.NewECBDecrypter(block) des := make([]byte, len(encrypted)) ecbMod.CryptBlocks(des, encrypted) // 去除 PKCS5 填充 result := PKCS5UnPadding(des) return result } // PKCS5UnPadding func PKCS5UnPadding(origData []byte) []byte { length := len(origData) // 去掉最后一个字节 unpadding 次 unpadding := int(origData[length-1]) if unpadding > length { return origData } return origData[:(length - unpadding)] } // PKCS5Padding func PKCS5Padding(ciphertext []byte, blockSize int) []byte { padding := blockSize - len(ciphertext)%blockSize padtext := bytes.Repeat([]byte{byte(padding)}, padding) return append(ciphertext, padtext...) } // 加密 func AESCBCPck5Encrypt(origData, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } blockSize := block.BlockSize() origData = PKCS5Padding(origData, blockSize) blockMode := cipher.NewCBCEncrypter(block, key[:blockSize]) crypted := make([]byte, len(origData)) blockMode.CryptBlocks(crypted, origData) return crypted, nil } // base64补全 func padding(origin string) string { missing := len(origin) % 4 if missing != 0 { origin += strings.Repeat("=", 4-missing) } return origin } // AdDecrypt 集团广告中心-广告数据解密专用 func AdDecrypt(encryptedData, keyBase64 string) (res string, err error) { // 1. Base64 解码获取密钥 keyBytes, err := base64.StdEncoding.DecodeString(padding(keyBase64)) if err != nil { return "", fmt.Errorf("密钥 Base64 解码失败: %v", err) } // 2. Base64 解码获取加密数据 data, err := base64.StdEncoding.DecodeString(padding(encryptedData)) if err != nil { return "", fmt.Errorf("数据 Base64 解码失败: %v", err) } // 3. 拆分 IV 与密文(前 12 字节为 IV) if len(data) < 12 { return "", errors.New("数据长度不足,无法提取 IV") } iv := data[:12] ciphertext := data[12:] // 4. 初始化 AES 密码块 block, err := aes.NewCipher(keyBytes) if err != nil { return "", fmt.Errorf("创建 AES 密码块失败: %v", err) } // 5. 采用 GCM 模式 aesGCM, err := cipher.NewGCM(block) if err != nil { return "", fmt.Errorf("创建 GCM 失败: %v", err) } // 6. 解密数据 plainText, err := aesGCM.Open(nil, iv, ciphertext, nil) if err != nil { return "", fmt.Errorf("解密失败: %v", err) } return string(plainText), nil }