go - 在 Golang 中双击加密

标签 go

文档:https://developers.google.com/ad-exchange/rtb/response-guide/decrypt-price#sample_code

golang中没有官方的“Double Click Crypto”示例代码,所以我尝试自己实现。但是我无法通过doc中的测试。请帮助我!

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)
}

测试结果:

--- FAIL: TestEncryptPrice (0.00s)
        Error Trace:    price_test.go:19
    Error:          Not equal:
                    expected: "WEp8wQAAAABnFd5EkB2k1wJeFcAj-Z_JVOeGzA"
                    actual: "WEp8wQAAAABnFd5EkB2k1wf7jAcG7gZ9tPUnAA"
--- FAIL: TestDecryptPrice (0.00s)
        Error Trace:    price_test.go:32
    Error:          Expected nil, but got: &errors.errorString{s:"sinature mismatch: confSignature = \xbe\xaa\xf6h, sinature = T\xe7\x86\xcc"}
        Error Trace:    price_test.go:33
    Error:          Not equal:
                    expected: 0x64
                    actual: 0x0
FAIL

最佳答案

这段代码可以通过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 解密。

关于go - 在 Golang 中双击加密,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47332451/

相关文章:

javascript - 如何从等式到使用 javascript 进行编码

memory-management - Golang 中 []byte 和 string 转换的技术问题

go - 增加的秒数不打印

go - 如何分析 Golang Web 应用服务器

go - 如何并发遍历 Golang 中的 sql 结果集?

docker - 启动容器进程导致 “exec:\”转到\“: executable file not found in $PATH”:未知

date - Golang 日期解析故障

Golang : How to recover a string(int64)?

go - Go中一对圆括号语法表达式是什么意思?

Golang Stop Worker 但等待缓冲 channel 为空