doc:https://developers.google.com/ad-exchange/rtb/response-guide/decrypt-price#sample_code
没有官方" Double Click Crypto" golang中的示例代码,所以我尝试自己实现。但我无法通过doc测试。请帮帮我!
verLessThan
这是我的代码:
skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o= // Encryption key (e_key)
arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo= // Integrity key (i_key)
WEp8wQAAAABnFd5EkB2k1wJeFcAj-Z_JVOeGzA // 100 CPI micros
WEp8sQAAAACwF6CtLJrXSRFBM8UiTTIyngN-og // 1900 CPI micros
WEp8nQAAAAADG-y45xxIC1tMWuTjzmDW6HtroQ // 2700 CPI micros
package main
// https://developers.google.com/ad-exchange/rtb/response-guide/decrypt-price?hl=zh-CN
import (
"bytes"
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"encoding/binary"
"fmt"
)
var base64Codec = base64.URLEncoding.WithPadding(base64.NoPadding)
func safeXORBytes(dst, a, b []byte) int {
n := len(a)
if len(b) < n {
n = len(b)
}
for i := 0; i < n; i++ {
dst[i] = a[i] ^ b[i]
}
return n
}
func EncryptPrice(eKey []byte, iKey []byte, price uint64, iv []byte) (finalMessage string, err error) {
if len(iv) != 16 {
err = fmt.Errorf("len(iv) = %d != 16", len(iv))
return
}
h1 := hmac.New(sha1.New, eKey)
h1.Write(iv)
pad := h1.Sum(nil)[:8]
priceBytes := make([]byte, 8)
binary.BigEndian.PutUint64(priceBytes, price)
encPrice := make([]byte, 8)
n := safeXORBytes(encPrice, priceBytes, pad)
if n != 8 {
err = fmt.Errorf("safeXORBytes n != %d", n)
return
}
h2 := hmac.New(sha1.New, iKey)
h2.Write(priceBytes)
h2.Write(iv)
signature := h2.Sum(nil)[:4]
finalMessage = base64Codec.EncodeToString(append(append(iv, encPrice...), signature...))
return
}
func DecryptPrice(eKey []byte, iKey []byte, finalMessage string) (price uint64, err error) {
finalMessageBytes, err := base64Codec.DecodeString(finalMessage)
if err != nil {
return
}
if len(finalMessageBytes) != 28 {
err = fmt.Errorf("len(finalMessageBytes) = %d != 28", len(finalMessageBytes))
return
}
iv := finalMessageBytes[:16]
encPrice := finalMessageBytes[16:24]
signature := finalMessageBytes[24:]
h1 := hmac.New(sha1.New, eKey)
h1.Write(iv)
pad := h1.Sum(nil)[:8]
priceBytes := make([]byte, 8)
n := safeXORBytes(priceBytes, encPrice, pad)
if n != 8 {
err = fmt.Errorf("safeXORBytes n != %d", n)
return
}
h2 := hmac.New(sha1.New, iKey)
h2.Write(priceBytes)
h2.Write(iv)
confSignature := h2.Sum(nil)[:4]
if bytes.Compare(confSignature, signature) != 0 {
err = fmt.Errorf("sinature mismatch: confSignature = %s, sinature = %s", confSignature, signature)
return
}
price = binary.BigEndian.Uint64(priceBytes)
return
}
测试结果:
package main
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestEncryptPrice(t *testing.T) {
eKeyBase64Encoded := "skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o"
eKey, err := base64Codec.DecodeString(eKeyBase64Encoded)
assert.Nil(t, err)
iKeyBase64Encoded := "arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo"
iKey, err := base64Codec.DecodeString(iKeyBase64Encoded)
assert.Nil(t, err)
finalMessage, err := EncryptPrice(eKey, iKey, uint64(100), []byte{88, 74, 124, 193, 0, 0, 0, 0, 103, 21, 222, 68, 144, 29, 164, 215})
assert.Nil(t, err)
assert.Equal(t, "WEp8wQAAAABnFd5EkB2k1wJeFcAj-Z_JVOeGzA", finalMessage)
}
func TestDecryptPrice(t *testing.T) {
eKeyBase64Encoded := "skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o"
eKey, err := base64Codec.DecodeString(eKeyBase64Encoded)
assert.Nil(t, err)
iKeyBase64Encoded := "arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo"
iKey, err := base64Codec.DecodeString(iKeyBase64Encoded)
assert.Nil(t, err)
price, err := DecryptPrice(eKey, iKey, "WEp8wQAAAABnFd5EkB2k1wJeFcAj-Z_JVOeGzA")
assert.Nil(t, err)
assert.Equal(t, uint64(100), price)
}
答案 0 :(得分:0)
此代码可以通过https://github.com/google/openrtb-doubleclick/blob/0.9.0/doubleclick-core/src/test/java/com/google/doubleclick/crypto/DoubleClickCryptoTest.java中的测试 ,所以我想文档中的加密价格不会被文档中的e_key和i_key删除。
答案 1 :(得分:0)
我今天遇到了同样的问题。最后,我发现错误是“ ekey
”和“ ikey
”不需要base64Codec.DecodeString
,只需使用[] byte(eKeyBase64Encoded)。
eKeyBase64Encoded := "skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o"
eKey := []byte(eKeyBase64Encoded)
assert.Nil(t, err)
iKeyBase64Encoded := "arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo"
iKey :=[]byte(iKeyBase64Encoded)
assert.Nil(t, err)
price, err := DecryptPrice(eKey, iKey, "WEp8wQAAAABnFd5EkB2k1wJeFcAj-Z_JVOeGzA")
....
答案 2 :(得分:0)
此文档https://developers.google.com/authorized-buyers/rtb/response-guide/decrypt-price中列出的加密价格已使用它们在价格上方显示的密钥进行了编码。这些例子是正确的。我写了一个小的Go程序包,它提供了Decrypt功能,我可能很快会添加一个加密功能:https://github.com/matipan/doubleclick。下面我留下一个示例和代码片段,以方便访问。
首先,为了能够解析密钥,我们需要遵守网络安全的base64解码,这意味着我们需要使用base64.URLEncoding!解码密钥:
// ParseKeys parses the base64 web-safe encoded keys as explained in Google's documentation:
// https://developers.google.com/authorized-buyers/rtb/response-guide/decrypt-price
func ParseKeys(ic, ec []byte) (icKey []byte, ecKey []byte, err error) {
icKey = make([]byte, base64.URLEncoding.DecodedLen(len([]byte(ic))))
n, err := base64.URLEncoding.Decode(icKey, []byte(ic))
if err != nil {
return nil, nil, fmt.Errorf("%w: could not decode price integrity key", err)
}
icKey = icKey[:n]
ecKey = make([]byte, base64.URLEncoding.DecodedLen(len([]byte(ec))))
n, err = base64.URLEncoding.Decode(ecKey, []byte(ec))
if err != nil {
return nil, nil, fmt.Errorf("%w: could not decode price encryption key", err)
}
ecKey = ecKey[:n]
return icKey, ecKey, nil
}
我们可以调用此代码并解密显示的密钥:
icKey, ecKey, err = ParseKeys([]byte("arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo="), []byte("skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o="))
具有更多错误处理功能的解密价格的功能是:
// ErrInvalidPrice is the error returned when the price parsed
// by DecryptPrice is not correct.
var ErrInvalidPrice = errors.New("price is invalid")
// DecryptPrice decrypts the price with google's doubleclick cryptography encoding.
// encPrice is an unpadded web-safe base64 encoded string according to RFC 3548.
// https://developers.google.com/authorized-buyers/rtb/response-guide/decrypt-price
func DecryptPrice(icKey, ecKey, encPrice []byte) (uint64, error) {
if len(icKey) == 0 || len(ecKey) == 0 {
return 0, errors.New("encryption and integrity keys are required")
}
if len(encPrice) != 38 {
return 0, fmt.Errorf("%w: invalid length, expected 28 got %d", ErrInvalidPrice, len(encPrice))
}
dprice := make([]byte, base64.RawURLEncoding.DecodedLen(len(encPrice)))
n, err := base64.RawURLEncoding.Decode(dprice, encPrice)
if err != nil {
return 0, fmt.Errorf("%w: invalid base64 string", err)
}
dprice = dprice[:n]
if len(dprice) != 28 {
return 0, fmt.Errorf("%w: invalid decoded price length. Expected 28 got %d", ErrInvalidPrice, len(dprice))
}
// encrypted price is composed of parts of fixed lenth. We break it up according to:
// {initialization_vector (16 bytes)}{encrypted_price (8 bytes)}{integrity (4 bytes)}
iv, p, sig := dprice[0:16], dprice[16:24], dprice[24:]
h := hmac.New(sha1.New, ecKey)
n, err = h.Write(iv)
if err != nil || n != len(iv) {
return 0, fmt.Errorf("%w: could not write hmac hash for iv. err=%s, n=%d, len(iv)=%d", ErrInvalidPrice, err, n, len(iv))
}
pricePad := h.Sum(nil)
price := safeXORBytes(p, pricePad)
if price == nil {
return 0, fmt.Errorf("%w: price xor price_pad failed", ErrInvalidPrice)
}
h = hmac.New(sha1.New, icKey)
n, err = h.Write(price)
if err != nil || n != len(price) {
return 0, fmt.Errorf("%w: could not write hmac hash for price. err=%s, n=%d, len(price)=%d", ErrInvalidPrice, err, n, len(price))
}
n, err = h.Write(iv)
if err != nil || n != len(iv) {
return 0, fmt.Errorf("%w: could not write hmac hash for iv. err=%s, n=%d, len(iv)=%d", ErrInvalidPrice, err, n, len(iv))
}
confSig := h.Sum(nil)[:4]
if bytes.Compare(confSig, sig) != 0 {
return 0, fmt.Errorf("%w: integrity of price is not valid", ErrInvalidPrice)
}
return binary.BigEndian.Uint64(price), nil
}
func safeXORBytes(a, b []byte) []byte {
n := len(a)
if len(b) < n {
n = len(b)
}
if n == 0 {
return nil
}
dst := make([]byte, n)
for i := 0; i < n; i++ {
dst[i] = a[i] ^ b[i]
}
return dst
}
我们现在可以使用1900微米的示例来调用此代码:YWJjMTIzZGVmNDU2Z2hpN7fhCuPemC32prpWWw
:
price, err := DecryptPrice(icKey, ecKey, []byte("YWJjMTIzZGVmNDU2Z2hpN7fhCuPemC32prpWWw"))
价格将为1900