Decriptare indicatori di targeting iperlocale

Se i publisher trasmettono ad Authorized Buyers dati sulla posizione su dispositivi mobili più specifici di un codice postale, Authorized Buyers invierà un'area di recinzione"hyperlocal&#39"agli acquirenti in un nuovo campo criptato: BidRequest.encrypted_hyperlocal_set.

Sequenza temporale

  1. Un utente installa un'app per dispositivi mobili con pubblicità e autorizza l'app ad accedere e a condividere la posizione del dispositivo con terze parti. Questa app è integrata con l'SDK Google Ads e invia la posizione di questo dispositivo a Google.
  2. I server di Google generano uno speciale segnale di targeting iperlocale che rappresenta un recinto virtuale che circonda la posizione del dispositivo, ad esempio per proteggere la privacy dell'utente.
  3. I server Google serializzano e criptano l'indicatore di targeting iperlocale utilizzando il token di sicurezza specifico di ciascun acquirente. Tieni presente che lo strumento di offerta si basa sulla stessa chiave per decriptare la macro WINNING_PRICE.
  4. Lo strumento di offerta decripta e deserializza l'indicatore di targeting iperlocale in un buffer di protocollo. Lo strumento di offerta può quindi analizzare l'indicatore e fare offerte di conseguenza.

Dipendenze

Avrai bisogno di una libreria di crittografia che supporti SHA-1 HMAC, ad esempio Openssl.

Definizione

Un protocollo di targeting iperlocale è definito nel protocollo in questo modo:

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

Ogni indicatore di targeting iperlocale contiene uno o più poligoni e un punto centrale. Per ogni poligono, l'indicatore di targeting iperlocale contiene:

  • La latitudine e la longitudine di ogni angolo del poligono, passate come un campo corners ripetuto.
  • Il centro geometrico approssimativo dell'area del recinto virtuale, passato nel campo facoltativo center_point.

Struttura dell'indicatore di targeting

L'indicatore di targeting iperlocale criptato contenuto in BidRequest.encrypted_hyperlocal_set contiene 3 sezioni:

  • initialization_vector: 16 byte.
  • ciphertext: serie di sezioni da 20 byte.
  • integrity_signature: 4 byte.
{initialization_vector (16 bytes)}{ciphertext (20-byte sections)}{integrity_signature (4 bytes)}

L'array di ciphertext byte è diviso in più sezioni da 20 byte, ad eccezione del fatto che l'ultima sezione può contenere da 1 a 20 byte inclusi. Per ogni sezione dell'originale byte_array, il corrispondente ciphertext di 20 byte viene generato come:

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

Dove || è concatenata.

Definizioni

Variabile Dettagli
initialization_vector 16 byte: univoco per l'impressione.
encryption_key 32 byte: fornito durante la creazione dell'account.
integrity_key 32 byte: fornito durante la creazione dell'account.
byte_array Un oggetto HyperlocalSet serializzato, in sezioni da 20 byte.
counter_bytes Il valore in byte mostra il numero ordinale della sezione, vedi di seguito.
final_message Array di byte inviati tramite il campo BidRequest.encrypted_hyperlocal_set.
Operatori Dettagli
hmac(key, data) MAC H-SHA-1, utilizzando key per criptare data.
a || b stringa a concatenata con stringa b.

Calcolare contatori_byte

counter_bytes contrassegna l'ordine di ogni sezione di 20 byte del ciphertext. Tieni presente che l'ultima sezione può contenere da 1 a 20 byte inclusi. Per riempire counter_bytes con il valore corretto quando esegui la funzione hmac(), conteggia le sezioni di 20 byte (incluso il resto) e utilizza la seguente tabella di riferimento:

Numero sezione Valore counter_bytes
0 Nessuno
1...256 1 byte. Il valore aumenta da 0 a 255 in sequenza.
257...512 2 byte. Il valore del primo byte è 0, il valore del secondo byte aumenta da 0 a 255 in sequenza.
513... 768 3 byte. Il valore dei primi due byte è 0, il valore dell'ultimo byte aumenta da 0 a 255 in sequenza.

Non prevediamo che la lunghezza di BidRequest.encrypted_hyperlocal_set superi il limite di 1 kilobyte, anche in considerazione di un'ulteriore crescita. Tuttavia, il valore counter_bytes può essere sufficiente per supportare un indicatore di targeting iperlocale di durata arbitraria.

Schema di crittografia

Lo schema di crittografia per l'indicatore di targeting iperlocale si basa sullo stesso schema utilizzato per la decriptazione delle conferme di prezzo.

  1. Serializzazione: l'indicatore di targeting iperlocale, che è un'istanza dell'oggetto HyperlocalSet come definito nel proto, viene prima serializzato tramite SerializeAsString() in un array di byte.

  2. Crittografia: l'array di byte viene quindi criptato utilizzando uno schema di crittografia personalizzato progettato per ridurre al minimo l'overhead di dimensione e garantire comunque una sicurezza adeguata. Lo schema di crittografia utilizza un algoritmo HMAC con chiave per generare un pad segreto in base al initialization_vector, che è univoco per l'evento di impressione.

Pseudo codice di crittografia

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

Schema di decriptazione

Il codice di decriptazione deve 1) decriptare il segnale di targeting iperlocale utilizzando la chiave di crittografia e 2) verificare i bit di integrità con la chiave di integrità. Le chiavi ti verranno fornite durante la creazione dell'account. Non ci sono limitazioni alla strutturazione della tua implementazione. Nella maggior parte dei casi, dovresti essere in grado di prendere il codice di esempio e adattarlo in base alle tue esigenze.

  1. Genera il pad: HMAC(encryption_key, initialization_vector || counter_bytes)
  2. XOR: utilizza questo risultato e <xor> con il testo criptato per invertire la crittografia.
  3. Verifica: la firma di integrità trasmette 4 byte di HMAC(integrity_key, byte_array || initialization_vector)

Pseudocodice di decriptazione

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

Codice C++ di esempio

Questa è una funzione chiave del nostro codice di esempio di decriptazione completo.

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

Esempio di segnali e chiavi iperlocali

Per verificare e verificare il codice:

  1. Converti una stringa contenente 308 caratteri esadecimali in un array di 154 byte. Ad esempio, data la seguente stringa:
    E2014EA201246E6F6E636520736F7572636501414243C0ADF6B9B6AC17DA218FB50331EDB376701309CAAA01246E6F6E636520736F7572636501414243C09ED4ECF2DB7143A9341FDEFD125D96844E25C3C202466E6F6E636520736F7572636502414243517C16BAFADCFAB841DE3A8C617B2F20A1FB7F9EA3A3600256D68151C093C793B0116DB3D0B8BE9709304134EC9235A026844F276797
    
    convertirlo in un array di 154 byte nel seguente modo:
    const char serialized_result[154] = { 0xE2, 0x01, 0x4E, ... };
    
  2. Richiama il metodo BidRequest.ParsePartialFromString() per deserializzare l'array da 154 byte in un buffer di protocollo BidRequest.
    BidRequest bid_req;
    bid_req.ParsePartialFromString(serialzed_result);
    
  3. Verifica che BidRequest abbia solo 3 campi:
    • encrypted_hyperlocal_set
      Dichiarati nel messaggio BidReqeust.
    • encrypted_advertising_id
      Dichiarati nel messaggio BidReqeust.Mobile.
    • encrypted_hashed_idfa
      Dichiarati nel messaggio BidReqeust.Mobile.

    Ad esempio:

    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. Utilizza i seguenti encryption_key e integrity_key per decriptare i tre campi e verificare che vengano decriptati correttamente.
    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};
    

Rileva gli attacchi di risposta inattiva

Per rilevare gli attacchi di risposta inattiva, ti consigliamo di filtrare le risposte con un timestamp che differisce in modo significativo dall'ora di sistema, dopo aver preso in considerazione le differenze di fuso orario. I nostri server sono impostati sul fuso orario PST/PDT.

Per maggiori dettagli sull'implementazione, leggi la sezione "Rilevamento di attacchi di risposta inattive" nell'articolo Decriptare le conferme di prezzo.

Libreria Java

Invece di implementare gli algoritmi di crittografia per codificare e decodificare gli indicatori di targeting iperlocale, puoi utilizzare DoubleClickCrypto.java. Per ulteriori informazioni, consulta la pagina Crittografia.