I used sqlcipher_export(), exactly as specified here, to encrypt an existing Sqlite database. It all went fine – no errors, the resulting database is created and has a reasonable size. However, I am not able to open the encrypted database, even though I specify the correct key using PRAGMA key. Unencrypted databases open without problems.
Moreover, the encrypted database looks strange; the header seems to be encrypted, but not the data. See https://i.stack.imgur.com/HaBpS.png, it’s an image showing binary comparison between encrypted (left) and unencrypted (right) databases.
In the debugger I can see that, during the encryption, the program goes through sqlcipher_page_cipher(), but most of the time (every time except for 2 invocations) the following clause is executed, and the function returns early:
/* just copy raw data from in to out when key size is 0
* i.e. during a rekey of a plaintext database */
if(c_ctx->key_sz == 0) {
memcpy(out, in, size);
return SQLITE_OK;
}
SQL issued during encryption:
ATTACH DATABASE 'encrypted.db' AS encrypted KEY '12345';
SELECT sqlcipher_export('encrypted');
DETACH DATABASE encrypted;
SQL issued during opening:
// open database
PRAGMA key = '12345';
// try to read database - "file is encrypted or not a database"
CODEC_TRACE logs generated during encryption and decryption are here.
(In case it is important how I compiled Sqlcipher: I created an Sqlcipher amalgamation on a Linux machine, copied the resulting C file to a Windows machine, compiled it in Visual C++ Express, and linked to a precompiled OpenSSL DLL.)
Root cause: Calls to OpenSSL’s
HMAC_Init_ex()insqlcipher_page_hmac()corrupted memory that belonged toc_ctx->key_sz, setting it to zero.c_ctx->key_szwas adjacent to a parameter passed toHMAC_Init_ex(). (Details can be found in one of the comments to the original post.) This causedsqlcipher_page_cipher()to write plaintext pages to the encrypted file, instead of encrypted pages. Which didn’t make sense and made the resulting database unusable.Upgrading OpenSSL from 0.9.8k to 1.0.0i fixed the problem.