authy-extractor
Version:
Extract 2FA tokens from Authy
57 lines (56 loc) • 2.74 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const node_forge_1 = __importDefault(require("node-forge"));
// Got following functions from service workers
function isBase32(value) {
return value.replace(/-|\s/g, '').match(/^[a-zA-Z2-7]+=*$/) !== null;
}
function generatePBKDF2Key(password, salt, options) {
// eslint-disable-next-line no-param-reassign
if (options.decodeSalt)
salt = node_forge_1.default.util.hexToBytes(salt);
if (options.withoutEncoding) {
return node_forge_1.default.pkcs5.pbkdf2(password, salt, options.iterations, options.keySize);
}
return node_forge_1.default.pkcs5.pbkdf2(unescape(encodeURIComponent(password)), salt, options.iterations, options.keySize);
}
function decryptAESWithKey(key, value) {
const ivBuffer = node_forge_1.default.util.createBuffer(node_forge_1.default.util.decodeUtf8('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'));
const keyBuffer = node_forge_1.default.util.createBuffer(key);
const valueBuffer = node_forge_1.default.util.createBuffer(node_forge_1.default.util.decode64(value));
// forge.aes is deprecated, changed to forge.cipher.createDecipher
// const decryptionCypher = forge.aes.createDecryptionCipher(keyBuffer, "CBC");
// decryptionCypher.start(ivBuffer);
// decryptionCypher.update(valueBuffer);
// return decryptionCypher.finish() ? decryptionCypher.output.data : null;
const decipher = node_forge_1.default.cipher.createDecipher('AES-CBC', keyBuffer);
decipher.start({ iv: ivBuffer });
decipher.update(valueBuffer);
return decipher.finish() ? decipher.output.data : null;
}
function decryptAES(salt, password, value, withoutEncoding = false) {
const pbkdf2Key = generatePBKDF2Key(password, salt, {
iterations: 1000,
keySize: 32,
decodeSalt: false,
withoutEncoding,
});
return decryptAESWithKey(pbkdf2Key, value);
}
function decryptTokens(tokens, password) {
return tokens.reduce((decryptedTokens, token) => {
let decrypted = decryptAES(token.salt, password, token.encrypted_seed, false);
if (decrypted === null || !isBase32(decrypted)) {
decrypted = decryptAES(token.salt, password, token.encrypted_seed, true);
if (decrypted === null || !isBase32(decrypted)) {
return decryptedTokens;
}
}
decryptedTokens.push(Object.assign(Object.assign({}, token), { decrypted_seed: decrypted }));
return decryptedTokens;
}, []);
}
exports.default = decryptTokens;