Reklam Ağları için Reklamveren Tanımlayıcılarının Şifresini Çözme

Authorized Buyers aracılığıyla reklamları doldurmak üzere JavaScript etiketlerini kullanan Reklam Ağları, hem Android hem de iOS cihazlar için reklamveren tanımlayıcıları almaya uygundur. Bilgiler, Authorized Buyers tarafından yönetilen JavaScript etiketindeki %%EXTRA_TAG_DATA%% veya %%ADVERTISING_IDENTIFIER%% makrosu aracılığıyla gönderilir. Bu bölümün geri kalanında %%EXTRA_TAG_DATA%% ayıklama işlemine odaklanılır ancak benzer şekilde şifresi çözülebilen %%ADVERTISING_IDENTIFIER%%şifrelenmiş protokol arabelleğiMobileAdvertisingId ile ilgili ayrıntılar için IDFA veya Reklam Kimliği ile Yeniden Pazarlama bölümüne bakın.

Zaman çizelgesi

  1. Reklam Ağı, JavaScript uygulama içi etiketlerini Authorized Buyers kullanıcı arayüzü aracılığıyla günceller ve %%EXTRA_TAG_DATA%% makrosuna aşağıda açıklandığı gibi ekler.
  2. Uygulama, yayınlanma sırasında Google Mobile Ads SDK'sı aracılığıyla Authorized Buyers'dan reklam ister ve reklamveren tanımlayıcısını güvenli bir şekilde iletir.
  3. Uygulama, %%EXTRA_TAG_DATA%% makrosu bu tanımlayıcıyı içeren şifrelenmiş Reklam Ağı protokol arabelleği ile doldurularak JavaScript etiketini geri alır.
  4. Uygulama bu etiketi çalıştırarak kazanan reklam için Reklam Ağı'na bir çağrı yapar.
  5. Bu bilgileri kullanmak (para kazanmak) için Reklam Ağı'nın protokol arabelleğini işlemesi gerekir:
    1. WebSafeBase64 ile websafe dizesinin kodunu bayt dizesine geri döndürün.
    2. Aşağıda özetlenen şemayı kullanarak şifreyi çözün.
    3. Protoyu seri durumdan çıkarın ve ExtraTagData.advertising_id veya ExtraTagData.hashed_idfa'dan reklamveren kimliğini alın.

Bağımlılıklar

  1. WebSafeBase64 kodlayıcı.
  2. SHA-1 HMAC destekleyen bir şifreleme kitaplığı (ör. Openssl).
  3. Google protokol arabellek derleyicisi.

Websafe dizesinin kodunu çözme

%%EXTRA_TAG_DATA%% makrosu aracılığıyla gönderilen bilgilerin URL aracılığıyla gönderilmesi gerektiğinden, Google sunucuları bu bilgileri web için güvenli base64 (RFC 3548) ile kodlar.

Bu nedenle, şifre çözmeyi denemeden önce ASCII karakterlerinin kodunu bayt dizesine geri dönüştürmeniz gerekir. Aşağıdaki örnek C++ kodu, OpenSSL Projesi'nin BIO_f_base64() yöntemine dayanır ve Google'ın örnek şifre çözme kodunun bir parçasıdır.

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

Şifrelenmiş bayt dizesinin yapısı

ASCII karakterlerinin kodunu tekrar bir bayt dizesine dönüştürdükten sonra, şifresini çözmeye hazır olursunuz. Şifrelenmiş bayt dizesi 3 bölüm içerir:

  • initialization_vector: 16 bayt.
  • ciphertext: 20 baytlık bölüm dizisi.
  • integrity_signature: 4 bayt.
{initialization_vector (16 bytes)}{ciphertext (20-byte sections)}{integrity_signature (4 bytes)}

ciphertext bayt dizisi, birden fazla 20 baytlık bölüme ayrılır. Bunun istisnası, en son bölümün 1 ila 20 bayt (dahil) içerebilir. Orijinal byte_array öğesinin her bölümü için karşılık gelen 20 baytlık ciphertext şu şekilde oluşturulur:

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

Burada || birleştirmedir.

Tanımlar

Değişken Ayrıntılar
initialization_vector 16 bayt - gösterime özgüdür.
encryption_key 32 bayt (hesap kurulumunda sağlanır).
integrity_key 32 bayt (hesap kurulumunda sağlanır).
byte_array 20 baytlık bölümlerden oluşan serileştirilmiş ExtraTagData nesnesi.
counter_bytes Bölümün sıra numarasını gösteren bayt değeri (aşağıya bakın).
final_message %%EXTRA_TAG_DATA%% makrosu aracılığıyla gönderilen toplam bayt dizisi (eksi WebSafeBase64 kodlaması).
Operatörler Ayrıntılar
hmac(key, data) SHA-1 HMAC, data şifrelemesi için key kullanılıyor.
a || b a dizesi b dizesiyle birleştirildi.

Sayaç_baytlarını hesaplama

counter_bytes, ciphertext öğesinin her 20 baytlık bölümünün sırasını işaretler. Son bölümün toplam 1 ila 20 bayt içerebileceğini unutmayın. hmac() işlevinizi çalıştırırken counter_bytes öğesini doğru değerle doldurmak için 20 baytlık bölümleri (kalan kısmı dahil) sayın ve aşağıdaki başvuru tablosunu kullanın:

Bölüm numarası counter_bytes değer
0 Yok
1 ... 256 1 bayt. Değer art arda 0'dan 255'e yükselir.
257 ... 512 2 bayt. İlk baytın değeri 0'dır. İkinci baytın değeri ise sırayla 0'dan 255'e çıkar.
513 ... 768 3 bayt. İlk iki baytın değeri 0'dır. Son baytın değeri de sırayla 0'dan 255'e çıkar.

Başa dön

Şifreleme şeması

Şifreleme şeması, yerel mesafe hedefleme sinyalinin şifresini çözmek için kullanılan şemaya dayanır.

  1. Serileştirme: Protokol arabelleğinde tanımlanan ExtraTagData nesnesinin bir örneği önce SerializeAsString() ile bir bayt dizisine serileştirilir.

  2. Şifreleme: Bayt dizisi, daha sonra boyut ek yükünü en aza indirirken yeterli güvenlik sağlamak için tasarlanmış özel bir şifreleme şeması kullanılarak şifrelenir. Şifreleme şeması, gösterim etkinliğine özel olan initialization_vector değerini temel alan bir gizli tuş takımı oluşturmak için anahtarlı bir HMAC algoritması kullanır.

Şifreleme sözde kodu

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

Şifre çözme şeması

Şifre çözme kodunuz 1) şifreleme anahtarını kullanarak protokol arabelleğinin şifresini çözmeli ve 2) bütünlük anahtarıyla bütünlük bitlerini doğrulamalıdır. Anahtarlar size hesap kurulumu sırasında verilecektir. Uygulamanızı nasıl yapılandıracağınızla ilgili herhangi bir kısıtlama yoktur. Çoğunlukla, örnek kodu alıp ihtiyaçlarınıza göre uyarlayabilmeniz gerekir.

  1. Panonuzu oluşturun: HMAC(encryption_key, initialization_vector || counter_bytes)
  2. XOR: Şifrelemeyi geri almak için bu sonucu ve şifrelenmiş metinle birlikte <xor> alın.
  3. Doğrulama: Bütünlük imzası 4 bayt HMAC(integrity_key, byte_array || initialization_vector)

Şifre çözme sözde kodu

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

Örnek C++ kodu

Burada, eksiksiz şifre çözme örnek kodumuzdan bir anahtar işlevi bulunmaktadır.

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

Reklam Ağı protokol arabelleğinden veri alma

%%EXTRA_TAG_DATA%% içinde geçirilen verilerin kodunu çözdüğünüzde ve bu verilerin şifresini çözdükten sonra protokol arabelleğini seri durumdan çıkarmaya ve hedefleme için reklamveren tanımlayıcısını almaya hazırsınız demektir.

Protokol arabellekleri hakkında bilginiz yoksa dokümanlarımızı inceleyerek başlayın.

Tanım

Reklam Ağı protokol tamponu şu şekilde tanımlanır:

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

C++ protokol arabelleği dokümanlarında açıklandığı gibi ParseFromString() kullanarak bunu seri durumdan çıkarmanız gerekir.

Android advertising_id ve iOShashed_idfa alanlarıyla ilgili ayrıntılar için Reklam Kimliğinin Şifresini Çözme ve IDFA ile mobil uygulama envanterini hedefleme bölümlerine göz atın.

Java kitaplığı

Reklam ağları için Reklamveren Tanımlayıcılarını kodlamak ve kodunu çözmek üzere kripto algoritmalar uygulamak yerine DoubleClickCrypto.java'yı kullanabilirsiniz. Daha fazla bilgi için Kriptografi konusuna bakın.