Mendekripsi Informasi Harga

Saat materi iklan Anda memenangkan lelang, Google dapat memberitahukan harga pemenang jika cuplikan HTML atau URL VAST yang menentukan materi iklan menyertakan makro WINNING_PRICE. Google menampilkan harga pemenang dalam bentuk terenkripsi. Topik berikut menjelaskan cara aplikasi Anda dapat mendekripsi informasi harga pemenang.

Makro WINNING_PRICE dapat disertakan dalam materi iklan, misalnya, dengan permintaan piksel tidak terlihat yang dirender sebagai bagian dari iklan:

<div>
  <script language='JavaScript1.1' src='https://example.com?creativeID=5837243'/>
  <img src='https://example.com/t.gif?price=%%WINNING_PRICE%%' width='1' height='1'/>
</div>

Makro WINNING_PRICE juga dapat disertakan dalam URL VAST materi iklan video (tetapi tidak dalam URL tayangan di VAST):

https://example.com/vast/v?price=%%WINNING_PRICE%%

Skenario

  1. Aplikasi Anda menyertakan makro WINNING_PRICE di cuplikan HTML atau URL VAST yang ditampilkan ke Google.
  2. Google mengganti harga yang unggul untuk makro dalam encoding base64 yang aman untuk web tanpa padding (RFC 3548).
  3. Cuplikan akan meneruskan konfirmasi dalam format yang telah Anda pilih. Misalnya, konfirmasi mungkin diteruskan di URL permintaan piksel tidak terlihat yang dirender sebagai bagian dari iklan.
  4. Di server, aplikasi Anda dalam base64 yang aman untuk web akan mendekode informasi harga pemenang dan mendekripsi hasilnya.

Dependensi

Anda akan memerlukan library kripto yang mendukung HMAC SHA-1, seperti Openssl.

Kode contoh

Kode contoh disediakan di Java dan C++ serta dapat didownload dari project privatedatacommunicationprotocol.

  • Kode contoh Java menggunakan decoder base64 dari project commons Apache. Anda tidak perlu mendownload kode Apache commons, karena implementasi referensi menyertakan bagian yang diperlukan sehingga bersifat mandiri.

  • Kode contoh C++ menggunakan metode BIO base64 OpenSSL. Diperlukan string berenkode base64 yang aman untuk web (RFC 3548) dan mendekodenya. Biasanya, string base64 yang aman untuk web menggantikan padding "=" dengan "." (perhatikan bahwa tanda kutip ditambahkan untuk kejelasan pembacaan dan tidak disertakan dalam protokol), tetapi penggantian makro tidak menambahkan harga yang dienkripsi. Implementasi referensi menambahkan padding karena OpenSSL mengalami masalah dengan string yang tidak diberi padding.

Encoding

Enkripsi dan dekripsi harga pemenang memerlukan dua kunci rahasia, tetapi dibagikan. Kunci integritas dan kunci enkripsi, masing-masing disebut sebagai i_key, dan e_key. Kedua kunci disediakan saat pembuatan akun sebagai string base64 yang aman untuk web, dan dapat ditemukan di halaman Authorized Buyers pada bagian Setelan bidder > Setelan RTB > Kunci enkripsi.

Contoh kunci integritas dan enkripsi:

skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o=  // Encryption key (e_key)
arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo=  // Integrity key (i_key)

Kunci harus didekode dengan aman untuk web, lalu didekode dalam base64 oleh aplikasi Anda:

e_key = WebSafeBase64Decode('skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o=')
i_key = WebSafeBase64Decode('arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo=')

Skema enkripsi

Harga dienkripsi menggunakan skema enkripsi kustom yang dirancang untuk meminimalkan overhead ukuran sekaligus memastikan keamanan yang memadai. Skema enkripsi ini menggunakan algoritma HMAC dengan kunci untuk membuat secret pad berdasarkan ID peristiwa tayangan yang unik.

Harga terenkripsi memiliki panjang tetap 28 byte. Kode ini terdiri dari vektor inisialisasi 16 byte, ciphertext 8 byte, dan tanda tangan integritas 4 byte. Harga yang dienkripsi dienkode menggunakan base64 yang aman untuk web, menurut RFC 3548, dengan karakter padding dihilangkan. Dengan demikian, harga terenkripsi 28 byte dienkode sebagai string base-64 yang aman untuk web dengan 38 karakter, terlepas dari harga unggul yang dibayarkan.

Contoh harga yang dienkripsi:

YWJjMTIzZGVmNDU2Z2hpN7fhCuPemCce_6msaw  // 100 CPI micros
YWJjMTIzZGVmNDU2Z2hpN7fhCuPemCAWJRxOgA  // 1900 CPI micros
YWJjMTIzZGVmNDU2Z2hpN7fhCuPemC32prpWWw  // 2700 CPI micros

Format yang dienkripsi adalah:

{initialization_vector (16 bytes)}{encrypted_price (8 bytes)}
{integrity (4 bytes)}

Harga dienkripsi sebagai <price xor HMAC(encryption_key, initialization_vector)> sehingga dekripsi menghitung HMAC(encryption_key,initialization_vector) dan xor dengan harga terenkripsi untuk membalikkan enkripsi. Tahap integritas memerlukan 4 byte <HMAC(integrity_key, price||initialization_vector)> dengan || adalah penyambungan.

Input
iv vektor inisialisasi (16 byte - unik untuk tayangan)
e_key kunci enkripsi (32 byte - disediakan saat penyiapan akun)
i_key kunci integritas (32 byte - disediakan saat penyiapan akun)
price (8 byte - dalam mikro mata uang akun)
Notasi
hmac(k, d) HMAC SHA-1 data d, menggunakan kunci k
a || b string a disambungkan dengan string b
Kode semu
pad = hmac(e_key, iv)  // first 8 bytes
enc_price = pad <xor> price
signature = hmac(i_key, price || iv)  // first 4 bytes

final_message = WebSafeBase64Encode( iv || enc_price || signature )

Skema dekripsi

Kode dekripsi Anda harus mendekripsi harga menggunakan kunci enkripsi, dan memverifikasi bit integritas dengan kunci integritas. Kunci akan diberikan kepada Anda selama penyiapan. Tidak ada batasan terkait detail cara Anda menyusun implementasi. Secara umum, Anda harus dapat mengambil kode contoh dan menyesuaikannya sesuai dengan kebutuhan.

Input
e_key kunci enkripsi, 32 byte - disediakan saat penyiapan akun
i_key kunci integritas, 32 byte - disediakan saat penyiapan akun
final_message 38 karakter yang dienkode dalam base64 yang aman untuk web
Kode semu
// Base64 padding characters are omitted.
// Add any required base64 padding (= or ==).
final_message_valid_base64 = AddBase64Padding(final_message)

// Web-safe decode, then base64 decode.
enc_price = WebSafeBase64Decode(final_message_valid_base64)

// Message is decoded but remains encrypted.
(iv, p, sig) = enc_price // Split up according to fixed lengths.
price_pad = hmac(e_key, iv)
price = p <xor> price_pad

conf_sig = hmac(i_key, price || iv)
success = (conf_sig == sig)

Mendeteksi serangan respons yang sudah tidak berlaku

Untuk mendeteksi serangan respons yang sudah tidak berlaku, atau replay, sebaiknya Anda memfilter respons dengan stempel waktu yang berbeda secara signifikan dari waktu sistem, setelah memperhitungkan perbedaan zona waktu.

Vektor inisialisasi berisi stempel waktu dalam 8 byte pertama. Tabel ini dapat dibaca oleh fungsi C++ berikut:

void GetTime(const char* iv, struct timeval* tv) {
    uint32 val;
    memcpy(&val, iv, sizeof(val));
    tv->tv_sec = htonl(val);
    memcpy(&val, iv+sizeof(val), sizeof(val));
    tv->tv_usec = htonl(val)
}

Stempel waktu dapat dikonversi ke bentuk yang dapat dibaca manusia menggunakan kode C++ berikut:

struct tm tm;
localtime_r(&tv->tv_sec, &tm);

printf("%04d-%02d-%02d|%02d:%02d:%02d.%06ld",
       tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
       tm.tm_hour, tm.tm_min, tm.tm_sec,
       tv_.tv_usec);

Library Java

Daripada menerapkan algoritma kripto untuk mengenkode dan mendekode harga yang menang, Anda dapat menggunakan DoubleClickCrypto.java. Untuk informasi selengkapnya, lihat Kriptografi.