756 lines
19 KiB
Go
756 lines
19 KiB
Go
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
|
|
}
|