Nếu nhà xuất bản chuyển dữ liệu vị trí trên thiết bị di động tới Authorized Buyers cụ thể hơn so với mã bưu chính, Authorized Buyers sẽ gửi khoanh vùng địa lý "người dùng cục bộ" cho người mua trong một trường mã hoá mới: BidRequest.encrypted_hyperlocal_set
.
Tiến trình
- Người dùng cài đặt một ứng dụng dành cho thiết bị di động chứa quảng cáo và đồng ý cho phép ứng dụng đó truy cập và chia sẻ thông tin vị trí của thiết bị với bên thứ ba. Ứng dụng này cũng được tích hợp với SDK quảng cáo của Google và gửi vị trí thiết bị này cho Google.
- Các máy chủ của Google tạo ra một tín hiệu nhắm mục tiêu siêu địa phương đặc biệt để đại diện cho một khoanh vùng địa lý xung quanh vị trí của thiết bị, chẳng hạn như để bảo vệ quyền riêng tư của người dùng.
- Máy chủ của Google chuyển đổi tuần tự và mã hóa tín hiệu nhắm mục tiêu siêu địa phương bằng cách sử dụng khóa bảo mật dành riêng cho từng người mua. Xin lưu ý rằng người đặt giá thầu của bạn dựa trên cùng một khóa để giải mã macro JCT_PRICE.
- Người đặt giá thầu sẽ giải mã và giải tuần tự hoá tín hiệu nhắm mục tiêu siêu địa phương vào vùng đệm giao thức. Sau đó, người đặt giá thầu có thể phân tích tín hiệu và đặt giá thầu cho phù hợp.
Phần phụ thuộc
Bạn sẽ cần một thư viện mật mã hỗ trợ SHA-1 HMAC, chẳng hạn như Openssl.
Định nghĩa
Tín hiệu nhắm mục tiêu siêu địa phương được xác định trong proto như sau:
// 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;
Mỗi tín hiệu nhắm mục tiêu siêu địa phương chứa một hoặc nhiều đa giác và một điểm giữa. Đối với mỗi đa giác, tín hiệu nhắm mục tiêu siêu địa phương chứa:
- Vĩ độ và kinh độ của mỗi góc của đa giác tuần tự, được chuyển dưới dạng một trường
corners
lặp lại. - Trung tâm hình học gần đúng của khu vực khoanh vùng địa lý, được chuyển vào trường
center_point
không bắt buộc.
Cấu trúc của tín hiệu nhắm mục tiêu
Tín hiệu nhắm mục tiêu siêu địa phương đã mã hoá có trong BidRequest.encrypted_hyperlocal_set
chứa 3 phần:
initialization_vector
: 16 byte.ciphertext
: chuỗi các phần có dung lượng 20 byte.integrity_signature
: 4 byte.
{initialization_vector (16 bytes)}{ciphertext (20-byte sections)}{integrity_signature (4 bytes)}
Mảng ciphertext
byte được chia thành nhiều phần 20 byte, ngoại trừ phần cuối cùng có thể chứa từ 1 đến 20 byte. Đối với mỗi phần của byte_array
gốc, ciphertext
20 byte tương ứng sẽ được tạo thành:
<byte_array <xor> HMAC(encryption_key, initialization_vector || counter_bytes)>
Trong đó ||
là phép nối.
Định nghĩa
Biến | Thông tin chi tiết |
---|---|
initialization_vector |
16 byte - duy nhất cho lượt hiển thị. |
encryption_key |
32 byte – được cung cấp khi thiết lập tài khoản. |
integrity_key |
32 byte – được cung cấp khi thiết lập tài khoản. |
byte_array |
Một đối tượng HyperlocalSet chuyển đổi tuần tự, trong các phần 20 byte. |
counter_bytes |
Giá trị byte hiển thị số thứ tự của phần, hãy xem bên dưới. |
final_message |
Mảng byte được gửi qua trường BidRequest.encrypted_hyperlocal_set . |
Toán tử | Thông tin chi tiết |
---|---|
hmac(key, data) |
HMAC SHA-1, sử dụng key để mã hoá data . |
a || b |
chuỗi a nối với chuỗi b . |
Tính toán đếm_byte
counter_bytes
đánh dấu thứ tự của mỗi phần 20 byte của ciphertext
. Xin lưu ý rằng mục cuối cùng có thể chứa từ 1 đến
20 byte. Để điền counter_bytes
vào đúng giá trị khi chạy hàm hmac()
, hãy đếm các phần 20 byte (bao gồm phần còn lại) và sử dụng bảng tham chiếu sau:
Mã số mục | Giá trị counter_bytes |
---|---|
0 | Không có |
1... 256 | 1 byte. Giá trị này tăng từ 0 đến 255. |
257 ... 512 | 2 byte. Giá trị của byte đầu tiên là 0, giá trị của byte thứ hai tăng từ 0 đến 255 theo tuần tự. |
513 ... 768 | 3 byte. Giá trị của hai byte đầu tiên là 0, giá trị của byte cuối cùng tăng từ 0 đến 255 theo tuần tự. |
Chúng tôi dự kiến độ dài của BidRequest.encrypted_hyperlocal_set
sẽ không vượt quá một kilobyte, thậm chí còn có tính đến sự phát triển hơn nữa. Tuy nhiên, counter_bytes
có thể miễn là cần thiết để hỗ trợ tín hiệu nhắm mục tiêu siêu địa phương có độ dài tùy ý.
Lược đồ mã hóa
Lược đồ mã hoá cho tín hiệu nhắm mục tiêu siêu địa phương dựa trên cùng một lược đồ dùng để giải mã giá xác nhận.
Tuần tự hoá: Tín hiệu nhắm mục tiêu siêu địa phương, là một thực thể của đối tượng HyperlocalSet như được xác định trong proto, sẽ được chuyển đổi tuần tự thông qua
SerializeAsString()
thành một mảng byte.Mã hoá: Mảng byte sau đó được mã hoá bằng lược đồ mã hoá tuỳ chỉnh được thiết kế để giảm thiểu mức hao tổn kích thước trong khi vẫn đảm bảo khả năng bảo mật đầy đủ. Giao thức mã hoá sử dụng thuật toán HMAC chính để tạo bảng điều khiển bí mật dựa trên
initialization_vector
, riêng cho sự kiện hiển thị.
Mã giả
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
Lược đồ giải mã
Mã giải mã của bạn phải 1) giải mã tín hiệu nhắm mục tiêu siêu địa phương bằng khoá mã hoá và 2) xác minh các bit tính toàn vẹn bằng khoá toàn vẹn. Khoá sẽ được cung cấp cho bạn trong quá trình thiết lập tài khoản. Không có hạn chế nào đối với cách bạn tổ chức triển khai của mình. Trong hầu hết trường hợp, bạn có thể lấy mã mẫu và điều chỉnh mã theo nhu cầu của mình.
- Tạo bàn phím di chuyển:
HMAC(encryption_key, initialization_vector || counter_bytes)
- XOR: Lấy kết quả này và
<xor>
bằng mật mã để đảo ngược phương thức mã hoá. - Xác minh: Chữ ký về tính toàn vẹn sẽ truyền 4 byte
HMAC(integrity_key, byte_array || initialization_vector)
Mã giả giải mã
(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)
Mã C++ mẫu
Sau đây là một hàm chính trong mã mẫu giải mã hoàn chỉnh của chúng tôi.
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'); } } }
Ví dụ về khóa và tín hiệu siêu địa phương
Để kiểm tra và xác minh mã của bạn:
- Chuyển đổi một chuỗi chứa 308 ký tự hex thành một mảng
154 byte. Ví dụ: giả sử chuỗi sau:
E2014EA201246E6F6E636520736F7572636501414243C0ADF6B9B6AC17DA218FB50331EDB376701309CAAA01246E6F6E636520736F7572636501414243C09ED4ECF2DB7143A9341FDEFD125D96844E25C3C202466E6F6E636520736F7572636502414243517C16BAFADCFAB841DE3A8C617B2F20A1FB7F9EA3A3600256D68151C093C793B0116DB3D0B8BE9709304134EC9235A026844F276797
hãy chuyển đổi nó thành một mảng 154 byte như sau:const char serialized_result[154] = { 0xE2, 0x01, 0x4E, ... };
- Gọi phương thức
BidRequest.ParsePartialFromString()
để giải tuần tự mảng 154 byte vào vùng đệm giao thứcBidRequest
.BidRequest bid_req; bid_req.ParsePartialFromString(serialzed_result);
- Xác minh rằng
BidRequest
chỉ có 3 trường:encrypted_hyperlocal_set
Được khai báo trong thông báoBidReqeust
.encrypted_advertising_id
Được khai báo trong thông báoBidReqeust.Mobile
.encrypted_hashed_idfa
Được khai báo trong thông báoBidReqeust.Mobile
.
Ví dụ:
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 }
- Sử dụng
encryption_key
vàintegrity_key
sau đây để giải mã 3 trường và xác minh rằng bạn giải mã chúng chính xác.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};
Phát hiện cuộc tấn công phản hồi cũ
Để phát hiện các cuộc tấn công phản hồi lỗi thời, bạn nên lọc các phản hồi có dấu thời gian khác đáng kể với thời gian của hệ thống sau khi tính đến chênh lệch múi giờ. Máy chủ của chúng tôi được đặt theo giờ PST/PDT.
Để biết thông tin chi tiết về cách triển khai, hãy xem bài viết "Phát hiện cuộc tấn công phản hồi cũ" trong bài viết Giải mã xác nhận giá.
Thư viện Java
Thay vì triển khai các thuật toán mã hoá để mã hoá và giải mã tín hiệu nhắm mục tiêu siêu cục bộ, bạn có thể sử dụng DoubleClickCrypto.java. Để biết thêm thông tin, hãy xem nội dung Mật mã.