From a1204dd3795bd9bd9d7ad7a78e568543d337fc6a Mon Sep 17 00:00:00 2001 From: Stephen Lombardo Date: Mon, 9 Oct 2023 14:17:11 -0400 Subject: [PATCH] add pragma page_size compatibility so it will operate on encrypted databases --- src/crypto.c | 9 ++++++++- test/sqlcipher-core.test | 46 ++++++++++++++++++++++++++++++++++++++++++++- test/sqlcipher-pragmas.test | 29 ++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 9c722fd4..fcb1d9d6 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -260,7 +260,12 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef sqlcipher_vdbe_return_string(pParse, "rekey_kdf_iter", message, P4_TRANSIENT); sqlite3_log(SQLITE_WARNING, message); }else - if( sqlite3_stricmp(zLeft,"cipher_page_size")==0 ){ + if( sqlite3_stricmp(zLeft,"page_size")==0 || sqlite3_stricmp(zLeft,"cipher_page_size")==0 ){ + /* PRAGMA cipher_page_size will alter the size of the database pages while ensuring that the + required reserve space is allocated at the end of each page. This will also override the + standard SQLite PRAGMA page_size behavior if a codec context is attached to the database handle. + If PRAGMA page_size is invoked but a codec context is not attached (i.e. dealing with a standard + unencrypted database) then return early and allow the standard PRAGMA page_size logic to apply. */ if(ctx) { if( zRight ) { int size = atoi(zRight); @@ -272,6 +277,8 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef char * page_size = sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_pagesize(ctx)); sqlcipher_vdbe_return_string(pParse, "cipher_page_size", page_size, P4_DYNAMIC); } + } else { + return 0; /* return early so that the PragTyp_PAGE_SIZE case logic in pragma.c will take effect */ } }else if( sqlite3_stricmp(zLeft,"cipher_default_page_size")==0 ){ diff --git a/test/sqlcipher-core.test b/test/sqlcipher-core.test index 5aed9fb6..c4b5e3bf 100644 --- a/test/sqlcipher-core.test +++ b/test/sqlcipher-core.test @@ -498,7 +498,7 @@ file delete -force test.db # key and page size # 4. verify that the table is readable # and the data just inserted is visible -do_test custom-pagesize { +do_test custom-pagesize-pragma-cipher-page-size { sqlite_orig db test.db execsql { @@ -528,11 +528,55 @@ do_test custom-pagesize { } {ok 1000} db close +file delete -force test.db + +# run the same logic as previous test but use +# pragma page_size instead +do_test custom-pagesize-pragma-pagesize { + sqlite_orig db test.db + + execsql { + PRAGMA key = 'testkey'; + PRAGMA page_size = 8192; + CREATE table t1(a,b); + BEGIN; + } + + for {set i 1} {$i<=1000} {incr i} { + set r [expr {int(rand()*500000)}] + execsql "INSERT INTO t1 VALUES($i,'value $r');" + } + + execsql { + COMMIT; + } + + db close + sqlite_orig db test.db + + execsql { + PRAGMA key = 'testkey'; + PRAGMA page_size = 8192; + SELECT count(*) FROM t1; + } + +} {ok 1000} +db close +file delete -force test.db # open the database with the default page size ## and verfiy that it is not readable do_test custom-pagesize-must-match { sqlite_orig db test.db + execsql { + PRAGMA key = 'testkey'; + PRAGMA cipher_page_size = 8192; + CREATE table t1(a,b); + } + + db close + sqlite_orig db test.db + catchsql { PRAGMA key = 'testkey'; SELECT name FROM sqlite_schema WHERE type='table'; diff --git a/test/sqlcipher-pragmas.test b/test/sqlcipher-pragmas.test index daf7f8a9..c7087bb9 100644 --- a/test/sqlcipher-pragmas.test +++ b/test/sqlcipher-pragmas.test @@ -202,6 +202,35 @@ do_test verify-pragma-cipher-page-size-changed { db close file delete -force test.db +# verify that a call to pragma page_size +# will report change via both page_size and cipher_page_size +# when there is an attached codec +do_test verify-pragma-page-size-encrypted { + sqlite_orig db test.db + execsql { + PRAGMA key = 'test'; + PRAGMA page_size = 8192; + PRAGMA page_size; + PRAGMA cipher_page_size; + } +} {ok 8192 8192} +db close +file delete -force test.db + +# verify that a call to pragma page_size +# will not report a change to cipher_page_size for an +# unencrypted database +do_test verify-pragma-page-size-plaintext { + sqlite_orig db test.db + execsql { + PRAGMA page_size = 8192; + PRAGMA page_size; + PRAGMA cipher_page_size; + } +} {8192} +db close +file delete -force test.db + # verify setting cipher_store_pass before key # does not cause segfault do_test verify-cipher-store-pass-before-key-does-not-segfault { -- 2.11.4.GIT