On our About page, we describe the guiding principles that have shaped Obsidian since the start. Privacy is one of these principles, and we go to great lengths to make sure we can uphold this statement:
We believe that your thoughts and ideas belong to you and deserve complete privacy. That’s why your data is stored on your device, inaccessible to us. When you use our online services, your data is protected with end-to-end encryption for maximum security.
When you use Obsidian Sync, your data is end-to-end encrypted. But how can you be sure that is true?
In this guide, we provide step-by-step instructions so that you can trustlessly verify the end-to-end encryption of your data when it is sent and received via our Sync servers.
Let’s review how Obsidian Sync encryption works:
In the next few steps, you’ll learn how to get your vault’s salt, and test the encryption of your data.
First, get the salt used to derive your encryption key by following these steps:
let data = await (await fetch('https://api.obsidian.md/vault/list', {method:'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({token: app.account.token})})).json();
let vaults = [].concat(data.shared, data.vaults);
let vault = vaults.find(v => v.id === app.internalPlugins.getEnabledPluginById('sync').vaultId);
console.log(`The salt of your vault ${vault.name} is: "${vault.salt}"`);
You should see a message containing your salt:
The salt of your vault Notes is: "8II2%?YeNpddlbd@4Z)c"
Next, find an example of a sync event and decrypt it. Here we will use the Network tab of Developers Tools. This is where all sync events are logged, so you can see data that is being sent and received by the Obsidian app, and confirm that it is using your encryption key.
sync-xx.obsidian.md
— you may need to reload Obsidian to see it.Copy message > Copy as Base64
.// Use the standard crypto package from NodeJS
let crypto = require('crypto');
// Enter your password, salt, and binary data as base64
let password = 'E@QAXVBo44PQtzS6EAyU';
let salt = '8II2%?YeNpddlbd@4Z)c';
let data = Buffer.from('ApLmsQVGwGHmjb7jM4G2ZXnl2+Wi8CJMZSbgCTvcBHendXw01iNw3oWQ8Y8gW1tS7f/OMly1n4KoNhjy', 'base64');
// Derive the encryption/decryption key from your password and salt
let key = crypto.scryptSync(Buffer.from(password.normalize('NFKC'), 'utf8'), Buffer.from(salt.normalize('NFKC'), 'utf8'),
32, {N: 32768, r: 8, p: 1, maxmem: 128 * 32768 * 8 * 2});
// Split up the data blob into the 12-bytes IV, the encrypted data, and the 16-bytes auth tag.
let iv = data.subarray(0, 12);
let encryptedData = data.subarray(12, data.length - 16);
let authTag = data.subarray(data.length - 16);
// Decrypt the data
let decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
decipher.setAuthTag(authTag);
let decrypted = Buffer.concat([decipher.update(encryptedData), decipher.final()]);
// Print it to a string
console.log(decrypted.toString('utf8'));
The data that is returned should be a revision of a file that was sent or received via the Obsidian Sync’s servers. That’s it! If it properly decrypts, you’ll know your encryption key is working.