diff --git a/src/crypto.c b/src/crypto.c index 36b7f77..7608cc5 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -45,11 +45,13 @@ typedef struct { int key_sz; int iv_sz; + int pass_sz; int rekey_plaintext; void *key; void *buffer; void *rekey; void *salt; + void *pass; Btree *pBt; } codec_ctx; @@ -268,7 +270,13 @@ int sqlite3CodecAttach(sqlite3* db, int nDb, const void *zKey, int nKey) { /* allocate space for salt data */ ctx->key = sqlite3Malloc(ctx->key_sz); if(ctx->key == NULL) return SQLITE_NOMEM; - + + /* allocate space for raw key data */ + ctx->pass = sqlite3Malloc(nKey); + if(ctx->pass == NULL) return SQLITE_NOMEM; + memcpy(ctx->pass, zKey, nKey); + ctx->pass_sz = nKey; + /* read the first 16 bytes directly off the database file. This is the salt. */ sqlite3_file *fd = sqlite3Pager_get_fd(pPager); if(fd == NULL || sqlite3OsRead(fd, ctx->salt, 16, 0) != SQLITE_OK) { @@ -309,6 +317,11 @@ int sqlite3FreeCodecArg(void *pCodecArg) { memset(ctx->salt, 0, FILE_HEADER_SZ); sqlite3_free(ctx->salt); } + + if(ctx->pass) { + memset(ctx->pass, 0, ctx->pass_sz); + sqlite3_free(ctx->pass); + } memset(ctx, 0, sizeof(codec_ctx)); sqlite3_free(ctx); @@ -407,6 +420,15 @@ int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey) { if(rc == SQLITE_OK) { rc = sqlite3BtreeCommit(pDb->pBt); memcpy(ctx->key, ctx->rekey, key_sz); + if(ctx->pass) { + memset(ctx->pass, 0, ctx->pass_sz); + sqlite3_free(ctx->pass); + } + ctx->pass = sqlite3Malloc(nKey); + if(ctx->pass == NULL) return SQLITE_NOMEM; + memcpy(ctx->pass, pKey, nKey); + ctx->pass_sz = nKey; + } else { printf("error\n"); sqlite3BtreeRollback(pDb->pBt); @@ -435,8 +457,8 @@ void sqlite3CodecGetKey(sqlite3* db, int nDb, void **zKey, int *nKey) { /* if the codec has an attached codec_context user the raw key data */ if(ctx) { - *zKey = ctx->key; - *nKey = ctx->key_sz; + *zKey = ctx->pass; + *nKey = ctx->pass_sz; } else { *zKey = 0; *nKey = 0; diff --git a/test/crypto.test b/test/crypto.test index 39da1ed..c919e12 100644 --- a/test/crypto.test +++ b/test/crypto.test @@ -38,6 +38,7 @@ file delete -force test.db file delete -force test2.db +file delete -force test3.db set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -203,6 +204,39 @@ do_test codec-1.11 { } {25000} db close +db2 close + +# attach an encrypted database +do_test codec-1.12 { + sqlite_orig db3 test3.db + + execsql { + BEGIN; + PRAGMA key = 'testkey'; + CREATE TABLE t3(a,b); + } db3 + + for {set i 1} {$i<=15000} {incr i} { + set r [expr {int(rand()*500000)}] + execsql "INSERT INTO t3 VALUES($i,$r);" db3 + } + + execsql { + COMMIT; + } db3 + + db3 close + + sqlite_orig db2 test2.db + + execsql { + PRAGMA key = 'testkey'; + SELECT count(*) FROM t2; + ATTACH 'test3.db' AS db3; + SELECT count(*) FROM db3.t3; + } db2 + +} {25000 15000} finish_test