m4heshd / better-sqlite3-multiple-ciphers

better-sqlite3 with multiple-cipher encryption support 🔒
MIT License
137 stars 27 forks source link

Question: how to know if given key is the right one ? #58

Closed NoxFly closed 11 months ago

NoxFly commented 11 months ago

Here a minimal example where script A is run 1 time, then script B is run after script A.

// script A
const sqlite = require('better-sqlite3-multiple-ciphers');

const db = sqlite('data.db', { fileMustExist: false });

db.pragma("key='my-secret'");

console.log(db);

db.prepare("CREATE TABLE test (field TEXT)").run();
db.prepare("INSERT INTO test (field) VALUES ('value')").run();

db.close();
// script B
const db = sqlite('data.db', { fileMustExist: false });

db.pragma("key='my-secret'");

console.log(db);

const data = db.prepare("SELECT * FROM test").all();
console.log(data); // [ { field: 'value' } ]

The 2 scripts will run well, and the data will be logged.

But, if in script B, I inform a wrong key, no error will be throw when connecting to the database. Instead, I'll have an error when I'll try to run a request, here the SELECT.

/home/noxfly/codes/nodejs/test/node_modules/better-sqlite3-multiple-ciphers/lib/methods/wrappers.js:7
        return this[cppdb].prepare(sql, this, false);
                           ^
SqliteError: file is not a database
    at Database.prepare (/home/noxfly/codes/nodejs/test/node_modules/better-sqlite3-multiple-ciphers/lib/methods/wrappers.js:5:21)
    at Object.<anonymous> (/home/noxfly/codes/nodejs/test/src/index.js:18:17)
    at Module._compile (node:internal/modules/cjs/loader:1218:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1272:10)
    at Module.load (node:internal/modules/cjs/loader:1081:32)
    at Module._load (node:internal/modules/cjs/loader:922:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    at node:internal/main/run_main_module:23:47 {
  code: 'SQLITE_NOTADB'
}

Node.js v18.13.0

The logs about the db variable are the same in the 2 cases :

Database {
    name: 'data.db',
    open: true,
    readonly: false,
    memory: false
}

If "file is not a database", then you should probably put open property to false.

I've read the all documentation, nothing is mentionned about this.

How have I to do ? Executing a request just to test that is not really apropriated.

m4heshd commented 11 months ago

Sorry about the late response. Not at my workstation these days.

That's an unfortunate side-effect of encryption. The engine itself doesn't know if it's even a database if it can't be decrypted because there's no way to distinct an encrypted database from a random file. I know for a fact that non-legacy SQLCipher leaves some headers unencrypted so the engine knows all the metadata for decrypting it but that's about it. It still wouldn't provide you with a descriptive error. You can observe this same behavior in programs like DB4S (SQLCipher version).

I inform a wrong key, no error will be throw when connecting to the database.

That's because no decryption happens when you run just the PRAGMA statement. Pages get decrypted when you actually need them, like when running a SELECT or when you need to make any kind of change to the database.

Executing a request just to test that is not really appropriated.

This is the only way to do it. Just run an inexpensive statement.

Closing the issue since this is expected behavior.