How I got SQLCipher working with Electron on macOS:
- First compile SQLCipher and dynamically link it to macOS' crypto libraries. Don't use OpenSSL. Zetetic (makers of SQLCipher) say that using macOS' crypto libraries is definitely going to be easiest on a Mac. Note that using SQLCipher libraries installed via Homebrew is going to seem like it works, and it will on your computer, but Homebrew's SQLCipher dynamcially links OpenSSL, so your app will crash when deployed to other computers (i.e. dynamic linking will fail at run timer because other computer wont have OpenSSL installed). So you want to dynamically link macOS crypto.
- Then you want to rebuild node-sqlite3 with a modified binding.gyp so that the SQLCipher library is statically linked into your SQLite binding. You should end up with a binary file ./node_modules/sqlite3/lib/binding/electron-v3.0-darwin-x64/node_sqlite3.node that has libsqlcipher.a statically linked within it. The statically linked libsqlcipher.a will in-turn dynamically link macOS' libcrypto.
- So in summary: dynamically link macOS' libcrypto when compiling SQLCipher, and statically link libsqlcipher when compiling (a.k.a. rebuilding) node-sqlite3 bindings.
- Also be sure you're using the Electron flags (check version!) for rebuilding. (see RebuildSQLite.sh below).
- The core things I didn't understand and that slowed me down:
- Never having dealt with rebuilding native node modules. node-gyp and electron-rebuild are used to do this.
- Not understanding dynamic and static linking well enough. This was especially challenging because crashes are just hard crashes with horrible error messages, and this setup requires multiple steps in linking (once when you compile SQLCipher and once when you rebuild node-sqlite3).
-
Clone sqlcipher.
cd ~/code git clone git@github.com:sqlcipher/sqlcipher.git cd sqlcipher git checkout -b v.3.4.2 tags/v3.4.2
-
Configure the build.
make clean ./configure --enable-tempstore=yes --enable-load-extension --disable-tcl --with-crypto-lib=commoncrypto
CFLAGS="-DSQLITE_HAS_CODEC -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_FTS5"
LDFLAGS="-framework Security -framework Foundation"
(was -framework CoreServices instead of -framework Foundation at one point)
-
Run the build.
make
This will produce the file ./.lib/libsqlcipher.a
which will be referenced when
we run npm rebuild
. If you want to clean up the built files, run make clean
.
Other notes on compiling SQLCipher
I've spent countless hours trying to get SQLCipher to work by statically linking
OpenSSL's libcrypto.a. Building libsqlcipher.a seems to work, and so does
npm rebuild
ing node-sqlite3, but when Command E is deployed everything seems
to work, but the resulting database is just NOT encrypted. It seems there may be
some problem or core thing I'm missing with how statically linking OpenSSL to
SQLCipher works. ¯_(ツ)_/¯
- Rebuild node-sqlite3 pointing to libsqlcipher.a
This is done in our script tesla/sqlcipher/RebuildSQLite.sh. You can just run
yarn rebuild-sqlite
.
echo "Copying custom binding.gyp (node-sqlite3)"
cp sqlcipher/custom-binding.gyp node_modules/sqlite3/binding.gyp
echo "Rebuilding node-sqlite3 bindings with statically linked SQLCipher (libsqlcipher.a)"
npm rebuild sqlite3 --build-from-source --static_linking_path=/Users/ben/code/sqlcipher/.libs/libsqlcipher.a --runtime=electron --target=3.0.6 --dist-url=https://atom.io/download/electron
libsqlcipher.a is pulled into the node-sqlite3 bindings and a new binary file is
placed at
./node_modules/sqlite3/lib/binding/electron-v3.0-darwin-x64/node_sqlite3.node
.
This binary has SQLCipher bundled in it, which in-turn dynamically links Common
Crypto. Running yarn package
from here will build the app with the SQLCipher
features enabled.
otool -L /Users/ben/code/sqlcipher/.libs/libsqlcipher.dylib
strings .libs/libsqlcipher.a | grep -i RAND_add
strings .libs/libsqlcipher.a | grep -i RAND_add
- Beware of accidental dynamic includes or configuration issues in binding.gyp.
@ajmasia Nice! We don't have CI working with this, I'd very much appreciate if you can paste stuff that gets it working in a CI system.
@SrishtiSingh1902 We do have it working on Windows, it's something like this (below). I haven't done these steps myself, but am pasting some of the notes from one of our engineers...
Add the following System Variables
Log off and log back on to make sure that takes.
Setup SQLCipher
Edit the Makefile.msc or copy this one and rename to the proper directory
Search for
DSQLITE_TEMP_STORE
replace
with
Save your changes
Open
Visual Studio 2017\x64 Native Tools Command Prompt
from the application menuVerify sqlcipher built
Note that "command-e-extra" aligns with the .gyp file listed at the top of this gist. So for Windows, we point node-gyp to this
command-e-extra
folder. You can name it something other than Command E, that's our name :) but be sure to update your .gyp file accordingly.Setup Tesla
Yarn should:
Install all dependencies
Setup the DLL
Run electron-rebuild on slqite3. This is where the magic happens. It uses the
sqlcipher/custom-binding.gyp
to build sqlite with our custom version.Verify it worked by To check it out, go to
c:\code\tesla\node_modules\sqlite3\lib\binding\
you should see:Add extra DLLs
For most users, Command E will work fine but some may not have the right dlls installed for NodeRT
Add a
/c/code/extra-files/win-dlls
folder and copyvccorlib140.dll
fromC:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Redist\MSVC\14.16.27012\x64\Microsoft.VC141.CRT