Hi Stephen,
Thanks again for all the good stuff.
After I started working on a project using SqlCipher for sqlite encryption (on Windows, via MSVC), I realized some things:
**********************************************
1) I wanted to be able to rebuild the library myself when a new version of sqlite comes out, or with a version of sqlite that a SqlCipher version was not published against.
2) I wanted to be able to customize certain things, such as:
a. What crypto library I use. In my case, I wasn't happy adding 500K for openssl to the size of my executable when all I needed was a key derivation function and one or two encryption algorithms, or if I found an algorithm that I liked that had acceptable security but was faster than openssl's AES.
b. Whether I want to use a passphrase + kdf, versus just storing an encryption key in binary format or generating one at runtime from known values with the goal of obfuscating the binary. In my case, this is not a "user sets the passphrase" scenario, but rather a "use doesn't own the data" scenario. Storing a passphrase in plaintext makes it easier to reverse, so I don’t want to use a passphrase. Keep in mind here that in my use cases, reversing of the executable is by far the weaker vulnerability than reversing the encryption (even relatively weak encryption).
c. What random function I want to use to generate initialization vectors on the database pages, or whether I want to use them at all, or want to derive them from, say, the page number.
d. How big I want the encryption key, initialization vector, etc. to be.
3) I wanted to better understand how SqlCipher integrated with the sqlite code.
4) I wanted to be able to try different implementations and generate performance metrics.
**********************************************
So, I’ve restructured the code in the following ways…
**********************************************
1) I always now start with a plain sqlite amalgamated build.
2) To sqlite3.c, I:
a. Add #include “stdafx.h” at the very top of the file
b. Add #include “crypto.h” at the very end of the file
3) Create a new file, stdafx.h, in the same folder as sqlite3.c. (I actually just copy this file from a previous sqlite encryption project as a starting point). My base file is:
#pragma once
#define WIN32_LEAN_AND_MEAN
#define SQLITE_ENABLE_COLUMN_METADATA
#define SQLITE_API __declspec(dllexport)
#define SQLITE_DEFAULT_PAGE_SIZE 4096
#define SQLITE_HAS_CODEC
4) Place the attached crypto.h in the same folder as sqlite3.c.
a. This file is included at the bottom of sqlite3.c per #2b above.
b. This file provides implementation of the six or seven sqlite functions that must be defined when SQLITE_HAS_CODEC is defined during compilation.
c. The main features of this crypto.h are simplicity and dependency injection.
d. This is all boilerplate code that has been trimmed down to minimum requirements.
e. The things that can be done entirely boilerplate are implemented entirely in this file.
f. This file never changes from build to build of sqlite.
g. The dependency injection comes from the following functions that are declared in crypto.h but are not defined:
void CodecLibraryInitialize(void); // initialize crypto library, if needed
int CodecInitialize(struct Db*, codec_ctx* pCtx); // further initialize codec/cipher beyond defaults
int CodecKeySize(); // tell us the length of the encryption key (in bytes)
int CodecIvSize(); // tell us the size of the initialization vector on each database page
int CodecDeriveKey(const char* szPassphrase, int nPassphrase,
const unsigned char* pSalt, int nSalt,
unsigned char* pKey, int nKey); // generate an encryption key/length, returned in pKey, nKey
void CodecRandomness(int nBytes, void* pBuf); // generate pseudorandom bytes into buffer
void CodecFree(void* p); // free codec state data
int CodecEncryptDecrypt(codec_ctx* pCtx, Pgno pgNo, int mode,
int bufSize, unsigned char* in,
unsigned char* out); // encrypt/decrypt
h. At the bottom of this file is an include, #include “cryptoimpl.h”
5) I then create a file cryptoimpl.h in the same folder as sqlite3.c (again, copied from a base template or a previous project), and implement the 8 functions declared in 4f above (some of these may be empty implementations).
This approach has worked quite nicely for me. It gives me a clear definition of what functions I need to implement in what ways to enable/disable/alter behaviors. For example, CodecIvSize() can return 0 to decide that there is no initialization vector on the database pages. I can also use whatever crypto library or crypto functions I want to use to implement key derivation, random pseudobytes, and encryption/decryption. I can even use a C++ library if I handle the C/C++ linkage issues correctly. A sample cryptoimpl.h is attached to this e-mail along with crypto.h. I’ve also tried to use function names such that: a) All callbacks start with Codec. b) No functions except those that are part of sqlite (declared in sqlite) start with sqlite. c) Functions pointed to via the call to sqlite3PagerSetCodec start with “X” (XCodec and XCodecFree). d) Unnecessary functions that could be manually inlined were removed.
Some attempts at simplification have been made. For example, in sqliteCodecAttach, I assume that a negative nKey means that a binary encryption key is being passed rather than a passphrase. The passphrase itself is never stored anywhere in memory after a key is derived from it.
The one thing that is left out using this approach is the pragma support, which would require editing the sqlite3.c amalgamation at the location where pragma.c is spliced into the file. Since I don’t need pragma support (I am the only user of these databases; end users do not have the ability to run queries directly), I prefer to leave this out to help keep the build/implementation process simple.
During the work on this, I’ve learned a lot about sqlite and SqlCipher; it’s been fun.
Just throwing this out there in case there are any ideas you might want to integrate into SqlCipher. Anyone who finds anything here useful is free to use whatever they like completely free of any license or copyright and without any guarantees or warranties.
Thanks,
~Mike Stephenson
Also check that you are compiling/linking sqlite3.c with C linkage and not C++.
>Error 1 error C2037: left of 'pBt' specifies undefined struct/union 'Btree' c:\Qt\4.7.0\src\plugins\sqldrivers\sqlcipher\sqlite3.c 44924 qsqlcipher
means that the definition of struct Btree is missing. You could search sqlite3.c for "struct Btree". It should be typedef'd near the top of the file and then actually defined somewhere not too far above the line with the error.
In my plain sqlite amalgamation (not SqlCipher), the definition of struct Btree comes in from the file btreeInt.h. I see these comments in my plain sqlite3.c a couple hundred lines above the struct Btree definition:
/************** Include btreeInt.h in the middle of btmutex.c ****************/
/************** Begin file btreeInt.h ****************************************/
It sounds like btreeInt.h may not have been properly inserted into the amalgamation when it was built via configure.
If someone has a known-good sqlite3.c, a diff would show the problem quickly. I would try to provide a known-good, but at the moment cygwin and msys are crashing on my windows machine and are not functional.
-----Original Message-----
From: sqlc...@googlegroups.com [mailto:sqlc...@googlegroups.com] On Behalf Of Aleksey Kontsevich
Sent: Thursday, December 16, 2010 11:16 PM
To: SQLCipher Users
Subject: Re: How to build sqlcipher using Visual C++?
-----Original Message-----
From: sqlc...@googlegroups.com [mailto:sqlc...@googlegroups.com] On Behalf Of Aleksey Kontsevich
Sent: Thursday, December 16, 2010 8:38 PM
To: SQLCipher Users
#pragma once
#define SQLITE_ENABLE_COLUMN_METADATA
#ifdef Q_WS_WIN
#define WIN32_LEAN_AND_MEAN
#define SQLITE_API __declspec(dllexport)
#endif
#define SQLITE_DEFAULT_PAGE_SIZE 4096
#define SQLITE_HAS_CODEC