[bug_fixed] Transparent encryption support for SQLite
Posted: 29.01.2008, 10:31
Hello everybody,
as you may know SQLite supports transparent database file encrpytion. For this to work you need a commercial, but plattform independent SQLite plugin, available here: http://www.hwaci.com/sw/sqlite/prosupport.html#compress
For Windows there is also a free SQLite3 version with encryption, see here: http://sqlite.phxsoftware.com/
This free version is based on SQLite v3.5.4 and has full encryption support, but not plattform independet - it works only on windows. Originally this was written for Microsoft .NET compiler, but it also works with Delphi/C++ Builder and the Zeos components. Simply rename "System.Data.SQLite.dll" to "sqlite3.dll".
In the current version (v6.6.2-rc) Zeos does not implement the functions necessary for encryption support (some of the functions are there, but disabled).
That is why, I created a patch to fully activate encryption support for SQLite in Zeos. Here is what I did. The encryption support needs basicly three functions:
- sqlite_open_encrypted
- sqlite_key (set the encryption password)
- sqlite_rekey (set a new encryption password or re-encrypt a db file with a new password or encrypt an unencrypted db-file)
The first function is only available in SQLite v2.x. SQLite v3.x only knows the second and the third function, so the first is not necessary. So I implemented calls to all three functions in the plain SQLite drivers of Zeos and in IZSQLiteConnection.
If the three functions are not available in sqlite.dll the calls simply do nothing (because the functions pointers are nil/null). So the patch does not break compatibility with SQLite versions without encryption - they can be used as before.
To open an encrypted database file you can now specify the parameter "encrypted=true" in the parameters of ZConnection component. Then when opening / creating the database file a call to sqlite_key will be done. As the key the Password set in ZConnection component will be used.
Later on you can use
(ZConnection1.DbcConnection as IZConnection).GetPlainDriver() and
(ZConnection1.DbcConnection as IZConnection).GetConnectionHandle()
to access the Key and ReKey functions of IZSQLiteConnection.
So, what happens when you use this:
1. If your sqlite3.dll has no encrpytion support and you try to open ...
a) ... a unencrypted db file, with "encrypted=true": Works as usual, because the call to "Key" in Open is ignored. The db file is opened unencrypted.
b) ... a unencrypted db file, with "encrypted=false": Works as usual. The db file is simply opened unencrypted.
c) .... a encrypted db file, with "encrypted=true": You get an error, because the file can't be opened (thats the way it should be ).
d) ... a encrypted db file, with "encrypted=false": You get an error, because the file can't be opened (thats the way it should be ).
2. If your sqlite3.dll has encryption support and you try to open ...
a) ... a unencrypted db file, with "encrypted=true": You get an error, because when opening the file the "Open"-functions calls the "Key" function and sets the encryption key for this file. But because the file is unencrypted it has no encryption key, what means the key you set is wrong (if ZConnection.Password is not empty...). The database file is NOT simply encrypted (would be very dangerous if you do this by accident).
If you want to encrypt an existing db file you need to open it with "encrypted=false" then call IZSQLiteConnection.ReKey to set a password (now the file is encrypted). When you then open the db file the next time you need to set the correct password and "encrypted=true".
b) ... a unencrypted db file, with "encrypted=false": Works as usual. The db file is simply opened unencrypted.
c) ... a encrypted db file, with "encrypted=true": If your key in ZConnection.Password is correct, the encrypted db file is opened as usual and works as usual. If the key is wrong - guess - you get an error.
You can also Open the file with "encrypted=false", but then you need to set the correct key with IZSQLiteConnection.Key BEFORE you try to access any data in the database file.
If you want to set a new key for an encrypted db file, do it this way:
- open the file with the correct key, so "encrypted=true" or call Key-function.
- Call IZSQLiteConnection.ReKey to set the new key (be aware: the complete file is re-encrypted, that needs some time if the file is large). The next time you open the file use the new key...
d) ... a encrypted db file, with "encrypted=false": If you call "IZSQLiteConnection.Key" with the correct key BEFORE you access any data in the db file it will work fine, otherwise you simply get an error (that's the way it should be ).
Best regards, Eike
P.S. The patch is created with WinMerge
as you may know SQLite supports transparent database file encrpytion. For this to work you need a commercial, but plattform independent SQLite plugin, available here: http://www.hwaci.com/sw/sqlite/prosupport.html#compress
For Windows there is also a free SQLite3 version with encryption, see here: http://sqlite.phxsoftware.com/
This free version is based on SQLite v3.5.4 and has full encryption support, but not plattform independet - it works only on windows. Originally this was written for Microsoft .NET compiler, but it also works with Delphi/C++ Builder and the Zeos components. Simply rename "System.Data.SQLite.dll" to "sqlite3.dll".
In the current version (v6.6.2-rc) Zeos does not implement the functions necessary for encryption support (some of the functions are there, but disabled).
That is why, I created a patch to fully activate encryption support for SQLite in Zeos. Here is what I did. The encryption support needs basicly three functions:
- sqlite_open_encrypted
- sqlite_key (set the encryption password)
- sqlite_rekey (set a new encryption password or re-encrypt a db file with a new password or encrypt an unencrypted db-file)
The first function is only available in SQLite v2.x. SQLite v3.x only knows the second and the third function, so the first is not necessary. So I implemented calls to all three functions in the plain SQLite drivers of Zeos and in IZSQLiteConnection.
If the three functions are not available in sqlite.dll the calls simply do nothing (because the functions pointers are nil/null). So the patch does not break compatibility with SQLite versions without encryption - they can be used as before.
To open an encrypted database file you can now specify the parameter "encrypted=true" in the parameters of ZConnection component. Then when opening / creating the database file a call to sqlite_key will be done. As the key the Password set in ZConnection component will be used.
Later on you can use
(ZConnection1.DbcConnection as IZConnection).GetPlainDriver() and
(ZConnection1.DbcConnection as IZConnection).GetConnectionHandle()
to access the Key and ReKey functions of IZSQLiteConnection.
So, what happens when you use this:
1. If your sqlite3.dll has no encrpytion support and you try to open ...
a) ... a unencrypted db file, with "encrypted=true": Works as usual, because the call to "Key" in Open is ignored. The db file is opened unencrypted.
b) ... a unencrypted db file, with "encrypted=false": Works as usual. The db file is simply opened unencrypted.
c) .... a encrypted db file, with "encrypted=true": You get an error, because the file can't be opened (thats the way it should be ).
d) ... a encrypted db file, with "encrypted=false": You get an error, because the file can't be opened (thats the way it should be ).
2. If your sqlite3.dll has encryption support and you try to open ...
a) ... a unencrypted db file, with "encrypted=true": You get an error, because when opening the file the "Open"-functions calls the "Key" function and sets the encryption key for this file. But because the file is unencrypted it has no encryption key, what means the key you set is wrong (if ZConnection.Password is not empty...). The database file is NOT simply encrypted (would be very dangerous if you do this by accident).
If you want to encrypt an existing db file you need to open it with "encrypted=false" then call IZSQLiteConnection.ReKey to set a password (now the file is encrypted). When you then open the db file the next time you need to set the correct password and "encrypted=true".
b) ... a unencrypted db file, with "encrypted=false": Works as usual. The db file is simply opened unencrypted.
c) ... a encrypted db file, with "encrypted=true": If your key in ZConnection.Password is correct, the encrypted db file is opened as usual and works as usual. If the key is wrong - guess - you get an error.
You can also Open the file with "encrypted=false", but then you need to set the correct key with IZSQLiteConnection.Key BEFORE you try to access any data in the database file.
If you want to set a new key for an encrypted db file, do it this way:
- open the file with the correct key, so "encrypted=true" or call Key-function.
- Call IZSQLiteConnection.ReKey to set the new key (be aware: the complete file is re-encrypted, that needs some time if the file is large). The next time you open the file use the new key...
d) ... a encrypted db file, with "encrypted=false": If you call "IZSQLiteConnection.Key" with the correct key BEFORE you access any data in the db file it will work fine, otherwise you simply get an error (that's the way it should be ).
Best regards, Eike
P.S. The patch is created with WinMerge