Расшифровать сигналы гиперлокального таргетинга

Если издатели передают Авторизованным покупателям данные о мобильном местоположении, которые являются более точными, чем почтовый индекс, Авторизованные покупатели отправят покупателям «гиперлокальную» геозону в новом зашифрованном поле: BidRequest.encrypted_hyperlocal_set .

График

  1. Пользователь устанавливает поддерживаемое рекламой мобильное приложение и дает согласие на то, чтобы приложение получало доступ к местоположению устройства и делилось им с третьими лицами. Это приложение также интегрировано с Google Ads SDK и отправляет данные о местоположении устройства в Google.
  2. Серверы Google генерируют специальный сигнал гиперлокального таргетинга, представляющий геозону вокруг местоположения устройства, например, для защиты конфиденциальности пользователя.
  3. Серверы Google сериализуют и шифруют сигнал гиперлокального таргетинга с помощью ключа безопасности, характерного для каждого покупателя. Обратите внимание, что ваш участник торгов использует тот же ключ для расшифровки макроса WINNING_PRICE .
  4. Ваш участник торгов расшифровывает и десериализует сигнал гиперлокального таргетинга в буфер протокола. Затем ваш участник торгов может проанализировать сигнал и сделать соответствующую ставку.

Зависимости

Вам понадобится криптобиблиотека, поддерживающая SHA-1 HMAC, например Openssl .

Определение

Сигнал гиперлокального наведения определяется в прототипе следующим образом:

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

Каждый сигнал гиперлокального наведения содержит один или несколько многоугольников и центральную точку. Для каждого полигона сигнал гиперлокального наведения содержит:

  • Широта и долгота каждого угла многоугольника последовательно передаются как повторяющееся поле corners .
  • Приблизительный геометрический центр области геозоны, переданный в необязательном поле center_point .

Структура целевого сигнала

Зашифрованный сигнал гиперлокального таргетинга, содержащийся в BidRequest.encrypted_hyperlocal_set , состоит из 3 разделов:

  • initialization_vector : 16 байт.
  • ciphertext : последовательность 20-байтовых разделов.
  • integrity_signature : 4 байта.
{initialization_vector (16 bytes)}{ciphertext (20-byte sections)}{integrity_signature (4 bytes)}

Массив байтов ciphertext делится на несколько секций по 20 байт, за исключением того, что самая последняя секция может содержать от 1 до 20 байтов включительно. Для каждой секции исходного byte_array соответствующий 20-байтовый ciphertext генерируется как:

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

Где || является конкатенация.

Определения

Переменная Подробности
initialization_vector 16 байт - уникальный для оттиска.
encryption_key 32 байта - предоставляется при настройке учетной записи.
integrity_key 32 байта - предоставляется при настройке учетной записи.
byte_array Сериализованный объект HyperlocalSet в секциях по 20 байт.
counter_bytes Значение байта, показывающее порядковый номер раздела, см. ниже.
final_message Байтовый массив, отправленный через поле BidRequest.encrypted_hyperlocal_set .
Операторы Подробности
hmac(key, data) SHA-1 HMAC, использующий key для шифрования data .
a || b строка a объединенная со строкой b .

Вычислить counter_bytes

counter_bytes отмечает порядок каждого 20-байтового раздела ciphertext . Обратите внимание, что последний раздел может содержать от 1 до 20 байт включительно. Чтобы заполнить counter_bytes правильным значением при запуске функции hmac() , посчитайте 20-байтовые разделы (включая остаток) и используйте следующую справочную таблицу:

Номер раздела значение counter_bytes
0 Никто
1 … 256 1 байт. Значение увеличивается от 0 до 255 последовательно.
257 … 512 2 байта. Значение первого байта равно 0, значение второго байта последовательно увеличивается от 0 до 255.
513 … 768 3 байта. Значение первых двух байтов равно 0, значение последнего байта увеличивается от 0 до 255 последовательно.

Мы не ожидаем, что длина BidRequest.encrypted_hyperlocal_set превысит один килобайт, даже с учетом дальнейшего роста. Тем не менее, counter_bytes может быть настолько длинным, насколько это необходимо для поддержки гиперлокального целевого сигнала произвольной длины.

Схема шифрования

Схема шифрования сигнала гиперлокального таргетинга основана на той же схеме, которая используется для расшифровки подтверждения цены .

  1. Сериализация : сигнал гиперлокального таргетинга, который является экземпляром объекта HyperlocalSet, как определено в прототипе, сначала сериализуется через SerializeAsString() в массив байтов.

  2. Шифрование . Массив байтов затем шифруется с использованием пользовательской схемы шифрования, предназначенной для минимизации накладных расходов при обеспечении адекватной безопасности. Схема шифрования использует алгоритм HMAC с ключом для создания секретной панели на основе initialization_vector , уникального для события показа.

Псевдокод шифрования

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

Схема расшифровки

Ваш код дешифрования должен 1) расшифровать сигнал гиперлокального таргетинга с помощью ключа шифрования и 2) проверить биты целостности с помощью ключа целостности. Ключи будут предоставлены вам во время настройки учетной записи. Нет никаких ограничений на то, как вы структурируете свою реализацию. По большей части вы должны быть в состоянии взять пример кода и адаптировать его в соответствии с вашими потребностями.

  1. Создайте свой блокнот : HMAC(encryption_key, initialization_vector || counter_bytes)
  2. XOR : Возьмите этот результат и <xor> с зашифрованным текстом, чтобы отменить шифрование.
  3. Проверка : Подпись целостности проходит 4 байта HMAC(integrity_key, byte_array || initialization_vector)

Псевдокод расшифровки

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

Сюда включена ключевая функция из нашего полного примера кода расшифровки .

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

Пример гиперлокального сигнала и ключей

Чтобы протестировать и проверить свой код:

  1. Преобразуйте строку, содержащую 308 шестнадцатеричных символов, в массив из 154 байтов. Например, для следующей строки:
    E2014EA201246E6F6E636520736F7572636501414243C0ADF6B9B6AC17DA218FB50331EDB376701309CAAA01246E6F6E636520736F7572636501414243C09ED4ECF2DB7143A9341FDEFD125D96844E25C3C202466E6F6E636520736F7572636502414243517C16BAFADCFAB841DE3A8C617B2F20A1FB7F9EA3A3600256D68151C093C793B0116DB3D0B8BE9709304134EC9235A026844F276797
    
    преобразовать его в 154-байтовый массив следующим образом:
    const char serialized_result[154] = { 0xE2, 0x01, 0x4E, ... };
    
  2. Вызовите метод BidRequest.ParsePartialFromString() , чтобы десериализовать 154-байтовый массив в BidRequest протокола BidRequest.
    BidRequest bid_req;
    bid_req.ParsePartialFromString(serialzed_result);
    
  3. Убедитесь, что в BidRequest есть только 3 поля:
    • encrypted_hyperlocal_set
      Объявлено в сообщении BidReqeust .
    • encrypted_advertising_id
      Объявлено в сообщении BidReqeust.Mobile .
    • encrypted_hashed_idfa
      Объявлено в сообщении BidReqeust.Mobile .

    Например:

    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. Используйте следующий encryption_key и integrity_key , чтобы расшифровать 3 поля и убедиться, что вы правильно их расшифровали.
    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};
    

Обнаружение атак с устаревшим ответом

Чтобы обнаруживать атаки с устаревшими ответами, мы рекомендуем фильтровать ответы с отметкой времени, которая значительно отличается от системного времени, после учета разницы часовых поясов. Наши серверы настроены на время PST/PDT.

Подробнее о реализации см. в разделе «Обнаружение атак с устаревшим ответом» в статье « Расшифровка ценовых подтверждений ».

Java-библиотека

Вместо реализации криптоалгоритмов для кодирования и декодирования сигналов гиперлокального таргетинга вы можете использовать DoubleClickCrypto.java . Дополнительные сведения см. в разделе Криптография .