Jeśli wydawcy przekazują do usługi Authorized Buyers dane o lokalizacji na komórki, które są bardziej szczegółowe niż kod pocztowy, Authorized Buyers wysyła do kupujących nowy rekord – BidRequest.encrypted_hyperlocal_set
w postaci geofencingu.
oś czasu
- Użytkownik instaluje aplikację mobilną z reklamami i wyraża zgodę na jej dostęp do lokalizacji urządzenia innym firmom oraz udostępnianie ich. Aplikacja jest też zintegrowana z pakietem SDK Google Ads i wysyła do Google lokalizację urządzenia.
- Serwery Google generują specjalny sygnał kierowania lokalnego, który reprezentuje położenie geograficzne urządzenia, np. w celu ochrony prywatności użytkownika.
- Serwery Google serializują i szyfrują sygnał kierowania lokalnego, korzystając z klucza bezpieczeństwa każdego kupującego. Pamiętaj, że do odszyfrowywania WINNING_PRICE makr licytujący używa tego samego klucza.
- Licytujący odszyfrowuje i deserializuje sygnał kierowania hiperlokalnego w buforze protokołu. Licytujący może następnie przeanalizować sygnał i ustalić odpowiednią stawkę.
Zależności
Potrzebujesz biblioteki kryptograficznej, która obsługuje HMAC SHA-1, np. Openssl.
Definicja
Sygnał kierowania hiperlokalnego jest zdefiniowany w protoku:
// A hyperlocal targeting location when available. // message Hyperlocal { // A location on the Earth's surface. // message Point { optional float latitude = 1; optional float longitude = 2; } // The mobile device can be at any point inside the geofence polygon defined // by a list of corners. Currently, the polygon is always a parallelogram // with 4 corners. repeated Point corners = 1; } message HyperlocalSet { // This field currently contains at most one hyperlocal polygon. repeated Hyperlocal hyperlocal = 1; // The approximate geometric center of the geofence area. It is calculated // exclusively based on the geometric shape of the geofence area and in no // way indicates the mobile device's actual location within the geofence // area. If multiple hyperlocal polygons are specified above then // center_point is the geometric center of all hyperlocal polygons. optional Hyperlocal.Point center_point = 2; } // Hyperlocal targeting signal when available, encrypted as described at // https://developers.google.com/authorized-buyers/rtb/response-guide/decrypt-hyperlocal optional bytes encrypted_hyperlocal_set = 40;
Każdy sygnał kierowania hiperlokalnego zawiera co najmniej jeden wielokąt i punkt środkowy. W przypadku każdego wielokąta sygnał kierowania lokalnego obejmuje:
- Szerokość i długość geograficzna każdego wielokąta po kolei będą przekazywane jako pole powtarzane
corners
. - Przybliżone centrum geometryczne obszaru geofencingu przekazanego w opcjonalnym polu
center_point
.
Struktura sygnału kierowania
Zaszyfrowany sygnał kierowania hiperlokalnego zawarty w danych BidRequest.encrypted_hyperlocal_set
zawiera 3 sekcje:
initialization_vector
: 16 bajtów.ciphertext
: seria po 20 bajtów.integrity_signature
: 4 bajty.
{initialization_vector (16 bytes)}{ciphertext (20-byte sections)}{integrity_signature (4 bytes)}
Tablica ciphertext
jest podzielona na wiele sekcji po 20 bajtów z wyjątkiem części, w której cała ostatnia sekcja może zawierać od 1 do 20 bajtów. Dla każdej sekcji oryginalnego pliku byte_array
odpowiadające im 20-bajtowe pole ciphertext
jest generowane jako:
<byte_array <xor> HMAC(encryption_key, initialization_vector || counter_bytes)>
Gdzie ||
to połączenie.
Definicje
Zmienna | Szczegóły |
---|---|
initialization_vector |
16 bajtów – niepowtarzalnych dla wyświetlenia. |
encryption_key |
32 bajty – podane podczas konfigurowania konta. |
integrity_key |
32 bajty – podane podczas konfigurowania konta. |
byte_array |
Zserializowano obiekt HyperlocalSet w sekcjach 20-bajtowych. |
counter_bytes |
Wartość w bajcie zawierająca liczbę porządkową sekcji (patrz niżej). |
final_message |
Tablica bajtów wysłana przez pole BidRequest.encrypted_hyperlocal_set . |
Operatory | Szczegóły |
---|---|
hmac(key, data) |
Szyfrowanie MAC SHA-1, wykorzystując key do szyfrowania data . |
a || b |
ciąg a połączony z ciągiem b . |
Oblicz licznik_bajtów
counter_bytes
wskazuje kolejność każdej 20-bajtowych sekcji tagu ciphertext
. Ostatnia sekcja może zawierać od 1 do 20 bajtów. Aby funkcja counter_bytes
działała prawidłowo z funkcją hmac()
, policzyć sekcje 20-bajtowe (w tym pozostałą) i użyć tej tabeli:
Numer sekcji | Wartość: counter_bytes |
---|---|
0 | Brak |
1 ... 256 | 1 bajt. Sekwencja zwiększa się z 0 do 255. |
257 ... 512 | 2 bajty. Wartość pierwszego bajta wynosi 0, wartość drugiego bajtu rośnie od 0 do 255 po kolei. |
513 ... 768 | 3 bajty. Wartość w pierwszych 2 bajtach wynosi 0, a wartość ostatniego bajtu jest rosnąca w zakresie od 0 do 255. |
Nie oczekujemy, że długość zasobu BidRequest.encrypted_hyperlocal_set
przekroczy jeden kilobajt, nawet biorąc pod uwagę dalszy rozwój. Mimo to wartość counter_bytes
może służyć do obsługi sygnału kierowania lokalnego o dowolnej długości.
Schemat szyfrowania
Schemat szyfrowania dla sygnału kierowania lokalnego jest oparty na tym samym schemacie co odszyfrowywanie potwierdzeń cen.
Serializuj: sygnał kierowania hiperlokalnego, który jest instancją obiektu HyperlocalSet zdefiniowanego w proto, jest najpierw szeregowany przez tablicę
SerializeAsString()
do tablicy bajtów.Szyfrowanie: bajt jest szyfrowany przy użyciu niestandardowego schematu szyfrowania, który minimalizuje koszty ogólne i zapewnia właściwe zabezpieczenia. Schemat szyfrowania używa algorytmu HMAC z kluczem, aby wygenerować tajny panel na podstawie
initialization_vector
, który jest unikalny dla zdarzenia wyświetlenia.
Pseudokod szyfrowania
byte_array = SerializeAsString(HyperlocalSet object) pad = hmac(encryption_key, initialization_vector || counter_bytes ) // for each 20-byte section of byte_array ciphertext = pad <xor> byte_array // for each 20-byte section of byte_array integrity_signature = hmac(integrity_key, byte_array || initialization_vector) // first 4 bytes final_message = initialization_vector || ciphertext || integrity_signature
Schemat odszyfrowywania
Kod odszyfrowywania musi: 1) odszyfrować sygnał kierowania hiperlokalnego za pomocą klucza szyfrowania oraz 2) zweryfikować bity integralności za pomocą klucza integralności. Klucze zostaną Ci udostępnione podczas konfiguracji konta. Nie obowiązują żadne ograniczenia dotyczące struktury implementacji. W większości przypadków możesz pobrać przykładowy kod i dostosować go do swoich potrzeb.
- Wygeneruj tablet:
HMAC(encryption_key, initialization_vector || counter_bytes)
- XOR: odnieś ten wynik, a
<xor>
z szyfrem. - Zweryfikuj: podpis integralności przekazuje 4 bajty
HMAC(integrity_key, byte_array || initialization_vector)
Pseudokod szyfrowania
(initialization_vector, ciphertext, integrity_signature) = final_message // split up according to length rules pad = hmac(encryption_key, initialization_vector || counter_bytes) // for each 20-byte section of ciphertext byte_array = ciphertext <xor> pad // for each 20-byte section of ciphertext confirmation_signature = hmac(integrity_key, byte_array || initialization_vector) success = (confirmation_signature == integrity_signature)
Przykładowy kod C++
Poniżej znajdziesz kluczową funkcję naszego pełnego przykładowego kodu odszyfrowywania.
bool DecryptByteArray( const string& ciphertext, const string& encryption_key, const string& integrity_key, string* cleartext) { // Step 1. find the length of initialization vector and clear text. const int cleartext_length = ciphertext.size() - kInitializationVectorSize - kSignatureSize; if (cleartext_length < 0) { // The length cannot be correct. return false; } string iv(ciphertext, 0, kInitializationVectorSize); // Step 2. recover clear text cleartext->resize(cleartext_length, '\0'); const char* ciphertext_begin = string_as_array(ciphertext) + iv.size(); const char* const ciphertext_end = ciphertext_begin + cleartext->size(); string::iterator cleartext_begin = cleartext->begin(); bool add_iv_counter_byte = true; while (ciphertext_begin < ciphertext_end) { uint32 pad_size = kHashOutputSize; uchar encryption_pad[kHashOutputSize]; if (!HMAC(EVP_sha1(), string_as_array(encryption_key), encryption_key.length(), (uchar*)string_as_array(iv), iv.size(), encryption_pad, &pad_size)) { printf("Error: encryption HMAC failed.\n"); return false; } for (int i = 0; i < kBlockSize && ciphertext_begin < ciphertext_end; ++i, ++cleartext_begin, ++ciphertext_begin) { *cleartext_begin = *ciphertext_begin ^ encryption_pad[i]; } if (!add_iv_counter_byte) { char& last_byte = *iv.rbegin(); ++last_byte; if (last_byte == '\0') { add_iv_counter_byte = true; } } if (add_iv_counter_byte) { add_iv_counter_byte = false; iv.push_back('\0'); } } }
Próbka i sygnał hiperlokalny
Aby przetestować i zweryfikować kod:
- Przekonwertuj ciąg znaków zawierający 308 znaków szesnastkowych na tablicę po 154 bajtów. Na przykład w tym ciągu:
E2014EA201246E6F6E636520736F7572636501414243C0ADF6B9B6AC17DA218FB50331EDB376701309CAAA01246E6F6E636520736F7572636501414243C09ED4ECF2DB7143A9341FDEFD125D96844E25C3C202466E6F6E636520736F7572636502414243517C16BAFADCFAB841DE3A8C617B2F20A1FB7F9EA3A3600256D68151C093C793B0116DB3D0B8BE9709304134EC9235A026844F276797
przekonwertuj go na tablicę 154-bajtową w następujący sposób:const char serialized_result[154] = { 0xE2, 0x01, 0x4E, ... };
- Wywołaj metodę
BidRequest.ParsePartialFromString()
, aby destylować tablicę 154-bajtową do bufora protokołuBidRequest
.BidRequest bid_req; bid_req.ParsePartialFromString(serialzed_result);
- Sprawdź, czy pole
BidRequest
zawiera tylko 3 pola:encrypted_hyperlocal_set
Zadeklarowano w wiadomościBidReqeust
.encrypted_advertising_id
Zadeklarowano w wiadomościBidReqeust.Mobile
.encrypted_hashed_idfa
Zadeklarowano w wiadomościBidReqeust.Mobile
.
Przykład:
encrypted_hyperlocal_set:( { 100, 100 }, { 200, -300 }, { -400, 500 }, { -600, -700 },) encrypted_advertising_id: { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 } encrypted_hashed_idfa : { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xF1 }
- Aby odszyfrować 3 pola i sprawdzić, czy są prawidłowo odszyfrowane, użyj tych pól
encryption_key
iintegrity_key
.encryption_key = {0x02, 0xEE, 0xa8, 0x3c, 0x6c, 0x12, 0x11, 0xe1, 0x0b, 0x9f, 0x88, 0x96, 0x6c, 0xee, 0xc3, 0x49, 0x08, 0xeb, 0x94, 0x6f, 0x7e, 0xd6, 0xe4, 0x41, 0xaf, 0x42, 0xb3, 0xc0, 0xf3, 0x21, 0x81, 0x40}; integrity_key = {0xbf, 0xFF, 0xec, 0x55, 0xc3, 0x01, 0x30, 0xc1, 0xd8, 0xcd, 0x18, 0x62, 0xed, 0x2a, 0x4c, 0xd2, 0xc7, 0x6a, 0xc3, 0x3b, 0xc0, 0xc4, 0xce, 0x8a, 0x3d, 0x3b, 0xbd, 0x3a, 0xd5, 0x68, 0x77, 0x92};
Wykrywanie nieaktualnych ataków
Aby wykryć nieaktualne odpowiedzi, zalecamy filtrowanie odpowiedzi z sygnaturą czasową, która różni się znacznie od czasu systemowego po uwzględnieniu różnic w strefach czasowych. Nasze serwery mają ustawiony czas PST/PDT.
Szczegółowe informacje o implementacji znajdziesz w artykule „Wykrywanie nieaktualnych ataków odpowiedzi” w artykule Odszyfrowywanie potwierdzeń cen.
Biblioteka Java
Zamiast implementować algorytmy kryptograficzne w celu kodowania i dekodowania sygnałów kierowania hiperlokalnego, możesz użyć pliku DoubleClickCrypto.java. Więcej informacji znajdziesz na stronie Kryptografia.