Si les éditeurs transmettent à Authorized Buyers des données de localisation plus précises qu'un code postal, Authorized Buyers envoie une zone de géorepérage hyperlocalisée aux acheteurs dans un nouveau champ chiffré: BidRequest.encrypted_hyperlocal_set
.
Chronologie
- Un utilisateur installe une application mobile avec publicité et accepte que celle-ci accède à la position de l'appareil et la partage avec des tiers. Cette application est également intégrée au SDK Google Ads et envoie la position de cet appareil à Google.
- Les serveurs Google génèrent un signal de ciblage hyperlocalisé spécial qui représente une zone de géorepérage autour de l'emplacement de l'appareil, par exemple pour protéger la vie privée des utilisateurs.
- Les serveurs Google sérialisent et chiffrent le signal de ciblage hyperlocalisé à l'aide de la clé de sécurité spécifique à chaque acheteur. Notez que le système d'enchères utilise la même clé pour déchiffrer la macro WINNING_PRICE.
- Votre système d'enchères déchiffre et désérialise le signal de ciblage hyperlocalisé en un tampon de protocole. Votre enchérisseur peut ensuite analyser le signal et enchérir en conséquence.
Dépendances
Vous aurez besoin d'une bibliothèque de cryptographie compatible avec SHA-1 HMAC, telle que Openssl.
Définition
Un signal de ciblage hyperlocalisé est défini dans le protocole comme suit:
// 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;
Chaque signal de ciblage hyperlocalisé contient un ou plusieurs polygones et un point central. Pour chaque polygone, le signal de ciblage hyperlocalisé contient:
- La latitude et la longitude de chaque angle du polygone sont transmises de manière séquentielle en tant que champ
corners
répété. - Centre géométrique approximatif de la zone de géorepérage spécifiée dans le champ facultatif
center_point
.
Structure du signal de ciblage
Le signal de ciblage hyperlocalisé chiffré dans BidRequest.encrypted_hyperlocal_set
comporte trois sections:
initialization_vector
: 16 octets.ciphertext
: série de sections de 20 octets.integrity_signature
: 4 octets.
{initialization_vector (16 bytes)}{ciphertext (20-byte sections)}{integrity_signature (4 bytes)}
Le tableau d'octets ciphertext
est divisé en plusieurs sections de 20 octets, à l'exception que la toute dernière section peut contenir entre 1 et 20 octets. Pour chaque section du byte_array
d'origine, le ciphertext
de 20 octets correspondant est généré comme suit:
<byte_array <xor> HMAC(encryption_key, initialization_vector || counter_bytes)>
où ||
représente une concaténation.
Définitions
Variable | Détails |
---|---|
initialization_vector |
16 octets : valeur unique pour l'impression. |
encryption_key |
32 octets : fournis au moment de la configuration du compte. |
integrity_key |
32 octets : fournis au moment de la configuration du compte. |
byte_array |
Un objet HyperlocalSet sérialisé en sections de 20 octets. |
counter_bytes |
Valeur d'octets indiquant le numéro ordinal de la section (voir ci-dessous). |
final_message |
Tableau d'octets envoyé via le champ BidRequest.encrypted_hyperlocal_set . |
Opérateurs | Détails |
---|---|
hmac(key, data) |
HMAC SHA-1 utilisant key pour chiffrer data . |
a || b |
chaîne a concaténée avec la chaîne b . |
Calculer contre_octets
counter_bytes
marque l'ordre de chaque section de 20 octets de ciphertext
. Notez que la dernière section peut contenir entre 1 et 20 octets inclus. Pour renseigner counter_bytes
avec la valeur correcte lorsque vous exécutez votre fonction hmac()
, comptez les sections de 20 octets (y compris le reste) et utilisez la table de référence suivante:
Numéro de section | Valeur counter_bytes |
---|---|
0 | Aucun |
1 ... 256 | 1 octet. La valeur s'incrémente de 0 à 255 de manière séquentielle. |
257 ... 512 | 2 octets. La valeur du premier octet est 0. La valeur du deuxième octet s'incrémente de 0 à 255 de manière séquentielle. |
513 ... 768 | 3 octets. La valeur des deux premiers octets est égale à 0. Les valeurs du dernier octet sont incrémentées de 0 à 255 de manière séquentielle. |
La longueur de BidRequest.encrypted_hyperlocal_set
ne devrait pas dépasser un kilo-octet, même en tenant compte d'une croissance plus importante. Cependant, counter_bytes
peut être aussi long que nécessaire pour prendre en charge un signal de ciblage hyperlocalisé de longueur arbitraire.
Schéma de chiffrement
Le schéma de chiffrement pour le signal de ciblage hyperlocalisé est basé sur le même schéma que celui utilisé pour déchiffrer les confirmations de prix.
Sérialisation : le signal de ciblage hyperlocalisé, qui est une instance de l'objet HyperlocalSet, tel que défini dans le protocole, est d'abord sérialisé via
SerializeAsString()
en un tableau d'octets.Chiffrement : le tableau d'octets est ensuite chiffré à l'aide d'un schéma de chiffrement personnalisé conçu pour réduire la surcharge sur la taille tout en assurant une sécurité adéquate. Le schéma de chiffrement utilise un algorithme HMAC à clé pour générer un cache secret basé sur le
initialization_vector
, qui est unique à l'événement d'impression.
Pseudo-code de chiffrement
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
Schéma de déchiffrement
Votre code de déchiffrement doit 1) déchiffrer le signal de ciblage hyperlocalisé à l'aide de la clé de chiffrement et 2) vérifier les bits d'intégrité à l'aide de la clé d'intégrité. Les clés vous seront fournies lors de la configuration du compte. Il n'existe aucune restriction concernant la structure de votre mise en œuvre. Dans la plupart des cas, vous devez être en mesure de prendre l'exemple de code et de l'adapter à vos besoins.
- Générer votre bloc-notes :
HMAC(encryption_key, initialization_vector || counter_bytes)
- XOR : utilise ce résultat et
<xor>
avec le texte chiffré pour inverser le chiffrement. - Vérification : la signature d'intégrité transmet 4 octets de
HMAC(integrity_key, byte_array || initialization_vector)
Pseudo-déchiffrement
(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)
Exemple de code C++
Vous trouverez ci-dessous une fonction clé de notre exemple de code de déchiffrement complet.
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'); } } }
Exemples de clés et de signaux hyperlocalisés
Pour tester et valider votre code:
- Convertissez une chaîne contenant 308 caractères hexadécimaux en un tableau de 154 octets. Par exemple, avec la chaîne suivante :
E2014EA201246E6F6E636520736F7572636501414243C0ADF6B9B6AC17DA218FB50331EDB376701309CAAA01246E6F6E636520736F7572636501414243C09ED4ECF2DB7143A9341FDEFD125D96844E25C3C202466E6F6E636520736F7572636502414243517C16BAFADCFAB841DE3A8C617B2F20A1FB7F9EA3A3600256D68151C093C793B0116DB3D0B8BE9709304134EC9235A026844F276797
convertissez-la en tableau de 154 octets comme suit:const char serialized_result[154] = { 0xE2, 0x01, 0x4E, ... };
- Appelez la méthode
BidRequest.ParsePartialFromString()
pour désérialiser le tableau de 154 octets dans un tampon de protocoleBidRequest
.BidRequest bid_req; bid_req.ParsePartialFromString(serialzed_result);
- Vérifiez que
BidRequest
ne comporte que trois champs :encrypted_hyperlocal_set
Déclaré dans le messageBidReqeust
.encrypted_advertising_id
Déclaré dans le messageBidReqeust.Mobile
.encrypted_hashed_idfa
Déclaré dans le messageBidReqeust.Mobile
.
Exemple :
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 }
- Utilisez les
encryption_key
etintegrity_key
suivants pour déchiffrer les trois champs et vérifier que vous les avez correctement déchiffrés.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};
Détection des attaques de réponses obsolètes
Pour détecter les attaques de réponses obsolètes, nous vous recommandons de filtrer les réponses avec un horodatage très différent de l'heure du système, après prise en compte des différences de fuseau horaire. Nos serveurs sont définis sur l'heure PST/PDT.
Pour en savoir plus sur l'implémentation, consultez la section "Détecter les attaques de réponse obsolètes" de l'article Déchiffrer les confirmations de prix.
Bibliothèque Java
Au lieu de mettre en œuvre les algorithmes cryptographiques pour encoder et décoder les signaux de ciblage hyperlocalisés, vous pouvez utiliser DoubleClickCrypto.java. Pour en savoir plus, consultez la page Cryptographie.