فك تشفير إشارات الاستهداف المحلي

إذا مرَّر الناشرون بيانات الموقع الجغرافي المتوافق مع الأجهزة الجوّالة إلى "الشراة المعتمَدون" الأكثر تحديدًا من الرمز البريدي، سيرسل "الشراة المعتمَدون" الجغرافي إلى المشترين عبر حقل مشفّر جديد: BidRequest.encrypted_hyperlocal_set.

المخطط الزمني

  1. يثبّت المستخدم تطبيقًا متوافقًا مع الإعلانات متوافقًا مع الأجهزة الجوّالة ويوافق على وصول التطبيق إلى الموقع الجغرافي للجهاز ومشاركته مع أطراف ثالثة. وهذا التطبيق مُدمج أيضًا مع حزمة تطوير البرامج (SDK) في "إعلانات Google"، ويرسل هذا الموقع الجغرافي إلى Google.
  2. تُنشئ خوادم Google إشارة استهداف محلية خاصة تمثّل جدارًا جغرافيًا تحيط بموقع الجهاز الجغرافي، كحماية خصوصية المستخدم.
  3. تعمل خوادم Google على إنشاء تسلسل وإشارة إشارة استهداف محلية باستخدام مفتاح الأمان الخاص بكل مشترٍ. تذكّر أنّ نظام عروض الأسعار يعتمد على المفتاح نفسه لفك تشفير وحدة ماكرو WinNING_PRICE.
  4. يك ويمكن عندئذٍ لنظام عروض الأسعار الخاص بك تحليل الإشارة وعرض الأسعار وفقًا لذلك.

المهام التابعة

ستحتاج إلى مكتبة مشفّرة تتوافق مع خوارزمية SHA-1 HMAC، مثل Openssl.

التعريف

يتم تحديد إشارة استهداف محلية عالية في Proto على النحو التالي:

// 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، يتم إنشاء ciphertext بحجم 20 بايت على النحو التالي:

<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 MAC، باستخدام key لتشفير data
a || b السلسلة a مرتبطة بسلسلة b.

حساب Count_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 كما هو محدّد في Proto، يتم تسلسلها أولاً من خلال 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 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/توقيت المحيط الهادئ الصيفي.

للحصول على تفاصيل التنفيذ، يُرجى الاطّلاع على مقالة "اكتشاف هجمات الاستجابة القديمة" في مقالة فك تشفير الأسعار.

مكتبة Java

بدلاً من تنفيذ خوارزميات التشفير لتشفير وفك ترميز إشارات الاستهداف المحلي، يمكنك استخدام DoubleClickCrypto.java. لمزيد من المعلومات، راجِع التشفير.