Skip to content

Instantly share code, notes, and snippets.

@nero120
Last active January 20, 2023 17:26
Show Gist options
  • Save nero120/e878e40b14655c9526680472376b4f8c to your computer and use it in GitHub Desktop.
Save nero120/e878e40b14655c9526680472376b4f8c to your computer and use it in GitHub Desktop.
A Node.js script to decrypt xBrowserSync sync data.
const crypto = require('crypto');
const lzutf8 = require('lzutf8');
const util = require('util');
const pbkdf2 = util.promisify(crypto.pbkdf2);
async function getPasswordHash(password, syncId) {
// Generate pbkdf2 key and return as base64 string
const encoder = new util.TextEncoder('utf-8');
const keyData = encoder.encode(password);
const salt = encoder.encode(syncId);
const derivedKey = await pbkdf2(keyData, salt, 250000, 32, 'sha256');
const keyString = derivedKey.toString('base64');
return keyString;
}
async function decryptData(key, encryptedBookmarks) {
// Get the required data arrays for decryption
const keyData = Uint8Array.from(Buffer.from(key, 'base64'));
const encrypted_bytes = Uint8Array.from(Buffer.from(encryptedBookmarks, 'base64'));
const iv = encrypted_bytes.slice(0, 16);
const tag = encrypted_bytes.slice(-16);
const enc = encrypted_bytes.slice(16, encrypted_bytes.length - 16);
// Run decryption and return buffer
const decipher = crypto.createDecipheriv('aes-256-gcm', keyData, iv, { authTagLength: 16 });
decipher.setAuthTag(tag);
const decrypted = Buffer.concat([decipher.update(enc), decipher.final()]);
return decrypted;
}
(async () => {
// The raw entered password (50 characters in my case)
const plainTextPassword = 'asd';
// The sync ID extracted from the xbrowsersync UI (32 characters)
const syncId = 'bdf7b0a552c347cc8479a7b287a43c00';
// Encrypted bookmarks, extracted for testing from Chrome
const encryptedBookmarks = `dsAxxN4gQHvsr/5BPF8F1G84oxlTroAbDX++ha8JgHJgjE8iXvQH2+7t3daG3r2WPsmLRS/KWdc/FwntiAYqSZIzQQQn6VcKYFVCdA/ZeSjZhxYh3SnG8i/FA6zgI/hBWvbk4W/xgW14tvA1lNGHAYFU6ZAXhOlR`;
// Generate the password hash
const key = await getPasswordHash(plainTextPassword, syncId);
// Decrypt the encrypted data using password hash
const decryptedData = await decryptData(key, encryptedBookmarks);
// Decompress the decrypted data to it's original json and beautify
const decryptedJson = lzutf8.decompress(decryptedData);
const beautifiedJson = JSON.stringify(JSON.parse(decryptedJson), null, 2);
console.log(beautifiedJson);
})();
{
"name": "xbrowsersync-node-decryption",
"version": "1.0.0",
"description": "A Node.js script to decrypt xBrowserSync sync data.",
"main": "index.js",
"dependencies": {
"lzutf8": "^0.5.5"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment