Déchiffrer les confirmations de prix

Lorsque votre création remporte une enchère, Google peut vous indiquer le prix gagnant, si l'extrait HTML ou l'URL VAST qui définit la création inclut la macro WINNING_PRICE. Google renvoie le prix gagnant sous forme chiffrée. Les rubriques suivantes expliquent comment votre application peut déchiffrer les informations sur le prix gagnant.

La macro WINNING_PRICE peut être incluse dans une création, par exemple avec une requête de pixel invisible affichée dans l'annonce:

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

Vous pouvez également inclure la macro WINNING_PRICE dans l'URL VAST d'une création vidéo (mais pas dans l'URL d'impression du fichier VAST):

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

Scénario

  1. Votre application inclut la macro WINNING_PRICE dans l'extrait HTML ou l'URL VAST qu'elle renvoie à Google.
  2. Google remplace le prix gagnant dans la macro, au format base64 adapté au Web sans remplissage (RFC 3548).
  3. L'extrait de code transmet la confirmation dans le format que vous avez choisi. Par exemple, la confirmation peut être transmise à l'URL d'une requête de pixel invisible affichée dans l'annonce.
  4. Sur le serveur, l'application en base64 adaptée au Web décode les informations relatives au prix gagnant et déchiffre le résultat.

Dépendances

Vous aurez besoin d'une bibliothèque de chiffrement compatible avec SHA-1 HMAC, telle qu'Openssl.

Exemple de code

L'exemple de code est fourni en Java et C++ et peut être téléchargé à partir du projet privatedatacommunicationprotocol.

  • L'exemple de code Java utilise le décodeur base64 du projet Apache Commons. Vous n'avez pas besoin de télécharger le code Apache Commons, car la mise en œuvre de référence inclut la partie nécessaire et est donc autonome.

  • L'exemple de code C++ utilise la méthode BIO OpenSSL base64. Il utilise une chaîne encodée en base64 adaptée au Web (RFC 3548) et la décode. Normalement, les chaînes au format base64 adaptée au Web remplacent la marge intérieure "=" par "." (notez que les guillemets sont ajoutés pour faciliter la lecture et ne sont pas inclus dans le protocole), mais le remplacement de macro ne complète pas le prix chiffré. L'implémentation de la référence ajoute une marge intérieure, car OpenSSL rencontre des problèmes avec les chaînes sans remplissage.

Encodage

Pour remporter un prix, le chiffrement et le déchiffrement nécessitent deux clés secrètes, mais partagées. Une clé d'intégrité et une clé de chiffrement, appelées respectivement i_key et e_key. Ces deux clés sont fournies au moment de la configuration du compte en tant que chaînes base64 sécurisées pour le Web. Vous les trouverez sur la page Authorized Buyers sous Paramètres de l'enchérisseur > Paramètres RTB > Clés de chiffrement.

Exemples de clés d'intégrité et de chiffrement:

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

Les clés doivent être décodées de manière sécurisée sur le Web, puis décodées en base64 par votre application:

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

Schéma de chiffrement

Les prix sont chiffrés à l'aide d'un schéma de chiffrement personnalisé conçu pour réduire au maximum la surcharge de taille tout en assurant une sécurité adéquate. Le schéma de chiffrement utilise un algorithme HMAC à clé pour générer un bloc secret basé sur l'ID d'événement d'impression unique.

Le prix crypté a une longueur fixe de 28 octets. Il se compose d'un vecteur d'initialisation de 16 octets, de 8 octets de texte chiffré et d'une signature d'intégrité de 4 octets. Le prix chiffré est encodé au format base64 adapté au Web, conformément à la norme RFC 3548, et les caractères de remplissage sont omis. Ainsi, le prix chiffré de 28 octets est encodé sous la forme d'une chaîne au format base64 adaptée au Web de 38 caractères, quel que soit le prix payé.

Exemples de prix chiffrés:

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

Le format chiffré est le suivant:

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

Le prix est chiffré au format <price xor HMAC(encryption_key, initialization_vector)>. Le déchiffrement calcule donc HMAC(encryption_key,initialization_vector) et xor avec le prix chiffré pour inverser le chiffrement. L'étape d'intégrité prend 4 octets <HMAC(integrity_key, price||initialization_vector)>, où || correspond à une concaténation.

Entrées
iv Vecteur d'initialisation (16 octets ; unique pour l'impression)
e_key Clé de chiffrement (32 octets ; fournie lors de la configuration du compte)
i_key Clé d'intégrité (32 octets ; fournie lors de la configuration du compte)
price (8 octets ; en micro-unités de la devise du compte)
Notation
hmac(k, d) SHA-1 HMAC des données d, à l'aide de la clé k
a || b chaîne a concaténée avec la chaîne b
Pseudo-code
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 )

Schéma de déchiffrement

Votre code de déchiffrement doit déchiffrer le prix à l'aide de la clé de chiffrement et 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. Il n'existe aucune restriction concernant la structure de la mise en œuvre. Dans la plupart des cas, vous devriez pouvoir adapter l'exemple de code à vos besoins.

Entrées
e_key Clé de chiffrement (32 octets) fournie lors de la configuration du compte
i_key Clé d'intégrité (32 octets) fournie lors de la configuration du compte
final_message 38 caractères encodés en base64 pour le Web
Pseudo-code
// 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)

Détecter les attaques de réponses obsolètes

Pour détecter les attaques de réponse obsolète (ou par rejeu), il est recommandé de filtrer les réponses avec un horodatage considérablement différent de l'heure système, après avoir pris en compte les différences de fuseau horaire.

Le vecteur d'initialisation contient un code temporel dans les huit premiers octets. Il peut être lu par la fonction C++ suivante:

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

L'horodatage peut être converti dans un format lisible à l'aide du code C++ suivant:

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

Bibliothèque Java

Au lieu de mettre en œuvre les algorithmes de cryptographie pour encoder et décoder le prix gagnant, vous pouvez utiliser le fichier DoubleClickCrypto.java. Pour en savoir plus, consultez la page Cryptographie.