diff --git a/encoding.go b/encoding.go index 4e69a92..8bcba1f 100644 --- a/encoding.go +++ b/encoding.go @@ -1,9 +1,19 @@ package goutil import ( + "bytes" + "compress/gzip" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/base64" "encoding/json" "encoding/xml" + "errors" + "io" "unicode" + + "github.com/speps/go-hashids" ) // EncodeJSON encode anything to json string @@ -38,3 +48,98 @@ func HasChinese(str string) bool { } return false } + +func EncryptID(data int64, salt string) string { + hd := hashids.NewData() + hd.Salt = salt + h, _ := hashids.NewWithData(hd) + e, _ := h.Encode([]int{int(data)}) + return e +} + +func DecryptID(data, salt string) int64 { + hd := hashids.NewData() + hd.Salt = salt + h, _ := hashids.NewWithData(hd) + e, _ := h.DecodeWithError(data) + return int64(e[0]) +} + +// 先压缩再加密(适合长文本) +func Encrypt(plaintext string, key string) (string, error) { + // 1. 压缩 + var buf bytes.Buffer + gz := gzip.NewWriter(&buf) + if _, err := gz.Write([]byte(plaintext)); err != nil { + return "", err + } + if err := gz.Close(); err != nil { + return "", err + } + compressed := buf.Bytes() + + // 2. 加密(使用AES-GCM) + block, err := aes.NewCipher([]byte(Md5(key))) + if err != nil { + return "", err + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return "", err + } + + nonce := make([]byte, gcm.NonceSize()) + if _, err := io.ReadFull(rand.Reader, nonce); err != nil { + return "", err + } + + ciphertext := gcm.Seal(nonce, nonce, compressed, nil) + + // 使用RawURLEncoding + return base64.RawURLEncoding.EncodeToString(ciphertext), nil +} + +func Decrypt(encoded string, key string) (string, error) { + data, err := base64.RawURLEncoding.DecodeString(encoded) + if err != nil { + return "", err + } + + block, err := aes.NewCipher([]byte(Md5(key))) + if err != nil { + return "", err + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return "", err + } + + nonceSize := gcm.NonceSize() + if len(data) < nonceSize { + return "", errors.New("数据太短") + } + + nonce := data[:nonceSize] + ciphertext := data[nonceSize:] + + compressed, err := gcm.Open(nil, nonce, ciphertext, nil) + if err != nil { + return "", err + } + + // 解压缩 + reader, err := gzip.NewReader(bytes.NewReader(compressed)) + if err != nil { + return "", err + } + defer reader.Close() + + result, err := io.ReadAll(reader) + if err != nil { + return "", err + } + + return string(result), nil +} diff --git a/number.go b/number.go index 1df40aa..d7d0554 100644 --- a/number.go +++ b/number.go @@ -2,7 +2,6 @@ package goutil import ( "crypto/md5" - "github.com/speps/go-hashids" "sync" "sync/atomic" "time" @@ -69,19 +68,3 @@ func Hash32(s string) uint32 { } return digest } - -func EncryptID(data int64, salt string) string { - hd := hashids.NewData() - hd.Salt = salt - h, _ := hashids.NewWithData(hd) - e, _ := h.Encode([]int{int(data)}) - return e -} - -func DecryptID(data, salt string) int64 { - hd := hashids.NewData() - hd.Salt = salt - h, _ := hashids.NewWithData(hd) - e, _ := h.DecodeWithError(data) - return int64(e[0]) -}