If you are using System.Data.SQLite with the provided Encryption you may run
into the same problem as I had.
http://www.mail-archive.com/sqlite-users%40sqlite.org/msg66194.html
As Richard already clarified, this encryption is not officially supported by
the SQLite team and is only there for backward compatibility with older
System.Data.SQLite versions.
I've patched the the encryption myself, attached you will find two patches,
which you could apply to the System.Data.SQLite source.
It fixes two problems.
1. The change_counter is never encrypted anymore, fixing the problem of reading
old data. All other content of the database is encrypted and hasn't been
changed from the original implementation.
2. Initialization of the crypt context has to be thread-safe. Otherwise opening
the database in a multi-threaded environment may fail.
Hope this helps...
Kind Regards
Fabrizio
> -----Original Message-----
> From: [email protected] [mailto:sqlite-users-
> [email protected]] On Behalf Of Szomor Akos
> Sent: Donnerstag, 31. Oktober 2013 13:22
> To: [email protected]
> Subject: [sqlite] Multi thread access for encrypted database bug
>
> Hi,
>
> Issue is happening when encrypted database opened by two or more
> program same time.
> (Databases without encryption are working good.)
>
> Data modification by the first program is shown by the second one only if it
> is
> the first, third, 5th, 7th, etc. (odd) modification sequentially since the
> query
> of the second one.
> After modifying two, four, six, etc. (even) data sequentially the result is
> not
> available in second program. The select command by the second program will
> get a previous state of database.
>
> I hope it was understandable.
>
> _______________________________________________
> sqlite-users mailing list
> [email protected]
> http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users
Index: SQLite.Interop/src/win/crypt.c
===================================================================
--- SQLite.Interop/src/win/crypt.c (revision 11148)
+++ SQLite.Interop/src/win/crypt.c (revision 11149)
@@ -11,6 +11,9 @@
// Extra padding before and after the cryptographic buffer
#define CRYPT_OFFSET 8
+#define CHANGE_COUNTER_OFFSET 24
+#define CHANGE_COUNTER(page1) ((LPBYTE)page1) + CHANGE_COUNTER_OFFSET
+
typedef struct _CRYPTBLOCK
{
Pager *pPager; // Pager this cryptblock belongs to
@@ -143,10 +146,16 @@
DWORD dwPageSize;
LPVOID pvTemp;
+ char changeCounter[4]; //Stored change counter if the first page gets
en/decrypted.
+
if (!pBlock) return data;
if (pBlock->pvCrypt == NULL) return NULL; // This only happens if
CreateCryptBlock() failed to make scratch space
+ if (nPageNum == 1){
+ //Never encrypt the change counter, as the encrypted value is used by
SQLite.
+ CopyMemory(changeCounter, CHANGE_COUNTER(data), sizeof(changeCounter));
+ }
+
switch(nMode)
{
case 0: // Undo a "case 7" journal file encryption
@@ -207,6 +216,10 @@
break;
}
+ if (nPageNum == 1){
+ CopyMemory(CHANGE_COUNTER(data), changeCounter, sizeof(changeCounter));
+ }
+
return data;
}
Index: SQLite.Interop/src/win/crypt.c
===================================================================
--- SQLite.Interop/src/win/crypt.c (revision 11149)
+++ SQLite.Interop/src/win/crypt.c (revision 12174)
@@ -24,6 +24,9 @@
DWORD dwCryptSize; // Equal to or greater than dwPageSize. If larger,
pvCrypt is valid and this is its size
} CRYPTBLOCK, *LPCRYPTBLOCK;
+static long crypt_isInit = 0;
+static long crypt_initLock = 0;
+
HCRYPTPROV g_hProvider = 0; // Global instance of the cryptographic provider
#define SQLITECRYPTERROR_PROVIDER "Cryptographic provider not available"
@@ -42,13 +45,24 @@
// most platforms
static BOOL InitializeProvider()
{
- if (g_hProvider) return TRUE;
+ if (crypt_isInit)
+ return g_hProvider;
- if (!CryptAcquireContext(&g_hProvider, NULL, MS_ENHANCED_PROV,
PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
- {
- return FALSE;
+ // Accordingly to
https://groups.google.com/forum/?fromgroups=#!topic/microsoft.public.security.crypto/bJOlErtZDdo
+ // CryptAcquireContext is generally unsafe, therefore make sure only one
thread creates it.
+ if (InterlockedCompareExchange(&crypt_initLock, 1, 0) == 0) {
+ if (!CryptAcquireContext(&g_hProvider, NULL, MS_ENHANCED_PROV,
PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
+ {
+ g_hProvider = 0;
+ }
+ crypt_isInit = 1;
+ } else {
+ while (!crypt_isInit) {
+ Sleep(1);
+ }
}
- return TRUE;
+
+ return g_hProvider;
}
// Create or update a cryptographic context for a pager.
_______________________________________________
sqlite-users mailing list
[email protected]
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users