diff options
author | Jack Lloyd <[email protected]> | 2016-11-05 22:07:02 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2016-11-05 22:16:28 -0400 |
commit | 750902b7832792a74d073b4973e6b60a9731977b (patch) | |
tree | 03f9810f1eb8ad7343adeaf479336408509f9cf0 | |
parent | af7af14fb97299fc70a2a1f8590288fbf91f271b (diff) |
Revert "Move contrib/sqlite to github.com/randombit/botan-sqlite"
This reverts commit cfb12bf77940c566de1e6de4a79db6fe0d02ef1e.
tl;dr monorepo is better, especially for a project this small.
-rw-r--r-- | src/contrib/sqlite/codec.cpp | 201 | ||||
-rw-r--r-- | src/contrib/sqlite/codec.h | 106 | ||||
-rw-r--r-- | src/contrib/sqlite/codec_c_interface.h | 90 | ||||
-rw-r--r-- | src/contrib/sqlite/codecext.c | 242 | ||||
-rw-r--r-- | src/contrib/sqlite/readme.txt | 35 | ||||
-rw-r--r-- | src/contrib/sqlite/sqlite3-amalgamation.patch | 15 | ||||
-rw-r--r-- | src/contrib/sqlite/test_sqlite.cpp | 103 |
7 files changed, 792 insertions, 0 deletions
diff --git a/src/contrib/sqlite/codec.cpp b/src/contrib/sqlite/codec.cpp new file mode 100644 index 000000000..4a13d3dde --- /dev/null +++ b/src/contrib/sqlite/codec.cpp @@ -0,0 +1,201 @@ +/* + * Codec class for SQLite3 encryption codec. + * (C) 2010 Olivier de Gaalon + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#include "codec.h" + +Codec::Codec(void *db) +{ + InitializeCodec(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; +} + +void Codec::InitializeCodec(void *db) +{ + m_hasReadKey = false; + m_hasWriteKey = false; + m_db = db; + + 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) +{ + 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() +{ + m_hasWriteKey = false; +} + +void Codec::SetReadIsWrite() +{ + m_readKey = m_writeKey; + m_ivReadKey = m_ivWriteKey; + m_hasReadKey = m_hasWriteKey; +} + +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) +{ + memcpy(m_page, data, m_pageSize); + + 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) +{ + 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) +{ + 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() { +} +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) { + return ((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/contrib/sqlite/codec.h b/src/contrib/sqlite/codec.h new file mode 100644 index 000000000..673de2480 --- /dev/null +++ b/src/contrib/sqlite/codec.h @@ -0,0 +1,106 @@ +/* + * Codec class for SQLite3 encryption codec. + * (C) 2010 Olivier de Gaalon + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#ifndef _CODEC_H_ +#define _CODEC_H_ + +#include <string> +#include <botan/botan.h> +#include <botan/loadstor.h> + +using namespace std; +using namespace Botan; + +/*These constants can be used to tweak the codec behavior as follows + *Note that once you've encrypted a database with these settings, + *recompiling with any different settings will give you a library that + *cannot read that database, even given the same passphrase.*/ + +//BLOCK_CIPHER_STR: Cipher and mode used for encrypting the database +//make sure to add "/NoPadding" for modes that use padding schemes +const string BLOCK_CIPHER_STR = "Twofish/XTS"; + +//PBKDF_STR: Key derivation function used to derive both the encryption +//and IV derivation keys from the given database passphrase +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)"; + +//PBKDF_ITERATIONS: Number of hash iterations used in the key derivation +//process. +const int PBKDF_ITERATIONS = 10000; + +//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) +const int KEY_SIZE = 512/8; //512 bit, 64 byte key. (256 bit XTS key) + +//IV_DERIVATION_KEY_SIZE: Size of the key used with the CMAC (MAC_STR) +//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); + + 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); + + 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; + + SymmetricKey + m_readKey, + m_writeKey, + m_ivReadKey, + m_ivWriteKey; + + Pipe + m_encipherPipe, + m_decipherPipe, + m_macPipe; + + Keyed_Filter *m_encipherFilter; + Keyed_Filter *m_decipherFilter; + MAC_Filter *m_cmac; + + int m_pageSize; + unsigned char m_page[SQLITE_MAX_PAGE_SIZE]; + void *m_db; + const char *m_botanErrorMsg; + + InitializationVector GetIVForPage(u32bit page, bool useWriteKey); + void InitializeCodec(void *db); +}; + +#endif diff --git a/src/contrib/sqlite/codec_c_interface.h b/src/contrib/sqlite/codec_c_interface.h new file mode 100644 index 000000000..9f515c113 --- /dev/null +++ b/src/contrib/sqlite/codec_c_interface.h @@ -0,0 +1,90 @@ +/* + * Encryption codec class C interface + * (C) 2010 Olivier de Gaalon + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#ifndef _CODEC_C_INTERFACE_H_ +#define _CODEC_C_INTERFACE_H_ + +#ifdef __cplusplus +typedef unsigned char Bool; +#endif + +#ifdef __cplusplus +extern "C" +#endif +void InitializeBotan(); + +#ifdef __cplusplus +extern "C" +#endif +void* InitializeNewCodec(void *db); + +#ifdef __cplusplus +extern "C" +#endif +void* InitializeFromOtherCodec(const void *otherCodec, void *db); + +#ifdef __cplusplus +extern "C" +#endif +void GenerateWriteKey(void *codec, const char *userPassword, int passwordLength); + +#ifdef __cplusplus +extern "C" +#endif +void DropWriteKey(void *codec); + +#ifdef __cplusplus +extern "C" +#endif +void SetWriteIsRead(void *codec); + +#ifdef __cplusplus +extern "C" +#endif +void SetReadIsWrite(void *codec); + +#ifdef __cplusplus +extern "C" +#endif +unsigned char* Encrypt(void *codec, int page, unsigned char *data, Bool useWriteKey); + +#ifdef __cplusplus +extern "C" +#endif +void Decrypt(void *codec, int page, unsigned char *data); + +#ifdef __cplusplus +extern "C" +#endif +void SetPageSize(void *codec, int pageSize); + +#ifdef __cplusplus +extern "C" +#endif +Bool HasReadKey(void *codec); + +#ifdef __cplusplus +extern "C" +#endif +Bool HasWriteKey(void *codec); + +#ifdef __cplusplus +extern "C" +#endif +void* GetDB(void *codec); + +#ifdef __cplusplus +extern "C" +#endif +const char* GetAndResetError(void *codec); + +#ifdef __cplusplus +extern "C" +#endif +void DeleteCodec(void *codec); + +#endif
\ No newline at end of file diff --git a/src/contrib/sqlite/codecext.c b/src/contrib/sqlite/codecext.c new file mode 100644 index 000000000..f44c04a2e --- /dev/null +++ b/src/contrib/sqlite/codecext.c @@ -0,0 +1,242 @@ +/* + * Encryption codec implementation + * (C) 2010 Olivier de Gaalon + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#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; + 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, SQLITE_ERROR); + + // 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/contrib/sqlite/readme.txt b/src/contrib/sqlite/readme.txt new file mode 100644 index 000000000..4971fd44b --- /dev/null +++ b/src/contrib/sqlite/readme.txt @@ -0,0 +1,35 @@ +Build instructions for BotanSqlite3 +--- + +Requirements: + 1. Botan 1.9.0 or later + 2. SQLite3 amalgamation source, version 3.7.12.1 or later (previous versions may work, some will need minor changes) + + +Building: + +1. Extract sqlite3 amalgamation to a directory and add BotanSqlite3 source files + + If desired, codec.h can be modified to tweak the encryption algothrithms and parameters. (Defaults to Twofish/XTS with 256 bit key) + +2. Apply the patch "sqlite3.diff": + $ patch -p0 < sqlite3-amalgamation.patch + + If the patching fails for some reason (ie, changes in SQLite3), it should be trivial to do it manually. + +3. Compile the sqlite3 library with Botan encryption support: + $ gcc -c sqlite3.c -o botansqlite3.o && gcc -c codec.cpp -o codec.o `pkg-config --cflags botan-1.10` && ar rcs libbotansqlite3.a botansqlite3.o codec.o + + (replace "botan-1.10" with appropriate version) + +Testing: + +1. Build the test: + $ g++ test_sqlite.cpp -o test_sqlite `botan-config-1.10 --libs` ./libbotansqlite3.a + + (replace botan-config-1.10 w/ appropriate version) + +2. Run the test + $ ./test_sqlite + +3. Look for "All seems good" diff --git a/src/contrib/sqlite/sqlite3-amalgamation.patch b/src/contrib/sqlite/sqlite3-amalgamation.patch new file mode 100644 index 000000000..1c2a5c69d --- /dev/null +++ b/src/contrib/sqlite/sqlite3-amalgamation.patch @@ -0,0 +1,15 @@ +--- ./sqlite3.c.orig 2011-05-12 10:03:32.051879390 +0800 ++++ ./sqlite3.c 2011-05-12 10:09:04.028550281 +0800 +@@ -17,6 +17,7 @@ + ** language. The code for the "sqlite3" command-line shell is also in a + ** separate file. This file contains only code for the core SQLite library. + */ ++#define SQLITE_HAS_CODEC 1 + #define SQLITE_CORE 1 + #define SQLITE_AMALGAMATION 1 + #ifndef SQLITE_PRIVATE +@@ -125956,3 +125957,4 @@ + #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ + + /************** End of fts3_icu.c ********************************************/ ++#include "codecext.c" diff --git a/src/contrib/sqlite/test_sqlite.cpp b/src/contrib/sqlite/test_sqlite.cpp new file mode 100644 index 000000000..74bf24b06 --- /dev/null +++ b/src/contrib/sqlite/test_sqlite.cpp @@ -0,0 +1,103 @@ +/* + * Quick and dirty test for SQLite3 encryption codec. + * (C) 2010 Olivier de Gaalon + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#define SQLITE_HAS_CODEC 1 + +#include <sqlite3.h> +#include <stdio.h> + +namespace SQL +{ + const char * CREATE_TABLE_TEST = + "create table 'test' (id INTEGER PRIMARY KEY, name TEXT, creationtime TEXT);"; + const char * CREATE_TABLE_TEST2 = + "create table 'test2' (id INTEGER PRIMARY KEY, name TEXT, creationtime TEXT);"; + const char * INSERT_INTO_TEST = + "INSERT INTO test (name, creationtime) VALUES ('widget', '1st time');\ + INSERT INTO test (name, creationtime) VALUES ('widget', '2nd time');\ + INSERT INTO test (name, creationtime) VALUES ('widget', '3rd time');\ + INSERT INTO test (name, creationtime) VALUES ('widget', '4th time');\ + INSERT INTO test (name, creationtime) VALUES ('widget', '5th time');"; + const char * INSERT_INTO_TEST2 = + "INSERT INTO test2 (name, creationtime) VALUES ('widget2', '1st time2');\ + INSERT INTO test2 (name, creationtime) VALUES ('widget2', '2nd time2');\ + INSERT INTO test2 (name, creationtime) VALUES ('widget2', '3rd time2');\ + INSERT INTO test2 (name, creationtime) VALUES ('widget2', '4th time2');\ + INSERT INTO test2 (name, creationtime) VALUES ('widget2', '5th time2');"; + const char * SELECT_FROM_TEST = + "SELECT * FROM test;"; + const char * SELECT_FROM_TEST2 = + "SELECT * FROM test2;"; +}; + +static int callback(void *NotUsed, int argc, char **argv, char **azColName){ + int i; + fprintf(stderr, "\t"); + for(i=0; i<argc; i++){ + fprintf(stderr, "%s = %s | ", azColName[i], argv[i] ? argv[i] : "NULL"); + } + fprintf(stderr, "\n"); + return 0; +} + +int main(int argc, char** argv) +{ + sqlite3 * db; + const char * key = "anotherkey"; + const char * dbname = "./testdb"; + int keylen = 7; + char * error=0; + + fprintf(stderr, "Creating Database \"%s\"\n", dbname); + int rc = sqlite3_open(dbname, &db); + if (rc != SQLITE_OK) { fprintf(stderr, "Can't open/create database: %s\n", sqlite3_errmsg(db)); return 1; } + + fprintf(stderr, "Keying Database with key \"%s\"\n", key); + rc = sqlite3_key(db, key, keylen); + if (rc != SQLITE_OK) { fprintf(stderr, "Can't key database: %s\n", sqlite3_errmsg(db)); return 1; } + + fprintf(stderr, "Creating table \"test\"\n"); + rc = sqlite3_exec(db, SQL::CREATE_TABLE_TEST, 0, 0, &error); + if (rc != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", error); return 1; } + + fprintf(stderr, "Creating table \"test2\"\n"); + rc = sqlite3_exec(db, SQL::CREATE_TABLE_TEST2, 0, 0, &error); + if (rc != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", error); return 1; } + + fprintf(stderr, "Inserting into table \"test\"\n"); + rc = sqlite3_exec(db, SQL::INSERT_INTO_TEST, 0, 0, &error); + if (rc != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", error); return 1; } + + fprintf(stderr, "Inserting into table \"test2\"\n"); + rc = sqlite3_exec(db, SQL::INSERT_INTO_TEST2, 0, 0, &error); + if (rc != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", error); return 1; } + + fprintf(stderr, "Closing Database \"%s\"\n", dbname); + sqlite3_close(db); + + fprintf(stderr, "Opening Database \"%s\"\n", dbname); + rc = sqlite3_open(dbname, &db); + if (rc != SQLITE_OK) { fprintf(stderr, "Can't open/create database: %s\n", sqlite3_errmsg(db)); return 1; } + + fprintf(stderr, "Keying Database with key \"%s\"\n", key); + rc = sqlite3_key(db, key, keylen); + if (rc != SQLITE_OK) { fprintf(stderr, "Can't key database: %s\n", sqlite3_errmsg(db)); return 1; } + + fprintf(stderr, "Selecting all from test\n"); + rc = sqlite3_exec(db, SQL::SELECT_FROM_TEST, callback, 0, &error); + if (rc != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", error); return 1; } + + fprintf(stderr, "Selecting all from test2\n"); + rc = sqlite3_exec(db, SQL::SELECT_FROM_TEST2, callback, 0, &error); + if (rc != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", error); return 1; } + + fprintf(stderr, "Closing Database \"%s\"\n", dbname); + sqlite3_close(db); + + fprintf(stderr, "All Seems Good \n"); + return 0; +} |