Desencriptar indicadores de orientación hiperlocales

Si los publicadores pasan datos de ubicación móvil a Authorized Buyers, que es más específico que un código postal, Authorized Buyers enviará un geovallado hiperlocal a los compradores en un nuevo campo encriptado: BidRequest.encrypted_hyperlocal_set.

Rutas

  1. Un usuario instala una app para dispositivos móviles compatible con anuncios y da su consentimiento para que esta acceda a la ubicación del dispositivo y la comparta con terceros. Esta aplicación también está integrada con el SDK de anuncios de Google y envía la ubicación de este dispositivo a Google.
  2. Los servidores de Google generan una señal de orientación hiperlocal especial que representa un geovallado que rodea la ubicación del dispositivo, por ejemplo, para proteger la privacidad del usuario.
  3. Los servidores de Google serializan y encriptan la señal de orientación hiperlocal con la llave de seguridad específica de cada comprador. Ten en cuenta que tu ofertante se basa en la misma clave para desencriptar la macro WINNING_PRICE.
  4. Su ofertante desencripta y deserializa la señal de orientación hiperlocal en un búfer de protocolo. Luego, su ofertante puede analizar el indicador y realizar una oferta según corresponda.

Dependencias

Necesitarás una biblioteca criptográfica que admita SHA-1 HMAC, como Openssl.

Definición

En el proto, se define una señal de orientación hiperlocal de la siguiente manera:

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

Cada señal de orientación hiperlocal contiene uno o más polígonos y un punto central. Para cada polígono, el indicador de orientación hiperlocal contiene:

  • La latitud y la longitud de cada esquina del polígono de forma secuencial, que se pasan como un campo corners repetido.
  • El centro geométrico aproximado del área de geovallado, que se pasa en el campo opcional center_point.

Estructura del indicador de segmentación

El indicador de segmentación hiperlocal encriptado que se incluye en BidRequest.encrypted_hyperlocal_set contiene 3 secciones:

  • initialization_vector: 16 bytes
  • ciphertext: Serie de secciones de 20 bytes.
  • integrity_signature: 4 bytes
{initialization_vector (16 bytes)}{ciphertext (20-byte sections)}{integrity_signature (4 bytes)}

El arreglo de bytes ciphertext se divide en varias secciones de 20 bytes, con la excepción de que la última sección puede contener entre 1 y 20 bytes inclusive. Para cada sección del byte_array original, el ciphertext de 20 bytes correspondiente se genera de la siguiente manera:

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

Donde || es la concatenación.

Definiciones

Variable Detalles
initialization_vector 16 bytes: único para la impresión
encryption_key 32 bytes: Se proporcionan en la configuración de la cuenta.
integrity_key 32 bytes: Se proporcionan en la configuración de la cuenta.
byte_array Un objeto HyperlocalSet serializado, en secciones de 20 bytes.
counter_bytes Valor en bytes que muestra el número ordinal de la sección, consulta a continuación.
final_message El arreglo de bytes que se envió a través del campo BidRequest.encrypted_hyperlocal_set.
Operadores Detalles
hmac(key, data) SHA-1 HMAC, que usa key para encriptar data
a || b La string a se concatena con la string b.

Calcular contador_bytes

counter_bytes marca el orden de cada sección de 20 bytes de ciphertext. Ten en cuenta que la última sección puede contener entre 1 y 20 bytes inclusive. Para completar counter_bytes con el valor correcto cuando ejecutes la función hmac(), cuenta las secciones de 20 bytes (incluido el resto) y usa la siguiente tabla de referencia:

Número de sección Valor counter_bytes
0 Ninguno
1 ... 256 1 byte. El valor aumenta de 0 a 255 de forma secuencial.
257 ... 512 2 bytes. El valor del primer byte es 0; el valor del segundo byte aumenta de 0 a 255 de forma secuencial.
513 ... 768 3 bytes. El valor de los primeros dos bytes es 0, el valor del último byte aumenta de 0 a 255 de manera secuencial.

No se espera que la longitud de BidRequest.encrypted_hyperlocal_set supere un kilobyte, incluso si se tiene en cuenta el crecimiento. Sin embargo, counter_bytes puede ser el tiempo necesario para admitir un indicador de orientación hiperlocal de longitud arbitraria.

Esquema de encriptación

El esquema de encriptación para la señal de orientación hiperlocal se basa en el mismo esquema utilizado para desencriptar confirmaciones de precio.

  1. Serialización: la señal de orientación hiperlocal, que es una instancia del objeto HyperlocalSet, como se define en el proto, primero se serializa por medio de SerializeAsString() en un arreglo de bytes.

  2. Encriptación: Luego, el arreglo de bytes se encripta con un esquema de encriptación personalizado diseñado para minimizar la sobrecarga de tamaño y, a la vez, garantizar la seguridad adecuada. El esquema de encriptación usa un algoritmo de HMAC con clave para generar un pad secreto basado en initialization_vector, que es único para el evento de impresión.

Pseudocódigo de encriptación

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

Esquema de desencriptación

Tu código de desencriptación debe 1) desencriptar la señal de segmentación hiperlocal con la clave de encriptación y 2) verificar los bits de integridad con la clave de integridad. Las claves se le proporcionarán durante la configuración de la cuenta. No hay restricciones en la forma en la que estructuras tu implementación. En general, deberías poder tomar el código de muestra y adaptarlo según tus necesidades.

  1. Genera tu teclado: HMAC(encryption_key, initialization_vector || counter_bytes)
  2. XOR: Toma este resultado y <xor> con el texto cifrado para revertir la encriptación.
  3. Verificar: La firma de integridad pasa 4 bytes de HMAC(integrity_key, byte_array || initialization_vector).

Pseudocódigo de desencriptación

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

Código de muestra C++

Aquí se incluye una función clave de nuestro código de ejemplo de desencriptación 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');
    }
  }
}

Ejemplo de indicadores y claves hiperlocales

Para probar y verificar tu código, haz lo siguiente:

  1. Convierte una string que contenga 308 caracteres hexadecimales en un arreglo de 154 bytes. Por ejemplo, con la siguiente string:
    E2014EA201246E6F6E636520736F7572636501414243C0ADF6B9B6AC17DA218FB50331EDB376701309CAAA01246E6F6E636520736F7572636501414243C09ED4ECF2DB7143A9341FDEFD125D96844E25C3C202466E6F6E636520736F7572636502414243517C16BAFADCFAB841DE3A8C617B2F20A1FB7F9EA3A3600256D68151C093C793B0116DB3D0B8BE9709304134EC9235A026844F276797
    
    convertirlo en un array de 154 bytes de la siguiente manera:
    const char serialized_result[154] = { 0xE2, 0x01, 0x4E, ... };
    
  2. Llama al método BidRequest.ParsePartialFromString() para deserializar el arreglo de 154 bytes en un búfer de protocolo BidRequest.
    BidRequest bid_req;
    bid_req.ParsePartialFromString(serialzed_result);
    
  3. Verifica que BidRequest tenga solo 3 campos:
    • encrypted_hyperlocal_set
      Declarado en el mensaje BidReqeust.
    • encrypted_advertising_id
      Declarado en el mensaje BidReqeust.Mobile.
    • encrypted_hashed_idfa
      Declarado en el mensaje BidReqeust.Mobile.

    Por ejemplo:

    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. Usa los siguientes encryption_key y integrity_key para desencriptar los 3 campos y verificar que los desencriptes correctamente.
    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};
    

Detecta ataques de respuesta inactivos

Para detectar ataques de respuesta inactivos, recomendamos filtrar las respuestas con una marca de tiempo que difiere significativamente de la hora del sistema después de considerar las diferencias de zona horaria. Nuestros servidores están configurados en hora PST/PDT.

Para obtener detalles de implementación, consulta "Cómo detectar ataques de respuesta inactiva" en el artículo Desencriptar confirmaciones de precio.

Biblioteca Java

En lugar de implementar los algoritmos criptográficos para codificar y decodificar los indicadores de orientación hiperlocales, puedes usar DoubleClickCrypto.java. Para obtener más información, consulta Criptografía.