Hyperlokale Ausrichtungssignale entschlüsseln

Wenn Publisher mobile Standortdaten an Authorized Buyers übergeben, die spezifischer als eine Postleitzahl sind, sendet Authorized Buyers den Käufer in einem neuen verschlüsselten Feld einen Geofence an BidRequest.encrypted_hyperlocal_set.

Zeitplan

  1. Ein Nutzer installiert eine werbeunterstützte App und stimmt der Verwendung der App zu. Diese App ist auch in das Google Ads SDK integriert und sendet den Standort dieses Geräts an Google.
  2. Google-Server generieren ein spezielles hyperlokales Targeting-Signal, das einen Geofence um den Gerätestandort darstellt, um die Privatsphäre der Nutzer zu schützen.
  3. Die hyperlokalen Targeting-Signale werden von Google-Servern mit dem für jeden Käufer spezifischen Sicherheitsschlüssel serialisiert und verschlüsselt. Die Gebotsfunktion entschlüsselt für das Entschlüsseln des WINNING_PRICE-Makros denselben Schlüssel.
  4. Die Gebotsfunktion entschlüsselt das hyperlokale Ausrichtungssignal in einem Protokollpuffer. Die Gebotsfunktion kann das Signal dann analysieren und entsprechend bieten.

Abhängigkeiten

Sie benötigen eine Kryptobibliothek, die SHA-1 HMAC unterstützt, z. B. Openssl.

Definition

Ein hyperlokales Ausrichtungssignal ist im Proto so definiert:

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

Jedes hyperlokale Ausrichtungssignal enthält mindestens ein Polygon und einen Mittelpunkt. Das hyperlokale Ausrichtungssignal enthält für jedes Polygon Folgendes:

  • Breiten- und Längengrad jeder Ecke des Polygons nacheinander, übergeben als Feld corners.
  • Der ungefähre geometrische Mittelpunkt des Geofence-Bereichs, der im optionalen Feld center_point übergeben wird.

Struktur des Targeting-Signals

Das verschlüsselte hyperlokale Ausrichtungssignal in BidRequest.encrypted_hyperlocal_set enthält drei Abschnitte:

  • initialization_vector: 16 Byte.
  • ciphertext: Serie von 20-Byte-Abschnitten
  • integrity_signature: 4 Byte.
{initialization_vector (16 bytes)}{ciphertext (20-byte sections)}{integrity_signature (4 bytes)}

Das ciphertext-Byte-Array ist in mehrere 20-Byte-Abschnitte unterteilt, mit der Ausnahme, dass der letzte Abschnitt 1 bis 20 Bytes umfassen kann. Für jeden Abschnitt der ursprünglichen byte_array wird die entsprechende 20-Byte-ciphertext wie folgt generiert:

<byte_array <xor> HMAC(encryption_key, initialization_vector || counter_bytes)>

Dabei ist || Verkettung.

Definition

Variable Details
initialization_vector 16 Byte – spezifisch für die Impression.
encryption_key 32 Bytes – bei der Kontoeinrichtung bereitgestellt
integrity_key 32 Bytes – bei der Kontoeinrichtung bereitgestellt
byte_array Ein serialisiertes HyperlocalSet-Objekt in 20-Byte-Abschnitten.
counter_bytes Bytewert, der die Ordinalzahl des Abschnitts angibt (siehe unten).
final_message Byte-Array, das über das Feld BidRequest.encrypted_hyperlocal_set gesendet wird.
Operatoren Details
hmac(key, data) SHA-1 HMAC, key zum Verschlüsseln von data verwenden.
a || b String a mit Verkettung b verknüpft.

Zähler-Byte berechnen

counter_bytes markiert die Reihenfolge jedes 20-Byte-Abschnitts von ciphertext. Der letzte Abschnitt kann zwischen 1 und 20 Byte enthalten sein. Um counter_bytes beim Ausführen der Funktion hmac() mit dem richtigen Wert zu füllen, zählen Sie die 20-Byte-Abschnitte (einschließlich der übrigen) und verwenden Sie die folgende Referenztabelle:

Abschnittsnummer counter_bytes Wert
0
1 ... 256 1 Byte. Der Wert erhöht sich sequenziell von 0 bis 255.
257 ... 512 2 Byte. Der Wert des ersten Bytes ist 0, der Wert des zweiten Bytes sequenziell von 0 bis 255.
513 ... 768 3 Byte. Der Wert der ersten beiden Byte ist 0, der Wert des letzten Byte inkrementell von 0 bis 255.

Wir gehen nicht davon aus, dass die Länge von BidRequest.encrypted_hyperlocal_set ein Kilobyte überschreitet, auch wenn wir weiteres Wachstum berücksichtigen. counter_bytes kann jedoch so lang sein, wie es zur Unterstützung eines hyperlokalen Targeting-Signals beliebiger Länge erforderlich ist.

Verschlüsselungsschema

Das Verschlüsselungsschema für hyperlokales Ausrichtungssignal basiert auf demselben Schema, das auch zum Entschlüsseln von Preisbestätigungen verwendet wird.

  1. Serialisierung: Das hyperlokale Ausrichtungssignal, bei dem es sich um eine Instanz des HyperlocalSet-Objekts im Proto handelt, wird zuerst über SerializeAsString() in ein Byte-Array serialisiert.

  2. Verschlüsselung: Das Byte-Array wird dann mit einem benutzerdefinierten Verschlüsselungsschema verschlüsselt, um den Größenaufwand zu minimieren und gleichzeitig eine angemessene Sicherheit zu gewährleisten. Das Verschlüsselungsschema verwendet einen HMAC-Algorithmus mit Schlüssel, um ein geheimes Pad basierend auf dem initialization_vector zu generieren, das für das Impressionsereignis eindeutig ist.

Pseudocode zur Verschlüsselung

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

Entschlüsselungsschema

Der Entschlüsselungscode muss 1) das hyperlokale Targeting-Signal mit dem Verschlüsselungsschlüssel entschlüsseln und 2) die Integritätsbits mit dem Integritätsschlüssel überprüfen. Die Schlüssel werden Ihnen bei der Kontoeinrichtung zur Verfügung gestellt. Es gibt keine Einschränkungen hinsichtlich der Strukturierung Ihrer Implementierung. In den meisten Fällen sollten Sie den Beispielcode an Ihre Anforderungen anpassen können.

  1. Pad generieren: HMAC(encryption_key, initialization_vector || counter_bytes)
  2. XOR: Verwenden Sie dieses Ergebnis und <xor> mit dem Geheimtext, um die Verschlüsselung umzukehren.
  3. Prüfen: Die Integritätssignatur übergibt 4 Byte von HMAC(integrity_key, byte_array || initialization_vector).

Entschlüsselungs-Pseudocode

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

Beispielcode für C++

Im Folgenden finden Sie eine Schlüsselfunktion aus unserem vollständigen Beispielcode für die Entschlüsselung.

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

Beispiele für hyperlokale Signale und Schlüssel

So testen und bestätigen Sie Ihren Code:

  1. Wandelt einen String mit 308 Hexadezimalzeichen in ein Array von 154 Byte um. Beispiel:
    E2014EA201246E6F6E636520736F7572636501414243C0ADF6B9B6AC17DA218FB50331EDB376701309CAAA01246E6F6E636520736F7572636501414243C09ED4ECF2DB7143A9341FDEFD125D96844E25C3C202466E6F6E636520736F7572636502414243517C16BAFADCFAB841DE3A8C617B2F20A1FB7F9EA3A3600256D68151C093C793B0116DB3D0B8BE9709304134EC9235A026844F276797
    
    Konvertieren Sie es folgendermaßen in ein 154-Byte-Array:
    const char serialized_result[154] = { 0xE2, 0x01, 0x4E, ... };
    
  2. Rufen Sie die Methode BidRequest.ParsePartialFromString() auf, um das 154-Byte-Array in einen BidRequest-Protokollpuffer zu deserialisieren.
    BidRequest bid_req;
    bid_req.ParsePartialFromString(serialzed_result);
    
  3. Achte darauf, dass BidRequest nur drei Felder enthält:
    • encrypted_hyperlocal_set
      In der BidReqeust-Nachricht deklariert.
    • encrypted_advertising_id
      In der BidReqeust.Mobile-Nachricht deklariert.
    • encrypted_hashed_idfa
      In der BidReqeust.Mobile-Nachricht deklariert.

    Beispiel:

    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 }
    
  4. Verwenden Sie die folgenden encryption_key und integrity_key, um die drei Felder zu entschlüsseln, und prüfen Sie, ob Sie sie korrekt entschlüsseln.
    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};
    

Angriffe auf veraltete Antworten erkennen

Zum Erkennen von Angriffen auf veraltete Antworten wird empfohlen, Antworten mit einem Zeitstempel zu filtern, der erheblich von der Systemzeit abweicht, wobei Zeitzonenunterschiede berücksichtigt werden. Unsere Server sind auf PST/PDT eingestellt.

Weitere Informationen zur Implementierung finden Sie im Artikel Preisbestätigungen entschlüsseln.

Java-Bibliothek

Anstatt die kryptografischen Algorithmen zum Codieren und Decodieren der hyperlokalen Targeting-Signale zu verwenden, können Sie DoubleClickCrypto.java verwenden. Weitere Informationen finden Sie unter Kryptografie.