Skip to content

Instantly share code, notes, and snippets.

@MJ111
Last active August 12, 2020 05:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MJ111/9220e71a3545b156b44de8a055ffea86 to your computer and use it in GitHub Desktop.
Save MJ111/9220e71a3545b156b44de8a055ffea86 to your computer and use it in GitHub Desktop.
Google win price decrypter typescript version
function base64AddPadding(str: string) {
return str + Array((4 - str.length % 4) % 4 + 1).join('=');
}
// should set your encryption, integrity key
const e_key = Buffer.from([0x00, ...]);
const i_key = Buffer.from([0x00, ...]);
// https://developers.google.com/authorized-buyers/rtb/response-guide/decrypt-price
// https://github.com/google/openrtb-doubleclick/blob/master/doubleclick-core/src/main/java/com/google/doubleclick/crypto/DoubleClickCrypto.java
const decodeWinPriceFromGoogle = (win_price: string): number => {
if (win_price.length != 38) throw new Error('[INVALID_GOOGLE_WIN_PRICE_LENGTH] ' + win_price);
// Base64 padding characters are omitted.
// Add any required base64 padding (= or ==).
const win_price_valid_base64 = base64AddPadding(win_price);
// Web-safe decode, then base64 decode.
const websafe_encoded = win_price_valid_base64.replace('-', '+').replace('_', '/');
// enc_price := initVector(16 bytes) || E(payload)(8 bytes) || I(signature)(4 bytes)
const enc_price = Buffer.from(websafe_encoded, 'base64');
// Message is decoded but remains encrypted.
// Split up according to fixed lengths.
const iv = enc_price.slice(0, 16);
const price_pad = crypto.createHmac('sha1', e_key).update(iv).digest();
for (let i = 0; i < 8; ++i) {
enc_price[16 + i] ^= price_pad[i];
}
const sig = enc_price.readUInt32BE(24);
const conf_sig = crypto.createHmac('sha1', i_key)
.update(enc_price.slice(16, 24))
.update(iv)
.digest()
.readUInt32BE(0);
const success = (conf_sig === sig);
if (success) {
// win_price is CPI https://support.google.com/authorizedbuyers/answer/3187591?hl=en
const decoded_win_price = parseInt(enc_price.slice(16, 24).toString('hex'), 16) / 1000;
return decoded_win_price;
} else {
throw new Error('[INVALID_GOOGLE_WIN_PRICE] ' + win_price);
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment