As redes de publicidade que usam
tags JavaScript para preencher anúncios por meio do Authorized Buyers estão qualificadas para
receber identificadores de anunciantes para dispositivos Android e iOS.
As informações são enviadas pela macro %%EXTRA_TAG_DATA%%
ou
%%ADVERTISING_IDENTIFIER%%
na tag JavaScript gerenciada
pelo Authorized Buyers. O restante desta seção se concentra na extração de %%EXTRA_TAG_DATA%%
. Consulte
Remarketing com IDFA ou ID de publicidade para mais detalhes sobre o buffer proto criptografado %%ADVERTISING_IDENTIFIER%%
MobileAdvertisingId
que pode ser descriptografado de maneira análoga.
Cronograma
- A rede de publicidade atualiza as tags JavaScript no app
por meio da interface do Authorized Buyers,
adicionando a macro
%%EXTRA_TAG_DATA%%
, conforme explicado abaixo. - No momento da veiculação, o app solicita um anúncio do Authorized Buyers pelo SDK dos anúncios para dispositivos móveis do Google e transmite o identificador do anunciante de maneira segura.
- O app recebe de volta a tag JavaScript, com a macro
%%EXTRA_TAG_DATA%%
preenchida com o buffer de protocolo criptografado da rede de publicidade contendo esse identificador. - O app executa essa tag, fazendo uma chamada para a rede de publicidade do anúncio vencedor.
- Para usar (gerar receita) essas informações, a rede de publicidade precisa processar
o buffer de protocolo:
- Decodifique a string segura para Web novamente em uma string de bytes com WebSafeBase64.
- Descriptografe-o usando o esquema descrito abaixo.
- Desserialize o proto e receba o ID do anunciante de ExtraTagData.advertising_id ou ExtraTagData.hashed_idfa.
Dependências
- O codificador WebSafeBase64.
- Uma biblioteca de criptografia compatível com o HMAC SHA-1, como Openssl.
- O compilador de buffer de protocolo do Google.
Decodificar string segura da Web
Como as informações enviadas pela macro %%EXTRA_TAG_DATA%%
precisam ser enviadas por um URL, os servidores do Google as codificam com base64 segura para a Web (RFC 3548).
Antes de tentar descriptografar, é necessário decodificar os caracteres ASCII de volta em uma bytestring. O exemplo de código C++ abaixo é baseado na BIO_f_base64() do OpenSSL Project (link em inglês) e faz parte do exemplo de código de descriptografia do 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); }
Estrutura de bytestring criptografada
Depois de decodificar os caracteres ASCII de volta em uma string de bytes, você está pronto para descriptografá-los. Ela contém três seções:
initialization_vector
: 16 bytes.ciphertext
: série de seções de 20 bytes.integrity_signature
: 4 bytes.
{initialization_vector (16 bytes)}{ciphertext (20-byte sections)}{integrity_signature (4 bytes)}
A matriz de bytes ciphertext
é dividida em várias seções de 20 bytes, com a exceção de que a última seção pode conter entre
1 e 20 bytes. Para cada seção do byte_array
original, o ciphertext
de 20 bytes correspondente
é gerado como:
<byte_array <xor> HMAC(encryption_key, initialization_vector || counter_bytes)>
em que ||
é concatenação.
Definições
Variável | Detalhes |
---|---|
initialization_vector |
16 bytes: exclusivo da impressão. |
encryption_key |
32 bytes: fornecidos na configuração da conta. |
integrity_key |
32 bytes: fornecidos na configuração da conta. |
byte_array |
Um objeto ExtraTagData serializado, em seções de 20 bytes. |
counter_bytes |
Valor de byte mostrando o número ordinal da seção, conforme abaixo. |
final_message |
Matriz de bytes total enviada pela macro %%EXTRA_TAG_DATA%% (menos a codificação WebSafeBase64). |
Operadores | Detalhes |
---|---|
hmac(key, data) |
SHA-1 HMAC que usa key para criptografar data . |
a || b |
string a concatenada com a string b . |
Calcular contador_bytes
counter_bytes
marca a ordem de cada seção de 20 bytes do
ciphertext
. Observe que a última seção pode conter entre 1 e 20 bytes. Para preencher counter_bytes
com o valor correto
ao executar a função hmac()
, conte as seções de 20 bytes
(incluindo o restante) e use a seguinte tabela de referência:
Número da seção | Valor counter_bytes |
---|---|
0 | Nenhum |
1 ... 256 | 1 byte. O valor aumenta de 0 a 255 sequencialmente. |
257 ... 512 | 2 bytes. O valor do primeiro byte é 0, e o valor do segundo byte aumenta de 0 para 255 sequencialmente. |
513 ... 768 | 3 bytes. O valor dos dois primeiros bytes é 0. O valor do último byte é incrementado de 0 a 255 sequencialmente. |
Esquema de criptografia
O esquema de criptografia é baseado no mesmo esquema usado para descriptografar o indicador de segmentação hiperlocal.
Serialização: uma instância do objeto ExtraTagData, conforme definido no buffer de protocolo, é serializada primeiro por meio de
SerializeAsString()
para uma matriz de bytes.Criptografia: a matriz de bytes é então criptografada usando um esquema de criptografia personalizado projetado para minimizar a sobrecarga de tamanho e, ao mesmo tempo, garantir a segurança adequada. O esquema de criptografia usa um algoritmo HMAC com chave para gerar um preenchimento de chave secreta com base no
initialization_vector
, que é exclusivo do evento de impressão.
Pseudocódigo de criptografia
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
Esquema de descriptografia
Seu código de descriptografia precisa 1) descriptografar o buffer de protocolo usando a chave de criptografia e 2) verificar os bits de integridade com essa chave. As chaves serão fornecidas a você durante a configuração da conta. Não há restrições em como você estrutura a implementação. Na maioria das vezes, você precisa conseguir adaptar o exemplo de código de acordo com suas necessidades.
- Gere seu pad:
HMAC(encryption_key, initialization_vector || counter_bytes)
- XOR: use esse resultado e
<xor>
com o texto criptografado para reverter a criptografia. - Verificar: a assinatura de integridade transmite 4 bytes de
HMAC(integrity_key, byte_array || initialization_vector)
.
Pseudocódigo de descriptografia
// 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)
Exemplo de código C++
Incluída aqui está uma função de chave do nosso código de exemplo de descriptografia completo.
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'); } }
Obter dados do buffer de protocolo da rede de publicidade
Depois de decodificar e descriptografar os dados transmitidos em %%EXTRA_TAG_DATA%%
, é possível desserializar o buffer de protocolo e receber o identificador do anunciante para segmentação.
Se você não estiver familiarizado com buffers de protocolo, comece com nossa documentação.
Definição
O buffer de protocolo da rede de publicidade é definido assim:
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; }
Será necessário desserializá-lo usando ParseFromString()
, conforme descrito na
documentação do buffer de protocolo C++.
Para detalhes sobre os campos advertising_id
do Android e hashed_idfa
do iOS, consulte Descriptografar ID de publicidade e Como segmentar inventário de apps para dispositivos móveis com o IDFA.
Biblioteca Java
Em vez de implementar os algoritmos criptográficos para codificar e decodificar os identificadores de anunciante para redes de publicidade, você pode usar o DoubleClickCrypto.java. Para mais informações, consulte Criptografia.