🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 方法一: ``` func main() { u, err := util.NewKSOAdPriceUtil() if err != nil { panic(err) } // 加密 如果要加密12元,则调用时使用12 * 1e8 enc, err := u.Encrypt(12 * 1e8) fmt.Println(enc, err) // 解密, 同理解出来的单位也是微元,转成元除以 1e8 即可 dec, err := u.Decriypt("MTYyOTE2NTU1MzYzNTE2NegbqJayGuXSB85OzQ") fmt.Println(dec, err) } ``` #### Golang版本DoubleClick算法实现 ``` package util import ( "bytes" "crypto/hmac" "crypto/sha1" "encoding/base64" "encoding/binary" "errors" "fmt" "time" ) type KSOAdxPriceUtil struct { encryptionKey []byte integrityKey []byte encoder *base64.Encoding } func NewKSOAdPriceUtil() (*KSOAdxPriceUtil, error) { u := &KSOAdxPriceUtil{} u.encoder = base64.URLEncoding var err error if u.encryptionKey, err = u.genKey([]byte(u.encoder.EncodeToString([]byte("kingsoft")))); err != nil { return nil, err } if u.integrityKey, err = u.genKey([]byte(u.encoder.EncodeToString([]byte("adx")))); err != nil { return nil, err } return u, nil } func (s *KSOAdxPriceUtil) Encrypt(price uint64) (string, error) { iv := []byte(fmt.Sprintf("%d", time.Now().UnixNano()/1000)) if len(s.integrityKey) == 0 || len(s.encryptionKey) == 0 { return "", errors.New("bad integrityKey or encryptionKey") } if len(iv) != 16 { return "", errors.New("bad iv") } h := hmac.New(sha1.New, s.encryptionKey) h.Write(iv) pad := h.Sum(nil)[:8] p := make([]byte, 8) binary.BigEndian.PutUint64(p, price) encPrice := s.safeXORBytes(pad, p) h = hmac.New(sha1.New, s.integrityKey) h.Write(p) h.Write(iv) sig := h.Sum(nil)[:4] b := make([]byte, 0, len(iv)+len(encPrice)+len(sig)) buf := bytes.NewBuffer(b) buf.Write(iv) buf.Write(encPrice) buf.Write(sig) n := base64.RawURLEncoding.EncodedLen(len(buf.Bytes())) ret := make([]byte, n, n) base64.RawURLEncoding.Encode(ret, buf.Bytes()) return string(ret), nil } func (s *KSOAdxPriceUtil) Decriypt(encPriceStr string) (uint64, error) { if len(s.integrityKey) == 0 || len(s.encryptionKey) == 0 { return 0, errors.New("encryption and integrity keys are required") } encPrice := []byte(encPriceStr) if len(encPrice) != 38 { return 0, fmt.Errorf("invalid price: invalid length, expected 38 got %d", len(encPrice)) } dprice := make([]byte, base64.RawURLEncoding.DecodedLen(len(encPrice))) n, err := base64.RawURLEncoding.Decode(dprice, encPrice) if err != nil { return 0, fmt.Errorf("invalid base64 string: %s", err.Error()) } dprice = dprice[:n] if len(dprice) != 28 { return 0, fmt.Errorf("invalid decoded price length. Expected 28 got %d", len(dprice)) } iv, p, sig := dprice[0:16], dprice[16:24], dprice[24:] h := hmac.New(sha1.New, s.encryptionKey) n, err = h.Write(iv) if err != nil || n != len(iv) { return 0, fmt.Errorf("could not write hmac hash for iv. err:%s, n:%d, len(iv):%d", err, n, len(iv)) } pricePad := h.Sum(nil) price := s.safeXORBytes(p, pricePad) if price == nil { return 0, fmt.Errorf("price xor price_pad failed") } h = hmac.New(sha1.New, s.integrityKey) n, err = h.Write(price) if err != nil || n != len(price) { return 0, fmt.Errorf("could not write hmac hash for price. err:%s, n:%d, len(price):%d", err, n, len(price)) } n, err = h.Write(iv) if err != nil || n != len(iv) { return 0, fmt.Errorf("could not write hmac hash for iv. err:%s, n:%d, len(iv):%d", err, n, len(iv)) } confSig := h.Sum(nil)[:4] if bytes.Compare(confSig, sig) != 0 { return 0, fmt.Errorf("integrity of price is not valid") } return binary.BigEndian.Uint64(price), nil } func (s *KSOAdxPriceUtil) genKey(target []byte) ([]byte, error) { icKey := make([]byte, s.encoder.DecodedLen(len([]byte(target)))) n, err := s.encoder.Decode(icKey, []byte(target)) if err != nil { return nil, fmt.Errorf("invalid key:%s, err: %x", target, err) } return icKey[:n], nil } func (s *KSOAdxPriceUtil) safeXORBytes(a, b []byte) []byte { n := len(a) if len(b) < n { n = len(b) } if n == 0 { return nil } ret := make([]byte, n) for i := 0; i < n; i++ { ret[i] = a[i] ^ b[i] } return ret } ``` ## 方法二: ``` package main /* golang 实现 google 的rtb 价格加密方案 https://developers.google.com/authorized-buyers/rtb/response-guide/decrypt-price#encryption-scheme */ import ( "crypto/hmac" "crypto/md5" "crypto/sha1" "encoding/base64" "encoding/binary" "encoding/hex" "fmt" "hash" "math" "strings" ) const ( PayloadSize = 8 InitVectorSize = 16 SignatureSize = 4 EKey = "" IKey = "" UTF8 = "utf-8" ) func AddBase64Padding(base64Input string) string { var b64 string b64 = base64Input if i := len(b64) % 4; i != 0 { b64 += strings.Repeat("=", 4-i) } return b64 } func CreateHmac(key, mode string, isBase64 bool) (hash.Hash, error) { var b64DecodedKey []byte var k []byte var err error if isBase64 { b64DecodedKey, err = base64.URLEncoding.DecodeString(AddBase64Padding(key)) if err == nil { key = string(b64DecodedKey[:]) } } if mode == UTF8 { k = []byte(key) } else { k, err = hex.DecodeString(key) } if err != nil { return nil, err } return hmac.New(sha1.New, k), nil } func HmacSum(_hmac hash.Hash, buf []byte) []byte { _hmac.Reset() _hmac.Write(buf) return _hmac.Sum(nil) } func Hmac(key string, buf []byte) ([]byte, error) { _hmac, err := CreateHmac(key, UTF8, true) if err != nil { err = fmt.Errorf("jzt/encrypt: create hmac error, %s", err.Error()) return nil, err } return HmacSum(_hmac, buf), nil } func EncryptPrice(price float64) (string, error) { var ( iv = make([]byte, InitVectorSize) encoded = make([]byte, PayloadSize) signature = make([]byte, SignatureSize) priceBytes = make([]byte, PayloadSize) ) sum := md5.Sum([]byte("")) copy(iv[:], sum[:]) // pad = hmac(e_key, iv) // first 8 bytes pad, err := Hmac(EKey, iv[:]) if err != nil { return "", err } pad = pad[:PayloadSize] bits := math.Float64bits(price) binary.BigEndian.PutUint64(priceBytes, bits) // enc_price = pad <xor> price for i := range priceBytes { encoded[i] = pad[i] ^ priceBytes[i] } // signature = hmac(i_key, data || iv), first 4 bytes sig, err := Hmac(IKey, append(priceBytes[:], iv[:]...)) if err != nil { return "", err } signature = sig[:SignatureSize] // final_message = WebSafeBase64Encode( iv || enc_price || signature ) finalMessage := strings.TrimRight( base64.URLEncoding.EncodeToString(append(append(iv[:], encoded[:]...), signature[:]...)), "=") return finalMessage, nil } func DecryptPrice(finalMessage string) (float64, error) { var err error var errPrice float64 encryptedPrice := AddBase64Padding(finalMessage) decoded, err := base64.URLEncoding.DecodeString(encryptedPrice) if err != nil { return errPrice, err } var ( iv = make([]byte, InitVectorSize) p = make([]byte, PayloadSize) signature = make([]byte, SignatureSize) priceBytes = make([]byte, PayloadSize) ) copy(iv[:], decoded[0:16]) copy(p[:], decoded[16:24]) copy(signature[:], decoded[24:28]) pad, err := Hmac(EKey, iv[:]) if err != nil { return errPrice, err } pad = pad[:PayloadSize] for i := range p { priceBytes[i] = pad[i] ^ p[i] } sig, err := Hmac(IKey, append(priceBytes[:], iv[:]...)) if err != nil { return errPrice, err } sig = sig[:SignatureSize] for i := range sig { if sig[i] != signature[i] { return errPrice, fmt.Errorf("jzt/decrypt: Failed to decrypt, got:%s ,expect:%s", string(sig), string(signature)) } } price := math.Float64frombits(binary.BigEndian.Uint64(priceBytes)) return price, nil } func main() { var result string var err error var price float64 result, err = EncryptPrice(0.11) if err != nil { err = fmt.Errorf("Encryption failed. Error : %s", err) } fmt.Println(result) price, err = DecryptPrice("1B2M2Y8AsgTpgAmY7PhCfumh5TxN_8-DUn4uHg") if err != nil { err = fmt.Errorf("Encryption failed. Error : %s", err) } fmt.Println(price) } ```