aboutsummaryrefslogtreecommitdiffstats
path: root/src/wrap/sqlite
diff options
context:
space:
mode:
Diffstat (limited to 'src/wrap/sqlite')
-rw-r--r--src/wrap/sqlite/codec.cpp208
-rw-r--r--src/wrap/sqlite/codec.h51
-rw-r--r--src/wrap/sqlite/codecext.c242
-rw-r--r--src/wrap/sqlite/codecext.cpp261
-rw-r--r--src/wrap/sqlite/readme.txt33
-rw-r--r--src/wrap/sqlite/sqlite.diff77
-rw-r--r--src/wrap/sqlite/sqlite3.diff46
-rw-r--r--src/wrap/sqlite/test_sqlite.cpp2
8 files changed, 463 insertions, 457 deletions
diff --git a/src/wrap/sqlite/codec.cpp b/src/wrap/sqlite/codec.cpp
index 60c8f6a21..9799b058f 100644
--- a/src/wrap/sqlite/codec.cpp
+++ b/src/wrap/sqlite/codec.cpp
@@ -13,111 +13,191 @@ Codec::Codec(void *db)
InitializeCodec(db);
}
-Codec::Codec(const Codec& other, void *db)
+Codec::Codec(const Codec *other, void *db)
{
//Only used to copy main db key for an attached db
InitializeCodec(db);
- m_hasReadKey = other.m_hasReadKey;
- m_hasWriteKey = other.m_hasWriteKey;
- m_readKey = other.m_readKey;
- m_ivReadKey = other.m_ivReadKey;
- m_writeKey = other.m_writeKey;
- m_ivWriteKey = other.m_ivWriteKey;
+ m_hasReadKey = other->m_hasReadKey;
+ m_hasWriteKey = other->m_hasWriteKey;
+ m_readKey = other->m_readKey;
+ m_ivReadKey = other->m_ivReadKey;
+ m_writeKey = other->m_writeKey;
+ m_ivWriteKey = other->m_ivWriteKey;
}
-void
-Codec::InitializeCodec(void *db)
+void Codec::InitializeCodec(void *db)
{
- bool botanInitialized = false;
- Library_State* state = swap_global_state(0);
- if(state)
- {
- botanInitialized = true;
- swap_global_state(state); // should return NULL FIXME: what if not?
- }
-
- if (!botanInitialized)
- LibraryInitializer::initialize();
-
m_hasReadKey = false;
m_hasWriteKey = false;
m_db = db;
- m_encipherFilter = get_cipher(BLOCK_CIPHER_STR, ENCRYPTION);
- m_decipherFilter = get_cipher(BLOCK_CIPHER_STR, DECRYPTION);
- m_cmac = new MAC_Filter(MAC_STR);
- m_encipherPipe.append(m_encipherFilter);
- m_decipherPipe.append(m_decipherFilter);
- m_macPipe.append(m_cmac);
+ try
+ {
+ m_encipherFilter = get_cipher(BLOCK_CIPHER_STR, ENCRYPTION);
+ m_decipherFilter = get_cipher(BLOCK_CIPHER_STR, DECRYPTION);
+ m_cmac = new MAC_Filter(MAC_STR);
+ m_encipherPipe.append(m_encipherFilter);
+ m_decipherPipe.append(m_decipherFilter);
+ m_macPipe.append(m_cmac);
+ }
+ catch(Botan::Exception e)
+ {
+ m_botanErrorMsg = e.what();
+ }
}
-void
-Codec::GenerateWriteKey(const char* userPassword, int passwordLength)
+void Codec::GenerateWriteKey(const char *userPassword, int passwordLength)
{
- PBKDF* pbkdf = get_pbkdf(PBKDF_STR);
- pbkdf->set_iterations(PBKDF_ITERATIONS);
- pbkdf->change_salt((const byte*)SALT_STR.c_str(), SALT_SIZE);
-
- SymmetricKey masterKey =
- pbkdf->derive_key(KEY_SIZE + IV_DERIVATION_KEY_SIZE, std::string(userPassword, passwordLength));
-
- m_writeKey = SymmetricKey(masterKey.bits_of(), KEY_SIZE);
- m_ivWriteKey = SymmetricKey(masterKey.bits_of() + KEY_SIZE, IV_DERIVATION_KEY_SIZE);
-
- m_hasWriteKey = true;
+ try
+ {
+#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,4)
+ PBKDF *pbkdf = get_pbkdf(PBKDF_STR);
+ SymmetricKey masterKey =
+ pbkdf->derive_key(KEY_SIZE + IV_DERIVATION_KEY_SIZE, std::string(userPassword, passwordLength),
+ (const byte*)SALT_STR.c_str(), SALT_SIZE, PBKDF_ITERATIONS);
+#elif BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,8,0)
+ S2K* s2k = get_s2k(PBKDF_STR);
+ s2k->set_iterations(PBKDF_ITERATIONS);
+ s2k->change_salt((const byte*)SALT_STR.c_str(), SALT_SIZE);
+
+ SymmetricKey masterKey =
+ s2k->derive_key(KEY_SIZE + IV_DERIVATION_KEY_SIZE, std::string(userPassword, passwordLength));
+#else
+#error "This code requires botan 1.8 or newer"
+#endif
+ m_writeKey = SymmetricKey(masterKey.bits_of(), KEY_SIZE);
+ m_ivWriteKey = SymmetricKey(masterKey.bits_of() + KEY_SIZE, IV_DERIVATION_KEY_SIZE);
+
+ m_hasWriteKey = true;
+ }
+ catch(Botan::Exception e)
+ {
+ m_botanErrorMsg = e.what();
+ }
}
-void
-Codec::DropWriteKey()
+void Codec::DropWriteKey()
{
m_hasWriteKey = false;
}
-void
-Codec::SetReadIsWrite()
+void Codec::SetReadIsWrite()
{
m_readKey = m_writeKey;
m_ivReadKey = m_ivWriteKey;
m_hasReadKey = m_hasWriteKey;
}
-void
-Codec::SetWriteIsRead()
+void Codec::SetWriteIsRead()
{
m_writeKey = m_readKey;
m_ivWriteKey = m_ivReadKey;
m_hasWriteKey = m_hasReadKey;
}
-unsigned char *
-Codec::Encrypt(int page, unsigned char* data, bool useWriteKey)
+unsigned char* Codec::Encrypt(int page, unsigned char *data, bool useWriteKey)
{
memcpy(m_page, data, m_pageSize);
- m_encipherFilter->set_key(useWriteKey ? m_writeKey : m_readKey);
- m_encipherFilter->set_iv(GetIVForPage(page, useWriteKey));
- m_encipherPipe.process_msg(m_page, m_pageSize);
- m_encipherPipe.read(m_page, m_encipherPipe.remaining(Pipe::LAST_MESSAGE), Pipe::LAST_MESSAGE);
+ try
+ {
+ m_encipherFilter->set_key(useWriteKey ? m_writeKey : m_readKey);
+ m_encipherFilter->set_iv(GetIVForPage(page, useWriteKey));
+ m_encipherPipe.process_msg(m_page, m_pageSize);
+ m_encipherPipe.read(m_page, m_encipherPipe.remaining(Pipe::LAST_MESSAGE), Pipe::LAST_MESSAGE);
+ }
+ catch(Botan::Exception e)
+ {
+ m_botanErrorMsg = e.what();
+ }
return m_page; //return location of newly ciphered data
}
-void
-Codec::Decrypt(int page, unsigned char* data)
+void Codec::Decrypt(int page, unsigned char *data)
{
- m_decipherFilter->set_key(m_readKey);
- m_decipherFilter->set_iv(GetIVForPage(page, false));
- m_decipherPipe.process_msg(data, m_pageSize);
- m_decipherPipe.read(data, m_decipherPipe.remaining(Pipe::LAST_MESSAGE), Pipe::LAST_MESSAGE);
+ try
+ {
+ m_decipherFilter->set_key(m_readKey);
+ m_decipherFilter->set_iv(GetIVForPage(page, false));
+ m_decipherPipe.process_msg(data, m_pageSize);
+ m_decipherPipe.read(data, m_decipherPipe.remaining(Pipe::LAST_MESSAGE), Pipe::LAST_MESSAGE);
+ }
+ catch(Botan::Exception e)
+ {
+ m_botanErrorMsg = e.what();
+ }
}
-InitializationVector
-Codec::GetIVForPage(u32bit page, bool useWriteKey)
+InitializationVector Codec::GetIVForPage(u32bit page, bool useWriteKey)
{
- static unsigned char* intiv[4];
- store_le(page, (byte*)intiv);
- m_cmac->set_key(useWriteKey ? m_ivWriteKey : m_ivReadKey);
- m_macPipe.process_msg((byte*)intiv, 4);
- return m_macPipe.read_all(Pipe::LAST_MESSAGE);
+ try
+ {
+ static unsigned char *intiv[4];
+ store_le(page, (byte*)intiv);
+ m_cmac->set_key(useWriteKey ? m_ivWriteKey : m_ivReadKey);
+ m_macPipe.process_msg((byte*)intiv, 4);
+ return m_macPipe.read_all(Pipe::LAST_MESSAGE);
+ }
+ catch(Botan::Exception e)
+ {
+ m_botanErrorMsg = e.what();
+ }
+}
+
+const char* Codec::GetAndResetError()
+{
+ const char *message = m_botanErrorMsg;
+ m_botanErrorMsg = 0;
+ return message;
}
+#include "codec_c_interface.h"
+
+void InitializeBotan() {
+ LibraryInitializer::initialize();
+}
+void* InitializeNewCodec(void *db) {
+ return new Codec(db);
+}
+void* InitializeFromOtherCodec(const void *otherCodec, void *db) {
+ return new Codec((Codec*)otherCodec, db);
+}
+void GenerateWriteKey(void *codec, const char *userPassword, int passwordLength) {
+ ((Codec*)codec)->GenerateWriteKey(userPassword, passwordLength);
+}
+void DropWriteKey(void *codec) {
+ ((Codec*)codec)->DropWriteKey();
+}
+void SetWriteIsRead(void *codec) {
+ ((Codec*)codec)->SetWriteIsRead();
+}
+void SetReadIsWrite(void *codec) {
+ ((Codec*)codec)->SetReadIsWrite();
+}
+unsigned char* Encrypt(void *codec, int page, unsigned char *data, Bool useWriteKey) {
+ ((Codec*)codec)->Encrypt(page, data, useWriteKey);
+}
+void Decrypt(void *codec, int page, unsigned char *data) {
+ ((Codec*)codec)->Decrypt(page, data);
+}
+void SetPageSize(void *codec, int pageSize) {
+ ((Codec*)codec)->SetPageSize(pageSize);
+}
+Bool HasReadKey(void *codec) {
+ return ((Codec*)codec)->HasReadKey();
+}
+Bool HasWriteKey(void *codec) {
+ return ((Codec*)codec)->HasWriteKey();
+}
+void* GetDB(void *codec) {
+ return ((Codec*)codec)->GetDB();
+}
+const char* GetAndResetError(void *codec)
+{
+ return ((Codec*)codec)->GetAndResetError();
+}
+void DeleteCodec(void *codec) {
+ Codec *deleteThisCodec = (Codec*)codec;
+ delete deleteThisCodec;
+}
diff --git a/src/wrap/sqlite/codec.h b/src/wrap/sqlite/codec.h
index c254f9fde..2f94bcc59 100644
--- a/src/wrap/sqlite/codec.h
+++ b/src/wrap/sqlite/codec.h
@@ -12,32 +12,6 @@
#include <botan/botan.h>
#include <botan/loadstor.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if defined(__BORLANDC__)
-#define __STDC__ 1
-#endif
-
-#include "./sqliteInt.h"
-
-#if defined(__BORLANDC__)
-#undef __STDC__
-#endif
-
-/* ATTENTION: Macro similar to that in pager.c
- * Needed because pager is forward declared when needed most
- * TODO: Check in case of new version of SQLite
- * ... but it's VERY unlikely to change (it'd break all past DBs)
- */
-#include "./os.h"
-#define CODEC_PAGER_MJ_PGNO(x) ((PENDING_BYTE/(x))+1)
-
-#ifdef __cplusplus
-} /* End of the 'extern "C"' block */
-#endif
-
using namespace std;
using namespace Botan;
@@ -57,6 +31,9 @@ const string PBKDF_STR = "PBKDF2(SHA-160)";
//SALT_STR: Hard coded salt used to derive the key from the passphrase.
const string SALT_STR = "&g#nB'9]";
+//SALT_SIZE: Size of the salt in bytes (as given in SALT_STR)
+const int SALT_SIZE = 64/8; //64 bit, 8 byte salt
+
//MAC_STR: CMAC used to derive the IV that is used for db page
//encryption
const string MAC_STR = "CMAC(Twofish)";
@@ -65,9 +42,6 @@ const string MAC_STR = "CMAC(Twofish)";
//process.
const int PBKDF_ITERATIONS = 10000;
-//SALT_SIZE: Size of the salt in bytes (as given in SALT_STR)
-const int SALT_SIZE = 64/8; //64 bit, 8 byte salt
-
//KEY_SIZE: Size of the encryption key. Note that XTS splits the key
//between two ciphers, so if you're using XTS, double the intended key
//size. (ie, "AES-128/XTS" should have a 256 bit KEY_SIZE)
@@ -77,29 +51,33 @@ const int KEY_SIZE = 512/8; //512 bit, 64 byte key. (256 bit XTS key)
//above.
const int IV_DERIVATION_KEY_SIZE = 256/8; //256 bit, 32 byte key
+//This is definited in sqlite.h and very unlikely to change
+#define SQLITE_MAX_PAGE_SIZE 32768
+
class Codec
{
public:
Codec(void *db);
- Codec(const Codec& other, void *db);
+ Codec(const Codec* other, void *db);
- void GenerateWriteKey(const char* userPassword, int passwordLength);
+ void GenerateWriteKey(const char *userPassword, int passwordLength);
void DropWriteKey();
void SetWriteIsRead();
void SetReadIsWrite();
- unsigned char* Encrypt(int page, unsigned char* data, bool useWriteKey);
- void Decrypt(int page, unsigned char* data);
+ unsigned char* Encrypt(int page, unsigned char *data, bool useWriteKey);
+ void Decrypt(int page, unsigned char *data);
void SetPageSize(int pageSize) { m_pageSize = pageSize; }
bool HasReadKey() { return m_hasReadKey; }
bool HasWriteKey() { return m_hasWriteKey; }
void* GetDB() { return m_db; }
+ const char* GetAndResetError();
private:
- bool m_hasReadKey;
- bool m_hasWriteKey;
+ bool m_hasReadKey;
+ bool m_hasWriteKey;
SymmetricKey
m_readKey,
@@ -118,7 +96,8 @@ private:
int m_pageSize;
unsigned char m_page[SQLITE_MAX_PAGE_SIZE];
- void* m_db;
+ void *m_db;
+ const char *m_botanErrorMsg;
InitializationVector GetIVForPage(u32bit page, bool useWriteKey);
void InitializeCodec(void *db);
diff --git a/src/wrap/sqlite/codecext.c b/src/wrap/sqlite/codecext.c
new file mode 100644
index 000000000..66f13b9b6
--- /dev/null
+++ b/src/wrap/sqlite/codecext.c
@@ -0,0 +1,242 @@
+/*
+ * Encryption codec implementation
+ * (C) 2010 Olivier de Gaalon
+ *
+ * Distributed under the terms of the Botan license
+ */
+
+#ifndef SQLITE_OMIT_DISKIO
+#ifdef SQLITE_HAS_CODEC
+
+#include "codec_c_interface.h"
+
+Bool HandleError(void *pCodec)
+{
+ const char *error = GetAndResetError(pCodec);
+ if (error) {
+ sqlite3Error((sqlite3*)GetDB(pCodec), SQLITE_ERROR, "Botan Error: %s", error);
+ return 1;
+ }
+ return 0;
+}
+
+// Guessing that "see" is related to SQLite Encryption Extension" (the semi-official, for-pay, encryption codec)
+// Just as useful for initializing Botan.
+void sqlite3_activate_see(const char *info)
+{
+ InitializeBotan();
+}
+
+// Free the encryption codec, called from pager.c (address passed in sqlite3PagerSetCodec)
+void sqlite3PagerFreeCodec(void *pCodec)
+{
+ if (pCodec)
+ DeleteCodec(pCodec);
+}
+
+// Report the page size to the codec, called from pager.c (address passed in sqlite3PagerSetCodec)
+void sqlite3CodecSizeChange(void *pCodec, int pageSize, int nReserve)
+{
+ SetPageSize(pCodec, pageSize);
+}
+
+// Encrypt/Decrypt functionality, called by pager.c
+void* sqlite3Codec(void *pCodec, void *data, Pgno nPageNum, int nMode)
+{
+ if (pCodec == NULL) //Db not encrypted
+ return data;
+
+ switch(nMode)
+ {
+ case 0: // Undo a "case 7" journal file encryption
+ case 2: // Reload a page
+ case 3: // Load a page
+ if (HasReadKey(pCodec))
+ Decrypt(pCodec, nPageNum, (unsigned char*) data);
+ break;
+ case 6: // Encrypt a page for the main database file
+ if (HasWriteKey(pCodec))
+ data = Encrypt(pCodec, nPageNum, (unsigned char*) data, 1);
+ break;
+ case 7: // Encrypt a page for the journal file
+ /*
+ *Under normal circumstances, the readkey is the same as the writekey. However,
+ *when the database is being rekeyed, the readkey is not the same as the writekey.
+ *(The writekey is the "destination key" for the rekey operation and the readkey
+ *is the key the db is currently encrypted with)
+ *Therefore, for case 7, when the rollback is being written, always encrypt using
+ *the database's readkey, which is guaranteed to be the same key that was used to
+ *read and write the original data.
+ */
+ if (HasReadKey(pCodec))
+ data = Encrypt(pCodec, nPageNum, (unsigned char*) data, 0);
+ break;
+ }
+
+ HandleError(pCodec);
+
+ return data;
+}
+
+int sqlite3CodecAttach(sqlite3 *db, int nDb, const void *zKey, int nKey)
+{
+ void *pCodec;
+
+ if (zKey == NULL || nKey <= 0)
+ {
+ // No key specified, could mean either use the main db's encryption or no encryption
+ if (nDb != 0 && nKey < 0)
+ {
+ //Is an attached database, therefore use the key of main database, if main database is encrypted
+ void *pMainCodec = sqlite3PagerGetCodec(sqlite3BtreePager(db->aDb[0].pBt));
+ if (pMainCodec != NULL)
+ {
+ pCodec = InitializeFromOtherCodec(pMainCodec, db);
+ sqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt),
+ sqlite3Codec,
+ sqlite3CodecSizeChange,
+ sqlite3PagerFreeCodec, pCodec);
+ }
+ }
+ }
+ else
+ {
+ // Key specified, setup encryption key for database
+ pCodec = InitializeNewCodec(db);
+ GenerateWriteKey(pCodec, (const char*) zKey, nKey);
+ SetReadIsWrite(pCodec);
+ sqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt),
+ sqlite3Codec,
+ sqlite3CodecSizeChange,
+ sqlite3PagerFreeCodec, pCodec);
+ }
+
+ if (HandleError(pCodec))
+ return SQLITE_ERROR;
+
+ return SQLITE_OK;
+}
+
+void sqlite3CodecGetKey(sqlite3* db, int nDb, void **zKey, int *nKey)
+{
+ // The unencrypted password is not stored for security reasons
+ // therefore always return NULL
+ *zKey = NULL;
+ *nKey = -1;
+}
+
+int sqlite3_key(sqlite3 *db, const void *zKey, int nKey)
+{
+ // The key is only set for the main database, not the temp database
+ return sqlite3CodecAttach(db, 0, zKey, nKey);
+}
+
+int sqlite3_rekey(sqlite3 *db, const void *zKey, int nKey)
+{
+ // Changes the encryption key for an existing database.
+ int rc = SQLITE_ERROR;
+ Btree *pbt = db->aDb[0].pBt;
+ Pager *pPager = sqlite3BtreePager(pbt);
+ void *pCodec = sqlite3PagerGetCodec(pPager);
+
+ if ((zKey == NULL || nKey == 0) && pCodec == NULL)
+ {
+ // Database not encrypted and key not specified. Do nothing
+ return SQLITE_OK;
+ }
+
+ if (pCodec == NULL)
+ {
+ // Database not encrypted, but key specified. Encrypt database
+ pCodec = InitializeNewCodec(db);
+ GenerateWriteKey(pCodec, (const char*) zKey, nKey);
+
+ if (HandleError(pCodec))
+ return SQLITE_ERROR;
+
+ sqlite3PagerSetCodec(pPager, sqlite3Codec, sqlite3CodecSizeChange, sqlite3PagerFreeCodec, pCodec);
+ }
+ else if (zKey == NULL || nKey == 0)
+ {
+ // Database encrypted, but key not specified. Decrypt database
+ // Keep read key, drop write key
+ DropWriteKey(pCodec);
+ }
+ else
+ {
+ // Database encrypted and key specified. Re-encrypt database with new key
+ // Keep read key, change write key to new key
+ GenerateWriteKey(pCodec, (const char*) zKey, nKey);
+ if (HandleError(pCodec))
+ return SQLITE_ERROR;
+ }
+
+ // Start transaction
+ rc = sqlite3BtreeBeginTrans(pbt, 1);
+ if (rc == SQLITE_OK)
+ {
+ // Rewrite all pages using the new encryption key (if specified)
+ int nPageCount = -1;
+ int rc = sqlite3PagerPagecount(pPager, &nPageCount);
+ Pgno nPage = (Pgno) nPageCount;
+
+ Pgno nSkip = PAGER_MJ_PGNO(pPager);
+ DbPage *pPage;
+
+ Pgno n;
+ for (n = 1; rc == SQLITE_OK && n <= nPage; n++)
+ {
+ if (n == nSkip)
+ continue;
+
+ rc = sqlite3PagerGet(pPager, n, &pPage);
+
+ if (!rc)
+ {
+ rc = sqlite3PagerWrite(pPage);
+ sqlite3PagerUnref(pPage);
+ }
+ else
+ sqlite3Error(db, SQLITE_ERROR, "%s", "Error while rekeying database page. Transaction Canceled.");
+ }
+ }
+ else
+ sqlite3Error(db, SQLITE_ERROR, "%s", "Error beginning rekey transaction. Make sure that the current encryption key is correct.");
+
+ if (rc == SQLITE_OK)
+ {
+ // All good, commit
+ rc = sqlite3BtreeCommit(pbt);
+
+ if (rc == SQLITE_OK)
+ {
+ //Database rekeyed and committed successfully, update read key
+ if (HasWriteKey(pCodec))
+ SetReadIsWrite(pCodec);
+ else //No write key == no longer encrypted
+ sqlite3PagerSetCodec(pPager, NULL, NULL, NULL, NULL);
+ }
+ else
+ {
+ //FIXME: can't trigger this, not sure if rollback is needed, reference implementation didn't rollback
+ sqlite3Error(db, SQLITE_ERROR, "%s", "Could not commit rekey transaction.");
+ }
+ }
+ else
+ {
+ // Rollback, rekey failed
+ sqlite3BtreeRollback(pbt);
+
+ // go back to read key
+ if (HasReadKey(pCodec))
+ SetWriteIsRead(pCodec);
+ else //Database wasn't encrypted to start with
+ sqlite3PagerSetCodec(pPager, NULL, NULL, NULL, NULL);
+ }
+
+ return rc;
+}
+
+#endif // SQLITE_HAS_CODEC
+
+#endif // SQLITE_OMIT_DISKIO
diff --git a/src/wrap/sqlite/codecext.cpp b/src/wrap/sqlite/codecext.cpp
deleted file mode 100644
index e542df975..000000000
--- a/src/wrap/sqlite/codecext.cpp
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * SQLite3 encryption extention codec
- * (C) 2010 Olivier de Gaalon
- *
- * Distributed under the terms of the Botan license
- */
-
-#ifndef SQLITE_OMIT_DISKIO
-#ifdef SQLITE_HAS_CODEC
-
-#include "codec.h"
-#include "sqlite3.h"
-
-// Required to implement, called from pragma.c, guessing that "see" is related to the
-// "SQLite Encryption Extension" (the semi-official, for-pay, encryption codec)
-extern "C"
-void sqlite3_activate_see(const char *info) { }
-
-// Free the encryption codec, called from pager.c (address passed in sqlite3PagerSetCodec)
-extern "C"
-void sqlite3PagerFreeCodec(void *pCodec)
-{
- if (pCodec)
- delete (Codec*) pCodec;
-}
-
-// Report the page size to the codec, called from pager.c (address passed in sqlite3PagerSetCodec)
-extern "C"
-void sqlite3CodecSizeChange(void *pCodec, int pageSize, int nReserve)
-{
- Codec* codec = (Codec*) pCodec;
- codec->SetPageSize(pageSize);
-}
-
-// Encrypt/Decrypt functionality, called by pager.c
-extern "C"
-void* sqlite3Codec(void* pCodec, void* data, Pgno nPageNum, int nMode)
-{
- if (pCodec == NULL) //Db not encrypted
- return data;
-
- Codec* codec = (Codec*) pCodec;
-
- try
- {
- switch(nMode)
- {
- case 0: // Undo a "case 7" journal file encryption
- case 2: // Reload a page
- case 3: // Load a page
- if (codec->HasReadKey())
- codec->Decrypt(nPageNum, (unsigned char*) data);
- break;
- case 6: // Encrypt a page for the main database file
- if (codec->HasWriteKey())
- data = codec->Encrypt(nPageNum, (unsigned char*) data, true);
- break;
- case 7: // Encrypt a page for the journal file
- /*
- *Under normal circumstances, the readkey is the same as the writekey. However,
- *when the database is being rekeyed, the readkey is not the same as the writekey.
- *(The writekey is the "destination key" for the rekey operation and the readkey
- *is the key the db is currently encrypted with)
- *Therefore, for case 7, when the rollback is being written, always encrypt using
- *the database's readkey, which is guaranteed to be the same key that was used to
- *read and write the original data.
- */
- if (codec->HasReadKey())
- data = codec->Encrypt(nPageNum, (unsigned char*) data, false);
- break;
- }
- }
- catch(Botan::Exception e)
- {
- sqlite3Error((sqlite3*)codec->GetDB(), SQLITE_ERROR, "Botan Error: %s", e.what());
- }
-
- return data;
-}
-
-//These functions are defined in pager.c
-extern "C" void* sqlite3PagerGetCodec(Pager *pPager);
-extern "C" void sqlite3PagerSetCodec(
- Pager *pPager,
- void *(*xCodec)(void*,void*,Pgno,int),
- void (*xCodecSizeChng)(void*,int,int),
- void (*xCodecFree)(void*),
- void *pCodec
-);
-
-
-extern "C"
-int sqlite3CodecAttach(sqlite3* db, int nDb, const void* zKey, int nKey)
-{
- try {
- if (zKey == NULL || nKey <= 0)
- {
- // No key specified, could mean either use the main db's encryption or no encryption
- if (nDb != 0 && nKey < 0)
- {
- //Is an attached database, therefore use the key of main database, if main database is encrypted
- Codec* mainCodec = (Codec*) sqlite3PagerGetCodec(sqlite3BtreePager(db->aDb[0].pBt));
- if (mainCodec != NULL)
- {
- Codec* codec = new Codec(*mainCodec, db);
- sqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt),
- sqlite3Codec,
- sqlite3CodecSizeChange,
- sqlite3PagerFreeCodec, codec);
- }
- }
- }
- else
- {
- // Key specified, setup encryption key for database
- Codec* codec = new Codec(db);
- codec->GenerateWriteKey((const char*) zKey, nKey);
- codec->SetReadIsWrite();
- sqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt),
- sqlite3Codec,
- sqlite3CodecSizeChange,
- sqlite3PagerFreeCodec, codec);
- }
- }
- catch(Botan::Exception e) {
- sqlite3Error(db, SQLITE_ERROR, "Botan Error: %s", e.what());
- return SQLITE_ERROR;
- }
- return SQLITE_OK;
-}
-
-extern "C"
-void sqlite3CodecGetKey(sqlite3* db, int nDb, void** zKey, int* nKey)
-{
- // The unencrypted password is not stored for security reasons
- // therefore always return NULL
- *zKey = NULL;
- *nKey = -1;
-}
-
-extern "C"
-int sqlite3_key(sqlite3 *db, const void *zKey, int nKey)
-{
- // The key is only set for the main database, not the temp database
- return sqlite3CodecAttach(db, 0, zKey, nKey);
-}
-
-extern "C"
-int sqlite3_rekey(sqlite3 *db, const void *zKey, int nKey)
-{
- // Changes the encryption key for an existing database.
- int rc = SQLITE_ERROR;
- Btree* pbt = db->aDb[0].pBt;
- Pager* pPager = sqlite3BtreePager(pbt);
- Codec* codec = (Codec*) sqlite3PagerGetCodec(pPager);
-
- if ((zKey == NULL || nKey == 0) && codec == NULL)
- {
- // Database not encrypted and key not specified. Do nothing
- return SQLITE_OK;
- }
-
- if (codec == NULL)
- {
- // Database not encrypted, but key specified. Encrypt database
- try {
- codec = new Codec(db);
- codec->GenerateWriteKey((const char*) zKey, nKey);
- } catch (Botan::Exception e) {
- sqlite3Error(db, SQLITE_ERROR, "Botan Error %s", e.what());
- return SQLITE_ERROR;
- }
- sqlite3PagerSetCodec(pPager, sqlite3Codec, sqlite3CodecSizeChange, sqlite3PagerFreeCodec, codec);
- }
- else if (zKey == NULL || nKey == 0)
- {
- // Database encrypted, but key not specified. Decrypt database
- // Keep read key, drop write key
- codec->DropWriteKey();
- }
- else
- {
- // Database encrypted and key specified. Re-encrypt database with new key
- // Keep read key, change write key to new key
- try {
- codec->GenerateWriteKey((const char*) zKey, nKey);
- } catch (Botan::Exception e) {
- sqlite3Error(db, SQLITE_ERROR, "Botan Error %s", e.what());
- return SQLITE_ERROR;
- }
- }
-
- // Start transaction
- rc = sqlite3BtreeBeginTrans(pbt, 1);
- if (rc == SQLITE_OK)
- {
- // Rewrite all pages using the new encryption key (if specified)
- int nPageCount = -1;
- int rc = sqlite3PagerPagecount(pPager, &nPageCount);
- Pgno nPage = (Pgno) nPageCount;
- int pageSize = sqlite3BtreeGetPageSize(pbt);
- //Can't use SQLite3 macro here since pager is forward declared...sigh
- Pgno nSkip = CODEC_PAGER_MJ_PGNO(pageSize);
- DbPage *pPage;
-
- for (Pgno n = 1; rc == SQLITE_OK && n <= nPage; n++)
- {
- if (n == nSkip)
- continue;
-
- rc = sqlite3PagerGet(pPager, n, &pPage);
-
- if (!rc)
- {
- rc = sqlite3PagerWrite(pPage);
- sqlite3PagerUnref(pPage);
- }
- else
- sqlite3Error(db, SQLITE_ERROR, "%s", "Error while rekeying database page. Transaction Canceled.");
- }
- }
- else
- sqlite3Error(db, SQLITE_ERROR, "%s", "Error beginning rekey transaction. Make sure that the current encryption key is correct.");
-
- if (rc == SQLITE_OK)
- {
- // All good, commit
- rc = sqlite3BtreeCommit(pbt);
-
- if (rc == SQLITE_OK)
- {
- //Database rekeyed and committed successfully, update read key
- if (codec->HasWriteKey())
- codec->SetReadIsWrite();
- else //No write key == no longer encrypted
- sqlite3PagerSetCodec(pPager, NULL, NULL, NULL, NULL);
- }
- else
- {
- //FIXME: can't trigger this, not sure if rollback is needed, reference implementation didn't rollback
- sqlite3Error(db, SQLITE_ERROR, "%s", "Could not commit rekey transaction.");
- }
- }
- else
- {
- // Rollback, rekey failed
- sqlite3BtreeRollback(pbt);
-
- // go back to read key
- if (codec->HasReadKey())
- codec->SetWriteIsRead();
- else //Database wasn't encrypted to start with
- sqlite3PagerSetCodec(pPager, NULL, NULL, NULL, NULL);
- }
-
- return rc;
-}
-
-#endif // SQLITE_HAS_CODEC
-
-#endif // SQLITE_OMIT_DISKIO
diff --git a/src/wrap/sqlite/readme.txt b/src/wrap/sqlite/readme.txt
index e131f9e91..b692aec9b 100644
--- a/src/wrap/sqlite/readme.txt
+++ b/src/wrap/sqlite/readme.txt
@@ -1,36 +1,31 @@
Build instructions for Botan SQLite3 codec
---
-1. Requires Botan 1.8.8 or later (earlier versions OK if you switch to
- CBC mode from XTS)
+1. Requires Botan 1.9.0 or later
-2. Download SQLite3 version 3.6.17 or later, get the version "as
- extracted from the source control system", NOT the amalgamation.
+2. Download and extract SQLite3 version 3.7.0.1 or later (previous
+ versions may work, untested)
-3. Apply the patch "sqlite.diff" [*]:
+3. From the extracted sqlite folder, apply the patch "sqlite3.diff":
$ patch -p0 < ../sqlite.diff
patching file Makefile.in
- patching file src/pager.c
+ patching file sqlite3.c
- If the patch to pager.c fails for some reason (ie, changes in
- SQLite3), all that need be done is remove the "static" keyword from
- the functions sqlite3PagerSetCodec and sqlite3PagerGetCodec.
+ If the patch to fails for some reason (ie, changes in SQLite3), it
+ should be trivial to do it manually.
-5. Create a folder called "botan" in the SQLite3 src dir and copy
- "codec.cpp", "codec.h", and "codecext.cpp" into it.
+4. Copy all files inside the "src" directory into the Sqlite3 directory
+ (codec.cpp, codec.h, codec_c_interface.h, codecext.c)
-6. As desired, edit the constants in codec.h to tweak the encryption
+5. As desired, edit the constants in codec.h to tweak the encryption
type to your needs. (Currently, Twofish/XTS with 256 bit key)
-7. Run ./configure in the SQLite3 root directory with the
- "--disable-amalgamation" and (if desired) "--disable-shared"
- arguments, and then run make.
+6. "./configure" and "make" Sqlite3
And to make sure it all worked...
-8. Make the test_sqlite.cpp file:
+7. Make the test_sqlite.cpp file:
$ g++ test_sqlite.cpp -o test_sqlite -lbotan /path/to/libsqlite3.a
-9. Run it
+8. Run it
$ ./test_sqlite
-10. Look for "All seems good"
-
+9. Look for "All seems good" \ No newline at end of file
diff --git a/src/wrap/sqlite/sqlite.diff b/src/wrap/sqlite/sqlite.diff
deleted file mode 100644
index 1a3ef764c..000000000
--- a/src/wrap/sqlite/sqlite.diff
+++ /dev/null
@@ -1,77 +0,0 @@
---- Makefile.in.orig 2009-10-30 09:34:59.000000000 -0400
-+++ Makefile.in 2010-01-21 22:51:22.000000000 -0500
-@@ -133,7 +133,10 @@
- GCOV_LDFLAGS1 = -lgcov
- USE_GCOV = @USE_GCOV@
- LTCOMPILE_EXTRAS += $(GCOV_CFLAGS$(USE_GCOV))
-+LTCOMPILE_EXTRAS += -DSQLITE_HAS_CODEC
- LTLINK_EXTRAS += $(GCOV_LDFLAGS$(USE_GCOV))
-+LTLINK_EXTRAS += -lstdc++
-+LTLINK_EXTRAS += -lbotan
-
-
- # The directory into which to store package information for
-@@ -176,7 +179,8 @@
- table.lo tokenize.lo trigger.lo update.lo \
- util.lo vacuum.lo \
- vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo \
-- walker.lo where.lo utf.lo vtab.lo
-+ walker.lo where.lo utf.lo vtab.lo \
-+ codec.lo codecext.lo
-
- # Object files for the amalgamation.
- #
-@@ -275,7 +279,10 @@
- $(TOP)/src/vdbeInt.h \
- $(TOP)/src/vtab.c \
- $(TOP)/src/walker.c \
-- $(TOP)/src/where.c
-+ $(TOP)/src/where.c \
-+ $(TOP)/src/botan/codec.cpp \
-+ $(TOP)/src/botan/codecext.cpp \
-+ $(TOP)/src/botan/codec.h
-
- # Generated source code files
- #
-@@ -411,6 +418,7 @@
- $(TOP)/src/sqlite3ext.h \
- $(TOP)/src/sqliteInt.h \
- $(TOP)/src/vdbe.h \
-+ $(TOP)/src/botan/codec.h \
- $(TOP)/src/vdbeInt.h \
- parse.h \
- config.h
-@@ -622,6 +630,13 @@
- notify.lo: $(TOP)/src/notify.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/notify.c
-
-+codec.lo: $(TOP)/src/botan/codec.cpp $(HDR) $(TOP)/src/botan/codec.h
-+ $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/botan/codec.cpp
-+
-+codecext.lo: $(TOP)/src/botan/codecext.cpp $(HDR) $(TOP)/src/botan/codec.h
-+ $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/botan/codecext.cpp
-+
-+
- pager.lo: $(TOP)/src/pager.c $(HDR) $(TOP)/src/pager.h
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/pager.c
-
---- src/pager.c.orig 2009-10-30 17:01:07.000000000 -0400
-+++ src/pager.c 2010-01-21 22:51:53.000000000 -0500
-@@ -5046,7 +5046,7 @@
- /*
- ** Set or retrieve the codec for this pager
- */
--static void sqlite3PagerSetCodec(
-+void sqlite3PagerSetCodec(
- Pager *pPager,
- void *(*xCodec)(void*,void*,Pgno,int),
- void (*xCodecSizeChng)(void*,int,int),
-@@ -5060,7 +5060,7 @@
- pPager->pCodec = pCodec;
- pagerReportSize(pPager);
- }
--static void *sqlite3PagerGetCodec(Pager *pPager){
-+void *sqlite3PagerGetCodec(Pager *pPager){
- return pPager->pCodec;
- }
- #endif
diff --git a/src/wrap/sqlite/sqlite3.diff b/src/wrap/sqlite/sqlite3.diff
new file mode 100644
index 000000000..7ea89f002
--- /dev/null
+++ b/src/wrap/sqlite/sqlite3.diff
@@ -0,0 +1,46 @@
+--- Makefile.in.orig 2010-08-05 00:15:13.000000000 +0800
++++ Makefile.in 2010-08-16 15:09:58.000000000 +0800
+@@ -65,7 +65,7 @@
+ libLTLIBRARIES_INSTALL = $(INSTALL)
+ LTLIBRARIES = $(lib_LTLIBRARIES)
+ libsqlite3_la_LIBADD =
+-am_libsqlite3_la_OBJECTS = sqlite3.lo
++am_libsqlite3_la_OBJECTS = sqlite3.lo codec.lo
+ libsqlite3_la_OBJECTS = $(am_libsqlite3_la_OBJECTS)
+ binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+ PROGRAMS = $(bin_PROGRAMS)
+@@ -209,10 +209,10 @@
+ sharedstatedir = @sharedstatedir@
+ sysconfdir = @sysconfdir@
+ target_alias = @target_alias@
+-AM_CFLAGS = @THREADSAFE_FLAGS@ @DYNAMIC_EXTENSION_FLAGS@ -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE
++AM_CFLAGS = @THREADSAFE_FLAGS@ @DYNAMIC_EXTENSION_FLAGS@ -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE -DSQLITE_HAS_CODEC
+ lib_LTLIBRARIES = libsqlite3.la
+ libsqlite3_la_SOURCES = sqlite3.c
+-libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8
++libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8 -lstdc++ -lbotan
+ sqlite3_SOURCES = shell.c sqlite3.h
+ sqlite3_LDADD = $(top_builddir)/libsqlite3.la @READLINE_LIBS@
+ sqlite3_DEPENDENCIES = $(top_builddir)/libsqlite3.la
+@@ -349,6 +349,13 @@
+ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
++@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
++
++codec.lo:
++@am__fastdepCC_TRUE@ if $(LTCOMPILE) codec.cpp -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
++@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
++@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+ mostlyclean-libtool:
+--- sqlite3.c.orig 2010-08-05 00:14:22.000000000 +0800
++++ sqlite3.c 2010-08-16 15:35:55.000000000 +0800
+@@ -118684,3 +118684,5 @@
+ #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */
+
+ /************** End of fts3_icu.c ********************************************/
++
++#include "codecext.c"
diff --git a/src/wrap/sqlite/test_sqlite.cpp b/src/wrap/sqlite/test_sqlite.cpp
index 8d8cad946..6a22cd612 100644
--- a/src/wrap/sqlite/test_sqlite.cpp
+++ b/src/wrap/sqlite/test_sqlite.cpp
@@ -5,6 +5,8 @@
* Distributed under the terms of the Botan license
*/
+#define SQLITE_HAS_CODEC 1
+
#include <sqlite3.h>
#include <stdio.h>