From fee1153e5c9684d1588b105cbb3c2b7aff3af89b Mon Sep 17 00:00:00 2001 From: Stephen Lombardo Date: Thu, 30 Aug 2018 13:14:18 -0400 Subject: [PATCH] adjust default page size to 4096 --- src/crypto_impl.c | 127 +++++++++++++++++++++++++++------------------- test/crypto.test | 65 +++++++++++++++++------- 2 files changed, 122 insertions(+), 70 deletions(-) diff --git a/src/crypto_impl.c b/src/crypto_impl.c index 8da24339..c1f0161d 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -73,7 +73,7 @@ typedef struct { static unsigned int default_flags = DEFAULT_CIPHER_FLAGS; static unsigned char hmac_salt_mask = HMAC_SALT_MASK; static int default_kdf_iter = PBKDF2_ITER; -static int default_page_size = 1024; +static int default_page_size = 4096; static int default_plaintext_header_sz = 0; static unsigned int sqlcipher_activate_count = 0; static sqlite3_mutex* sqlcipher_provider_mutex = NULL; @@ -1198,29 +1198,22 @@ cleanup: return rc; } +static int pager_truncate(Pager *pPager, Pgno nPage); + int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) { u32 meta; - int rc = 0; - int command_idx = 0; - int password_sz; - int saved_flags; - int saved_nChange; - int saved_nTotalChange; + int i, password_sz, key_sz, saved_flags, saved_nChange, saved_nTotalChange, nRes, user_version = 0, upgrade_from = 0, rc = 0; u8 saved_mTrace; int (*saved_xTrace)(u32,void*,void*,void*); /* Saved db->xTrace */ Db *pDb = 0; sqlite3 *db = ctx->pBt->db; const char *db_filename = sqlite3_db_filename(db, "main"); char *migrated_db_filename = sqlite3_mprintf("%s-migrated", db_filename); - char *pragma_hmac_off = "PRAGMA cipher_use_hmac = OFF;"; - char *pragma_4k_kdf_iter = "PRAGMA kdf_iter = 4000;"; - char *pragma_1x_and_4k; - char *set_user_version; - char *key; - int key_sz; - int user_version = 0; - int upgrade_1x_format = 0; - int upgrade_4k_format = 0; + char *v1_pragmas = "PRAGMA cipher_use_hmac = OFF; PRAGMA kdf_iter = 4000; PRAGMA cipher_page_size = 1024;"; + char *v2_pragmas = "PRAGMA kdf_iter = 4000; PRAGMA cipher_page_size = 1024;"; + char *v3_pragmas = "PRAGMA kdf_iter = 64000; PRAGMA cipher_page_size = 1024;"; + char *set_user_version, *key; + Btree *pDest = NULL, *pSrc = NULL; static const unsigned char aCopy[] = { BTREE_SCHEMA_VERSION, 1, /* Add one to the old schema cookie */ BTREE_DEFAULT_CACHE_SIZE, 0, /* Preserve the default page cache size */ @@ -1229,6 +1222,7 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) { BTREE_APPLICATION_ID, 0, /* Preserve the application id */ }; + rc = user_version = upgrade_from = 0; key_sz = ctx->read_ctx->pass_sz + 1; key = sqlcipher_malloc(key_sz); @@ -1236,7 +1230,7 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) { memcpy(key, ctx->read_ctx->pass, ctx->read_ctx->pass_sz); if(db_filename){ - const char* commands[5]; + const char* commands[4]; char *attach_command = sqlite3_mprintf("ATTACH DATABASE '%s-migrated' as migrate KEY '%q';", db_filename, key); @@ -1245,44 +1239,51 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) { CODEC_TRACE("No upgrade required - exiting\n"); goto exit; } + + /* Version 3 - check for 64k with hmac format and 1024 page size */ + rc = sqlcipher_check_connection(db_filename, key, ctx->read_ctx->pass_sz, v3_pragmas, &user_version); + if(rc == SQLITE_OK) { + CODEC_TRACE("Version 3 format found\n"); + upgrade_from = 3; + } - // Version 2 - check for 4k with hmac format - rc = sqlcipher_check_connection(db_filename, key, ctx->read_ctx->pass_sz, pragma_4k_kdf_iter, &user_version); + /* Version 2 - check for 4k with hmac format and 1024 page size */ + rc = sqlcipher_check_connection(db_filename, key, ctx->read_ctx->pass_sz, v2_pragmas, &user_version); if(rc == SQLITE_OK) { CODEC_TRACE("Version 2 format found\n"); - upgrade_4k_format = 1; + upgrade_from = 2; } - // Version 1 - check both no hmac and 4k together - pragma_1x_and_4k = sqlite3_mprintf("%s%s", pragma_hmac_off, - pragma_4k_kdf_iter); - rc = sqlcipher_check_connection(db_filename, key, ctx->read_ctx->pass_sz, pragma_1x_and_4k, &user_version); - sqlite3_free(pragma_1x_and_4k); + /* Version 1 - check no HMAC, 4k KDF, and 1024 page size */ + rc = sqlcipher_check_connection(db_filename, key, ctx->read_ctx->pass_sz, v1_pragmas, &user_version); if(rc == SQLITE_OK) { CODEC_TRACE("Version 1 format found\n"); - upgrade_1x_format = 1; - upgrade_4k_format = 1; - } - - if(upgrade_1x_format == 0 && upgrade_4k_format == 0) { - CODEC_TRACE("Upgrade format not determined\n"); - goto handle_error; + upgrade_from = 1; } set_user_version = sqlite3_mprintf("PRAGMA migrate.user_version = %d;", user_version); - commands[0] = upgrade_4k_format == 1 ? pragma_4k_kdf_iter : ""; - commands[1] = upgrade_1x_format == 1 ? pragma_hmac_off : ""; - commands[2] = attach_command; - commands[3] = "SELECT sqlcipher_export('migrate');"; - commands[4] = set_user_version; + switch(upgrade_from) { + case 1: + commands[0] = v1_pragmas; + break; + case 2: + commands[0] = v2_pragmas; + break; + case 3: + commands[0] = v3_pragmas; + break; + default: + CODEC_TRACE("Upgrade format not determined\n"); + goto handle_error; + } + commands[1] = attach_command; + commands[2] = "SELECT sqlcipher_export('migrate');"; + commands[3] = set_user_version; - for(command_idx = 0; command_idx < ArraySize(commands); command_idx++){ - const char *command = commands[command_idx]; - if(strcmp(command, "") == 0){ - continue; - } - rc = sqlite3_exec(db, command, NULL, NULL, NULL); + for(i = 0; i < ArraySize(commands); i++){ + rc = sqlite3_exec(db, commands[i], NULL, NULL, NULL); if(rc != SQLITE_OK){ + CODEC_TRACE("migration step %d failed error code %d\n", i, rc); break; } } @@ -1291,9 +1292,6 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) { sqlcipher_free(key, key_sz); if(rc == SQLITE_OK){ - Btree *pDest; - Btree *pSrc; - int i = 0; if( !db->autoCommit ){ CODEC_TRACE("cannot migrate from within a transaction"); @@ -1316,32 +1314,53 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) { db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder); db->xTrace = 0; db->mTrace = 0; - pDest = db->aDb[0].pBt; pDb = &(db->aDb[db->nDb-1]); pSrc = pDb->pBt; - + + nRes = sqlite3BtreeGetOptimalReserve(pSrc); + rc = sqlite3BtreeSetPageSize(pDest, default_page_size, nRes, 0); + if( rc!=SQLITE_OK ) goto handle_error; + CODEC_TRACE("set BTree page size to %d res %d rc %d\n", default_page_size, nRes, rc); + rc = sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL); + if( rc!=SQLITE_OK ) goto handle_error; + + pager_truncate(pDest->pBt->pPager, 0); + rc = sqlite3BtreeBeginTrans(pSrc, 2); + if( rc!=SQLITE_OK ) goto handle_error; + rc = sqlite3BtreeBeginTrans(pDest, 2); - + if( rc!=SQLITE_OK ) goto handle_error; + assert( 1==sqlite3BtreeIsInTrans(pDest) ); assert( 1==sqlite3BtreeIsInTrans(pSrc) ); + CODEC_TRACE("started transactions\n"); + sqlite3CodecGetKey(db, db->nDb - 1, (void**)&key, &password_sz); sqlite3CodecAttach(db, 0, key, password_sz); sqlite3pager_get_codec(pDest->pBt->pPager, (void**)&ctx); - + ctx->skip_read_hmac = 1; + for(i=0; iskip_read_hmac = 0; if( rc!=SQLITE_OK ) goto handle_error; + CODEC_TRACE("copied btree %d\n", rc); + rc = sqlite3BtreeCommit(pDest); + if( rc!=SQLITE_OK ) goto handle_error; + CODEC_TRACE("committed destination transaction %d\n", rc); db->flags = saved_flags; db->nChange = saved_nChange; @@ -1356,17 +1375,19 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) { remove(migrated_db_filename); sqlite3_free(migrated_db_filename); } else { - CODEC_TRACE("*** migration failure** \n\n"); + CODEC_TRACE("*** migration failure** error code: %d\n", rc); } } goto exit; - handle_error: +handle_error: + if(pDest) sqlite3BtreeRollback(pDest, SQLITE_OK, 0); + CODEC_TRACE("An error occurred attempting to migrate the database\n"); rc = SQLITE_ERROR; - exit: +exit: return rc; } diff --git a/test/crypto.test b/test/crypto.test index 62ea4692..ec69fa88 100644 --- a/test/crypto.test +++ b/test/crypto.test @@ -1,4 +1,3 @@ -# SQLCipher # codec.test developed by Stephen Lombardo (Zetetic LLC) # sjlombardo at zetetic dot net # http://zetetic.net @@ -878,7 +877,7 @@ do_test custom-pagesize { execsql { PRAGMA key = 'testkey'; - PRAGMA cipher_page_size = 4096; + PRAGMA cipher_page_size = 8192; CREATE table t1(a,b); BEGIN; } @@ -897,7 +896,7 @@ do_test custom-pagesize { execsql { PRAGMA key = 'testkey'; - PRAGMA cipher_page_size = 4096; + PRAGMA cipher_page_size = 8192; SELECT count(*) FROM t1; } @@ -1003,6 +1002,7 @@ do_test open-1.1.8-database { PRAGMA key = 'testkey'; PRAGMA cipher_use_hmac = off; PRAGMA kdf_iter = 4000; + PRAGMA cipher_page_size = 1024; SELECT count(*) FROM t1; SELECT distinct * FROM t1; } @@ -1018,6 +1018,7 @@ do_test attach-and-copy-1.1.8 { PRAGMA key = 'testkey'; PRAGMA cipher_use_hmac = OFF; PRAGMA kdf_iter = 4000; + PRAGMA cipher_page_size = 1024; ATTACH DATABASE 'test.db' AS db2 KEY 'testkey-hmac'; CREATE TABLE db2.t1(a,b); INSERT INTO db2.t1 SELECT * FROM main.t1; @@ -1056,7 +1057,7 @@ do_test attached-database-pragmas { execsql { COMMIT; ATTACH DATABASE 'test2.db' AS db2 KEY 'testkey2'; - PRAGMA db2.cipher_page_size = 4096; + PRAGMA db2.cipher_page_size = 8192; PRAGMA db2.cipher = 'aes-128-cbc'; PRAGMA db2.kdf_iter = 1000; PRAGMA db2.cipher_use_hmac = OFF; @@ -1069,7 +1070,7 @@ do_test attached-database-pragmas { sqlite_orig db test2.db execsql { PRAGMA key = 'testkey2'; - PRAGMA cipher_page_size = 4096; + PRAGMA cipher_page_size = 8192; PRAGMA cipher = 'aes-128-cbc'; PRAGMA kdf_iter = 1000; PRAGMA cipher_use_hmac = OFF; @@ -1135,7 +1136,7 @@ do_test export-database { COMMIT; ATTACH DATABASE 'test2.db' AS db2 KEY 'testkey2'; - PRAGMA db2.cipher_page_size = 4096; + PRAGMA db2.cipher_page_size = 8192; SELECT sqlcipher_export('db2'); @@ -1146,7 +1147,7 @@ do_test export-database { sqlite_orig db test2.db execsql { PRAGMA key = 'testkey2'; - PRAGMA cipher_page_size = 4096; + PRAGMA cipher_page_size = 8192; SELECT count(*) FROM t1; SELECT count(*) FROM v1; SELECT count(*) FROM sqlite_sequence; @@ -1455,7 +1456,7 @@ do_test cipher-options-before-keys { execsql { PRAGMA kdf_iter = 1000; - PRAGMA cipher_page_size = 4096; + PRAGMA cipher_page_size = 8192; PRAGMA cipher = 'aes-128-cbc'; PRAGMA cipher_use_hmac = OFF; PRAGMA key = 'testkey'; @@ -1486,12 +1487,14 @@ do_test default-hmac-kdf-attach { execsql { PRAGMA cipher_default_use_hmac = OFF; PRAGMA cipher_default_kdf_iter = 4000; + PRAGMA cipher_default_page_size = 1024; PRAGMA key = 'testkey'; SELECT count(*) FROM t1; ATTACH 'sqlcipher-1.1.8-testkey.db' AS db2 KEY 'testkey'; SELECT count(*) from db2.t1; PRAGMA cipher_default_use_hmac = ON; PRAGMA cipher_default_kdf_iter = 64000; + PRAGMA cipher_default_kdf_iter = 4096; } } {75709 75709} db close @@ -1535,10 +1538,12 @@ do_test change-default-hmac-kdf-attach { SELECT count(*) FROM t1; PRAGMA cipher_default_use_hmac = OFF; PRAGMA cipher_default_kdf_iter = 4000; + PRAGMA cipher_default_page_size = 1024; ATTACH 'sqlcipher-1.1.8-testkey.db' AS db2 KEY 'testkey'; SELECT count(*) from db2.t1; PRAGMA cipher_default_use_hmac = ON; PRAGMA cipher_default_kdf_iter = 64000; + PRAGMA cipher_default_page_size = 4096; } } {1 75709} db close @@ -1721,6 +1726,7 @@ do_test open-3.0-le-database { sqlite_orig db $sampleDir/sqlcipher-3.0-testkey.db execsql { PRAGMA key = 'testkey'; + PRAGMA cipher_page_size = 1024; SELECT count(*) FROM t1; SELECT distinct * FROM t1; } @@ -1734,6 +1740,7 @@ do_test open-2.0-le-database { execsql { PRAGMA key = 'testkey'; PRAGMA kdf_iter = 4000; + PRAGMA cipher_page_size = 1024; SELECT count(*) FROM t1; SELECT distinct * FROM t1; } @@ -1748,6 +1755,7 @@ do_test open-2.0-be-database { PRAGMA key = 'testkey'; PRAGMA cipher_hmac_pgno = be; PRAGMA kdf_iter = 4000; + PRAGMA cipher_page_size = 1024; SELECT count(*) FROM t1; SELECT distinct * FROM t1; } @@ -1765,6 +1773,7 @@ do_test be-to-le-migration { PRAGMA key = 'testkey'; PRAGMA cipher_hmac_pgno = be; PRAGMA kdf_iter = 4000; + PRAGMA cipher_page_size = 1024; ATTACH DATABASE 'test.db' AS db2 KEY 'testkey'; CREATE TABLE db2.t1(a,b); INSERT INTO db2.t1 SELECT * FROM main.t1; @@ -1917,7 +1926,7 @@ do_test verify-pragma-cipher-page-size-default { PRAGMA key = 'test'; PRAGMA cipher_page_size; } -} {1024} +} {4096} db close file delete -force test.db @@ -1927,10 +1936,10 @@ do_test verify-pragma-cipher-page-size-changed { sqlite_orig db test.db execsql { PRAGMA key = 'test'; - PRAGMA cipher_page_size = 4096; + PRAGMA cipher_page_size = 8192; PRAGMA cipher_page_size; } -} {4096} +} {8192} db close file delete -force test.db @@ -2033,6 +2042,7 @@ do_test open-2.0-beta-database { PRAGMA kdf_iter = 4000; PRAGMA fast_kdf_iter = 4000; PRAGMA cipher_hmac_salt_mask = "x'00'"; + PRAGMA cipher_page_size = 1024; SELECT count(*) FROM t1; SELECT distinct * FROM t1; } @@ -2051,6 +2061,7 @@ do_test 2.0-beta-to-2.0-migration { PRAGMA cipher_hmac_salt_mask = "x'00'"; PRAGMA kdf_iter = 4000; PRAGMA fast_kdf_iter = 4000; + PRAGMA cipher_page_size = 1024; SELECT count(*) FROM sqlite_master; PRAGMA cipher_hmac_salt_mask = "x'3a'"; @@ -2089,9 +2100,9 @@ if_built_with_commoncrypto verify-default-cipher { } } {aes-256-cbc} db close -file delete -force test.db +file delete -force test.db test.db-migrated test.db-journal -do_test migrate-1.1.8-database-to-3x-format { +do_test migrate-1.1.8-database-to-current-format { file copy -force $sampleDir/sqlcipher-1.1.8-testkey.db test.db sqlite_orig db test.db execsql { @@ -2107,9 +2118,9 @@ do_test migrate-1.1.8-database-to-3x-format { } } {1} db close -file delete -force test.db +file delete -force test.db test.db-migrated test.db-journal -do_test migrate-2-0-le-database-to-3x-format { +do_test migrate-2-0-le-database-to-current-format { file copy -force $sampleDir/sqlcipher-2.0-le-testkey.db test.db sqlite_orig db test.db execsql { @@ -2125,6 +2136,24 @@ do_test migrate-2-0-le-database-to-3x-format { } } {1} db close +file delete -force test.db test.db-migrated test.db-journal + +do_test migrate-3-0-database-to-current-format { + file copy -force $sampleDir/sqlcipher-3.0-testkey.db test.db + sqlite_orig db test.db + execsql { + PRAGMA key = 'testkey'; + PRAGMA cipher_migrate; + } + db close + + sqlite_orig db test.db + execsql { + PRAGMA key = 'testkey'; + SELECT count(*) FROM sqlite_master; + } +} {1} +db close file delete -force test.db do_test key-database-by-name { @@ -2233,6 +2262,7 @@ do_test can-migrate-with-keys-longer-than-64-characters { sqlite_orig db test.db execsql { PRAGMA key = "012345678901234567890123456789012345678901234567890123456789012345"; + PRAGMA cipher_page_size = 1024; PRAGMA kdf_iter = 4000; PRAGMA user_version = 5; } @@ -2258,6 +2288,7 @@ do_test can-migrate-with-raw-hex-key { sqlite_orig db test.db execsql { PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; + PRAGMA cipher_page_size = 1024; PRAGMA kdf_iter = 4000; PRAGMA cipher_use_hmac = off; PRAGMA user_version = 5; @@ -2284,7 +2315,7 @@ do_test attach_database_with_non_default_page_size { sqlite_orig db test2.db execsql { PRAGMA key = 'test'; - PRAGMA cipher_page_size = 4096; + PRAGMA cipher_page_size = 8192; CREATE TABLE t1(a,b); INSERT INTO t1(a,b) values('one for the money', 'two for the show'); INSERT INTO t1(a,b) values('three to get ready', 'now, go cat, go'); @@ -2293,7 +2324,7 @@ do_test attach_database_with_non_default_page_size { sqlite_orig db test.db execsql { - PRAGMA cipher_default_page_size = 4096; + PRAGMA cipher_default_page_size = 8192; PRAGMA key = 'test'; ATTACH DATABASE 'test2.db' as test2 KEY 'test'; SELECT count(*) FROM test2.t1;