View Source ExUid2

A library to interact with Unified ID2

It currently only handles the DSP part of UID2 (decrypting UID2 tokens in bid requests).

Installation

Add :ex_uid2 to the list of dependencies in mix.exs

def deps do
  [
      {:ex_uid2, "~> 0.1.0"}
  ]
end

Usage

Add the ExUid2 configuration to your application's config file:

import Config

config :ex_uid2,
  base_url: "https://uid2_operator_server.com",
  api_key: "your_api_key",
  secret_key: "your_secret_key"

Once started, the application will periodically request a fresh keyring from the configured UID2 operator server. Encrypted tokens can then be decrypted.

ExUid2.Dsp.decrypt_token(<redacted>)
{:ok,
 %ExUid2.Uid2{
   uid: <redacted>,
   established: ~U[2024-07-02 01:17:56.501Z],
   site_id: 11,
   site_key: %ExUid2.Keyring.Key{
     activates: 1717269873,
     created: 1717183473,
     expires: 1725909873,
     id: 2383,
     secret: <redacted>,
     keyset_id: nil
   },
   identity_scope: "UID2",
   identity_type: nil,
   advertising_token_version: 2,
   expires: ~U[2024-07-06 19:12:10.313Z]
 }}

If the keyring hasn't been properly fetched by the time a token decryption is attempted, an error tuple will be returned instead:

ExUid2.Dsp.decrypt_token(<redacted>)
{:error, :no_keyring_stored}

Token decryption specification

Since no specification for the token decryption protocol could be found, the decryption protocol has been found by reverse engineering the existing SDKs and may include errors and misconceptions, so this specification may be erroneous or incomplete, but has been shown to work for decoding encrypted UID2 tokens.

General flow

  1. A keyring is periocically updated by querying the /v2/key/sharing endpoint.
  2. The encrypted token envelope is fetched from the bid request
  3. The envelope is parsed to extract the token version, the master key ID, the master IV and the master payload
  4. The right key to decrypt the master payload is obtained by looking up the master key ID in the keyring.
  5. The master payload is decrypted using AES-256-CBC, the master key and the master IV.
  6. The decrypted master payload is parsed to extract the expiration timestamp, the site key ID, the identity IV and the identity payload.
  7. The expiration timestamp is checked to ensure the token is still valid.
  8. The right key to decrypt the identity is obtained by looking up the site key ID in the keyring.
  9. The indentity payload is decrypted using AES-256-CBC, the site key and the identity IV.
  10. The decrypted identity payload is parsed to extract the site ID, the identity length, the identity binary and the established timestamp.

/v2/key/sharing request

While the /v2/key/sharing endpoint is undocumented, The workflow to query UID2's endpoints is documented, the Encrypting Requests and Decrypting Responses documentation seem to apply there. It is what this library is doing.

Encrypted token envelope

Offset (bytes)Size (bytes)Description
01UID2 token version
14Master key ID. Must be uint32 big endian.
516Master 128-bit initialization vector (IV), which is used to randomize data encryption.
21NMaster Payload (encrypted)

Decrypted Master Payload

Offset (bytes)Size (bytes)Description
08Expiration time in milliseconds (Unix timestamp). Must be uint64 big endian.
84Site key ID. Must be uint32 big endian.
1216Identity 128-bit initialization vector (IV), which is used to randomize data encryption.

| 28 | N | Identity Payload (encrypted)

Decrypted Identity

Offset (bytes)Size (bytes)Description
04Site ID. Must be uint32 big endian.
44Length in bytes of ID binary. Must be uint32 big endian.
8NBase64-encoded ID binary (the actual user ID).
8 + N4Unknown.
12 + N8Time when the identity was established in milliseconds (Unix timestamp). Must be uint64 big endian.
20 + NMUnknown.