Skip to content

Instantly share code, notes, and snippets.

@hanchiang
Created May 28, 2023 12:34
Show Gist options
  • Save hanchiang/ae411d08cb238ccefa0aef4b2c2899e0 to your computer and use it in GitHub Desktop.
Save hanchiang/ae411d08cb238ccefa0aef4b2c2899e0 to your computer and use it in GitHub Desktop.
Reverse engineering cryptopanic.com API response
require('dotenv').config();
const CryptoJS = require("crypto-js");
const pako = require('pako');
const fs = require('fs');
const path = require('path');
const ENCRYPTION_KEY = process.env.CRYPTOPANIC_ENCRYPTION_KEY;
const CSRF_TOKEN = process.env.CRYPTOPANIC_CSRF_TOKEN;
function wordToByteArray(t, e) {
var n = [];
return (
e > 0 && n.push(t >>> 24),
e > 1 && n.push((t >>> 16) & 255),
e > 2 && n.push((t >>> 8) & 255),
e > 3 && n.push(255 & t),
n
);
}
function wordArrayToByteArray(t, e) {
t.hasOwnProperty("sigBytes") &&
t.hasOwnProperty("words") &&
((e = t.sigBytes), (t = t.words));
for (var n, s = [], i = 0; e > 0; )
(n = wordToByteArray(t[i], Math.min(4, e))),
(e -= n.length),
s.push(n),
i++;
return [].concat.apply([], s);
}
function normalizeDictList(t) {
var e = [];
return (
t.l.forEach(function (n) {
var s = {};
t.k.forEach(function (t, e) {
s[t] = n[e];
}),
e.push(s);
}),
e
);
}
// { words, sigBytes }
const key = CryptoJS.enc.Utf8.parse(ENCRYPTION_KEY);
// for posts
const postIvRaw = "news" + CSRF_TOKEN.substring(0, 12);
// for dashboard
const dashboardIvRaw = "newsrnlistrnlist";
const padding = CryptoJS.pad.ZeroPadding;
const postEncrypted = fs.readFileSync(path.join(__dirname, 'input', 'cryptopanic post data'), { encoding: 'utf-8' } );
const dashboardEncrypted = fs.readFileSync(path.join(__dirname, 'input', 'cryptopanic dashboard data'), { encoding: 'utf-8' });
const dataTypeMapping = {
post: {
iv: CryptoJS.enc.Utf8.parse(postIvRaw),
encrypted: postEncrypted
},
dashboard: {
iv: CryptoJS.enc.Utf8.parse(dashboardIvRaw),
encrypted: dashboardEncrypted
}
}
function decrypt(encrypted, key, iv, padding, dataType) {
// { words, sigBytes }
const decrypted = CryptoJS.AES.decrypt(encrypted, key, {
iv,
padding,
});
const byteArray = wordArrayToByteArray(decrypted);
try {
const inflated = pako.inflate(byteArray, { to: 'string' });
const inflatedJson = JSON.parse(inflated);
fs.writeFileSync(path.join(__dirname, 'decrypted', `${dataType}-inflatedRaw.json`), JSON.stringify(inflatedJson, undefined, 2));
const normalized = normalizeDictList(inflatedJson);
fs.writeFileSync(path.join(__dirname, 'decrypted', `${dataType}-normalized.json`), JSON.stringify(normalized, undefined, 2));
return normalized;
} catch(e) {
console.log(e);
}
}
// node decrypt.js
// dataType = 'post', 'dashboard'
if (require.main === module) {
let [_, __, dataType] = process.argv;
dataType = dataType ? dataType : 'post';
const decrypted = decrypt(dataTypeMapping[dataType].encrypted, key, dataTypeMapping[dataType].iv, padding, dataType);
console.log(decrypted);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment