Mendekripsi ID Pengiklan untuk Jaringan Iklan

Jaringan Iklan yang menggunakan tag JavaScript untuk mengisi iklan melalui Authorized Buyers memenuhi syarat untuk menerima ID pengiklan untuk perangkat Android dan iOS. Informasi ini dikirim melalui makro %%EXTRA_TAG_DATA%% atau %%ADVERTISING_IDENTIFIER%% di tag JavaScript yang dikelola oleh Authorized Buyers. Bagian lainnya berfokus pada ekstraksi %%EXTRA_TAG_DATA%%, tetapi lihat Pemasaran ulang dengan IDFA atau ID Iklan untuk detail tentang buffering proto terenkripsi %%ADVERTISING_IDENTIFIER%% MobileAdvertisingId yang dapat didekripsi secara analog.

Rentang waktu

  1. Jaringan Iklan memperbarui tag dalam aplikasi JavaScript-nya melalui UI Authorized Buyers, dengan menambahkan makro %%EXTRA_TAG_DATA%% seperti yang dijelaskan di bawah.
  2. Pada waktu penayangan, aplikasi akan meminta iklan dari Authorized Buyers melalui Google Mobile Ads SDK, sekaligus meneruskan ID pengiklan dengan aman.
  3. Aplikasi akan menerima kembali tag JavaScript, dengan makro %%EXTRA_TAG_DATA%% yang diisi dengan buffering protokol Jaringan Iklan terenkripsi yang berisi ID tersebut.
  4. Aplikasi menjalankan tag ini, sehingga melakukan panggilan ke Jaringan Iklan untuk iklan pemenang.
  5. Untuk menggunakan (memonetisasi) informasi ini, Jaringan Iklan harus memproses buffering protokol:
    1. Dekode string websafe kembali menjadi bytestring dengan WebSafeBase64.
    2. Dekripsinya menggunakan skema yang diuraikan di bawah ini.
    3. Lakukan deserialisasi proto dan dapatkan ID pengiklan dari ExtraTagData.advertising_id atau ExtraTagData.hashed_idfa.

Dependensi

  1. WebSafeBase64 encoder.
  2. Library kripto yang mendukung HMAC SHA-1, seperti Openssl.
  3. Compiler buffer protokol Google.

Mendekode string websafe

Karena informasi yang dikirim melalui makro %%EXTRA_TAG_DATA%% harus dikirim melalui URL, server Google mengenkodenya dengan base64 yang aman untuk web (RFC 3548).

Oleh karena itu, sebelum mencoba dekripsi, Anda harus mendekode karakter ASCII kembali ke bytestring. Contoh kode C++ di bawah ini didasarkan pada BIO_f_base64() Project OpenSSL, dan merupakan bagian dari kode dekripsi contoh Google.

string AddPadding(const string& b64_string) {
  if (b64_string.size() % 4 == 3) {
    return b64_string + "=";
  } else if (b64_string.size() % 4 == 2) {
    return b64_string + "==";
  }
  return b64_string;
}

// Adapted from http://www.openssl.org/docs/man1.1.0/crypto/BIO_f_base64.html
// Takes a web safe base64 encoded string (RFC 3548) and decodes it.
// Normally, web safe base64 strings have padding '=' replaced with '.',
// but we will not pad the ciphertext. We add padding here because
// openssl has trouble with unpadded strings.
string B64Decode(const string& encoded) {
  string padded = AddPadding(encoded);
  // convert from web safe -> normal base64.
  int32 index = -1;
  while ((index = padded.find_first_of('-', index + 1)) != string::npos) {
    padded[index] = '+';
  }
  index = -1;
  while ((index = padded.find_first_of('_', index + 1)) != string::npos) {
    padded[index] = '/';
  }

  // base64 decode using openssl library.
  const int32 kOutputBufferSize = 256;
  char output[kOutputBufferSize];

  BIO* b64 = BIO_new(BIO_f_base64());
  BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
  BIO* bio = BIO_new_mem_buf(const_cast(padded.data()),
                             padded.length());
  bio = BIO_push(b64, bio);
  int32 out_length = BIO_read(bio, output, kOutputBufferSize);
  BIO_free_all(bio);
  return string(output, out_length);
}

Struktur bytestring terenkripsi

Setelah mendekode karakter ASCII kembali menjadi string byte, Anda siap untuk mendekripsinya. Bytestring terenkripsi berisi 3 bagian:

  • initialization_vector: 16 byte.
  • ciphertext: serangkaian bagian yang berukuran 20 byte.
  • integrity_signature: 4-byte.
{initialization_vector (16 bytes)}{ciphertext (20-byte sections)}{integrity_signature (4 bytes)}

Array byte ciphertext dibagi menjadi beberapa bagian 20 byte, dengan pengecualian bahwa bagian terakhir dapat berisi antara 1 dan 20 byte secara inklusif. Untuk setiap bagian byte_array asli, ciphertext 20 byte yang sesuai akan dihasilkan sebagai:

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

dengan || adalah penyambungan.

Definisi

Variabel Detail
initialization_vector 16 byte - unik untuk tayangan.
encryption_key 32 byte - disediakan saat pembuatan akun.
integrity_key 32 byte - disediakan saat pembuatan akun.
byte_array Objek ExtraTagData serial, dalam bagian 20 byte.
counter_bytes Nilai byte yang menunjukkan nomor ordinal bagian, lihat di bawah.
final_message Total array byte yang dikirim melalui makro %%EXTRA_TAG_DATA%% (dikurangi encoding WebSafeBase64).
Operator Detail
hmac(key, data) HMAC SHA-1, menggunakan key untuk mengenkripsi data.
a || b string a yang disambungkan dengan string b.

Menghitung penghitung_byte

counter_bytes menandai urutan setiap bagian 20 byte dari ciphertext. Perhatikan bahwa bagian terakhir dapat berisi antara 1 dan 20 byte inklusif. Untuk mengisi counter_bytes dengan nilai yang benar saat menjalankan fungsi hmac(), hitung bagian 20 byte (termasuk sisanya) dan gunakan tabel referensi berikut:

Nomor bagian Nilai counter_bytes
0 Tidak ada
1 ... 256 1 byte. Nilai bertambah dari 0 hingga 255 secara berurutan.
257 ... 512 2 byte. Nilai byte pertama adalah 0. Nilai byte kedua bertambah dari 0 hingga 255 secara berurutan.
513 ... 768 3 byte. Nilai dua byte pertama adalah 0, nilai byte terakhir meningkat dari 0 hingga 255 secara berurutan.

Kembali ke atas

Skema enkripsi

Skema enkripsi didasarkan pada skema yang sama yang digunakan untuk mendekripsi sinyal penargetan hyperlocal.

  1. Serialisasi: Instance objek ExtraTagData seperti yang ditentukan dalam buffering protokol akan diserialisasi terlebih dahulu melalui SerializeAsString() ke array byte.

  2. Enkripsi: Array byte kemudian dienkripsi menggunakan skema enkripsi kustom yang dirancang untuk meminimalkan overhead ukuran sekaligus memastikan keamanan yang memadai. Skema enkripsi menggunakan algoritma HMAC dengan kunci untuk menghasilkan pad rahasia berdasarkan initialization_vector, yang unik untuk peristiwa tayangan.

Kode semu enkripsi

byte_array = SerializeAsString(ExtraTagData 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

Skema dekripsi

Kode dekripsi Anda harus 1) mendekripsi buffering protokol menggunakan kunci enkripsi, dan 2) memverifikasi bit integritas dengan kunci integritas. Kunci akan diberikan kepada Anda selama pembuatan akun. Tidak ada batasan pada cara Anda menyusun implementasi. Secara umum, Anda harus dapat mengambil kode contoh dan menyesuaikannya sesuai dengan kebutuhan.

  1. Membuat pad Anda: HMAC(encryption_key, initialization_vector || counter_bytes)
  2. XOR: Ambil hasil ini dan <xor> dengan teks cipher untuk membalikkan enkripsi.
  3. Memverifikasi: Tanda tangan integritas meneruskan 4 byte HMAC(integrity_key, byte_array || initialization_vector)

Kode semu dekripsi

// split up according to length rules
(initialization_vector, ciphertext, integrity_signature) = final_message

// for each 20-byte section of ciphertext
pad = hmac(encryption_key, initialization_vector || counter_bytes)

// for each 20-byte section of ciphertext
byte_array = ciphertext <xor> pad

confirmation_signature = hmac(integrity_key, byte_array ||
                         initialization_vector)
success = (confirmation_signature == integrity_signature)

Contoh kode C++

Fungsi kunci dari kode contoh dekripsi lengkap kami disertakan di sini.

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

Mendapatkan data dari buffering protokol Jaringan Iklan

Setelah mendekode dan mendekripsi data yang diteruskan di %%EXTRA_TAG_DATA%%, Anda siap mendeserialisasi buffering protokol dan mendapatkan ID pengiklan untuk penargetan.

Jika Anda tidak terbiasa dengan buffering protokol, mulai dengan dokumentasi kami.

Definisi

Buffering protokol Jaringan Iklan kita didefinisikan seperti ini:

message ExtraTagData {
  // advertising_id can be Apple's identifier for advertising (IDFA)
  // or Android's advertising identifier. When the advertising_id is an IDFA,
  // it is the plaintext returned by iOS's [ASIdentifierManager
  // advertisingIdentifier]. For hashed_idfa, the plaintext is the MD5 hash of
  // the IDFA.  Only one of the two fields will be available, depending on the
  // version of the SDK making the request.  Later SDKs provide unhashed values.
  optional bytes advertising_id = 1;
  optional bytes hashed_idfa = 2;
}

Anda harus melakukan deserialisasi menggunakan ParseFromString() seperti yang dijelaskan dalam dokumentasi buffering protokol C++.

Untuk mengetahui detail tentang kolom advertising_id Android dan iOS hashed_idfa, lihat Mendekripsi ID Iklan dan Menargetkan inventaris aplikasi seluler dengan IDFA.

Library Java

Daripada menerapkan algoritma kripto untuk mengenkode dan mendekode ID Pengiklan untuk jaringan iklan, Anda dapat menggunakan DoubleClickCrypto.java. Untuk informasi selengkapnya, lihat Kriptografi.