رمزگشایی سیگنال های هدف گذاری Hyperlocal

اگر ناشران داده‌های موقعیت مکانی تلفن همراه را به خریداران مجاز ارسال کنند که از کد پستی خاص‌تر است، خریداران مجاز یک geofence «فوق محلی» را برای خریداران در یک فیلد رمزگذاری‌شده جدید ارسال می‌کنند: BidRequest.encrypted_hyperlocal_set .

جدول زمانی

  1. یک کاربر یک برنامه تلفن همراه با پشتیبانی آگهی نصب می‌کند و رضایت می‌دهد که برنامه به مکان دستگاه دسترسی داشته باشد و با اشخاص ثالث به اشتراک بگذارد. این برنامه همچنین با Google ads SDK یکپارچه شده است و موقعیت مکانی دستگاه را برای Google ارسال می کند.
  2. سرورهای Google یک سیگنال هدف گیری هایپرمحلی خاص را تولید می کنند که نشان دهنده یک geofence در اطراف مکان دستگاه است، مانند محافظت از حریم خصوصی کاربر.
  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 مکرر منتقل می شود.
  • مرکز هندسی تقریبی منطقه geofence، در قسمت اختیاری 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 ۲۰ بایتی مربوطه به صورت زیر تولید می‌شود:

<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 استفاده می‌کند که منحصر به رویداد impression است.

شبه رمزگذاری

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/PDT تنظیم شده اند.

برای جزئیات پیاده‌سازی، به «تشخیص حملات واکنش قدیمی» در مقاله تأییدیه‌های قیمت رمزگشایی مراجعه کنید.

کتابخانه جاوا

به جای پیاده سازی الگوریتم های رمزنگاری برای رمزگذاری و رمزگشایی سیگنال های هدف گذاری هایپرمحلی، می توانید از DoubleClickCrypto.java استفاده کنید. برای اطلاعات بیشتر، رمزنگاری را ببینید.