mirror of
https://github.com/status-im/sqlcipher.git
synced 2026-08-30 22:11:14 +00:00
adds PRAGMA default_cipher_plaintext_header_size and tests
This commit is contained in:
@@ -302,6 +302,15 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef
|
||||
}
|
||||
}
|
||||
}else
|
||||
if( sqlite3StrICmp(zLeft,"cipher_default_plaintext_header_size")==0 ){
|
||||
if( zRight ) {
|
||||
sqlcipher_set_default_plaintext_header_size(atoi(zRight));
|
||||
} else {
|
||||
char *size = sqlite3_mprintf("%d", sqlcipher_get_default_plaintext_header_size());
|
||||
codec_vdbe_return_static_string(pParse, "cipher_default_plaintext_header_size", size);
|
||||
sqlite3_free(size);
|
||||
}
|
||||
}else
|
||||
if( sqlite3StrICmp(zLeft,"cipher_salt")==0 ){
|
||||
if(ctx) {
|
||||
if(zRight) {
|
||||
|
||||
@@ -262,6 +262,8 @@ int sqlcipher_codec_hmac(const codec_ctx *ctx, const unsigned char *hmac_key, in
|
||||
unsigned char* in, int in_sz, unsigned char *in2, int in2_sz,
|
||||
unsigned char *out);
|
||||
|
||||
int sqlcipher_set_default_plaintext_header_size(int size);
|
||||
int sqlcipher_get_default_plaintext_header_size();
|
||||
int sqlcipher_codec_ctx_set_plaintext_header_size(codec_ctx *ctx, int size);
|
||||
int sqlcipher_codec_ctx_get_plaintext_header_size(codec_ctx *ctx);
|
||||
|
||||
|
||||
+18
-7
@@ -74,6 +74,7 @@ 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_plaintext_header_sz = 0;
|
||||
static unsigned int sqlcipher_activate_count = 0;
|
||||
static sqlite3_mutex* sqlcipher_provider_mutex = NULL;
|
||||
static sqlcipher_provider *default_provider = NULL;
|
||||
@@ -686,12 +687,17 @@ int sqlcipher_codec_ctx_get_use_hmac(codec_ctx *ctx, int for_ctx) {
|
||||
return (c_ctx->flags & CIPHER_FLAG_HMAC) != 0;
|
||||
}
|
||||
|
||||
/* the lenght of plaintext header size must be:
|
||||
* 1. greater than or equal to zero
|
||||
* 2. a multiple of the cipher block size
|
||||
* 3. less than the usable size of the first database page
|
||||
*/
|
||||
int sqlcipher_set_default_plaintext_header_size(int size) {
|
||||
default_plaintext_header_sz = size;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
int sqlcipher_codec_ctx_set_plaintext_header_size(codec_ctx *ctx, int size) {
|
||||
/* the lenght of plaintext header size must be:
|
||||
* 1. greater than or equal to zero
|
||||
* 2. a multiple of the cipher block size
|
||||
* 3. less than the usable size of the first database page
|
||||
*/
|
||||
if(size >= 0 && (size % ctx->read_ctx->block_sz) == 0 && size < (ctx->page_sz - ctx->read_ctx->reserve_sz)) {
|
||||
ctx->plaintext_header_sz = size;
|
||||
return SQLITE_OK;
|
||||
@@ -699,6 +705,10 @@ int sqlcipher_codec_ctx_set_plaintext_header_size(codec_ctx *ctx, int size) {
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
int sqlcipher_get_default_plaintext_header_size() {
|
||||
return default_plaintext_header_sz;
|
||||
}
|
||||
|
||||
int sqlcipher_codec_ctx_get_plaintext_header_size(codec_ctx *ctx) {
|
||||
return ctx->plaintext_header_sz;
|
||||
}
|
||||
@@ -795,8 +805,6 @@ int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, sqlite3_f
|
||||
|
||||
ctx->pBt = pDb->pBt; /* assign pointer to database btree structure */
|
||||
|
||||
ctx->plaintext_header_sz = 0; /* by default all data encrypted */
|
||||
|
||||
/* allocate space for salt data. Then read the first 16 bytes
|
||||
directly off the database file. This is the salt for the
|
||||
key derivation function. If we get a short read allocate
|
||||
@@ -853,6 +861,9 @@ int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, sqlite3_f
|
||||
CODEC_TRACE("sqlcipher_codec_ctx_init: copying write_ctx to read_ctx\n");
|
||||
if((rc = sqlcipher_cipher_ctx_copy(ctx->write_ctx, ctx->read_ctx)) != SQLITE_OK) return rc;
|
||||
|
||||
CODEC_TRACE("sqlcipher_codec_ctx_init: calling sqlcipher_codec_ctx_set_plaintext_header_size with %d\n", default_plaintext_header_sz);
|
||||
if((rc = sqlcipher_codec_ctx_set_plaintext_header_size(ctx, default_plaintext_header_sz)) != SQLITE_OK) return rc;
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
+80
-9
@@ -2346,7 +2346,6 @@ file delete -force encrypted.db
|
||||
|
||||
# verify that a when a standard database is encrypted the first
|
||||
# 16 bytes are not "SQLite format 3\0"
|
||||
# start of the database unencrypted, i.e.
|
||||
do_test test-sqlcipher-header-overwrite {
|
||||
sqlite_orig db test.db
|
||||
execsql {
|
||||
@@ -2373,8 +2372,7 @@ do_test test-pragma-salt-get {
|
||||
} {1}
|
||||
file delete -force test.db
|
||||
|
||||
# set the salt of a new database
|
||||
# of an existing database
|
||||
# explicitly set the salt of a new database
|
||||
do_test test-pragma-salt-set {
|
||||
set rc {}
|
||||
sqlite_orig db test.db
|
||||
@@ -2401,7 +2399,8 @@ file delete -force test.db
|
||||
set hexkeyspec "\"x'98483C6EB40B6C31A448C22A66DED3B5E5E8D5119CAC8327B655C8B5C483648101010101010101010101010101010101'\""
|
||||
|
||||
# verify that a raw key with a fixed salt will work
|
||||
# first 16 bytes of database should be equal to the specified salt
|
||||
# the first 16 bytes of database should be equal to the specified salt
|
||||
# which is the last 32 characters of the hex key spec.
|
||||
# also verify return value of cipher_salt
|
||||
do_test test-raw-key-with-salt-spec {
|
||||
set rc {}
|
||||
@@ -2425,7 +2424,8 @@ do_test test-raw-key-with-salt-spec {
|
||||
db close
|
||||
file delete -force test.db
|
||||
|
||||
# verify that a raw key with an invalid salt will not work
|
||||
# verify that a raw key with an invalid salt will not work to
|
||||
# open an existing database.
|
||||
# should cause hmac failure due to invalid generated HMAC key
|
||||
do_test test-raw-key-with-invalid-salt-spec {
|
||||
sqlite_orig db test.db
|
||||
@@ -2445,8 +2445,9 @@ do_test test-raw-key-with-invalid-salt-spec {
|
||||
db close
|
||||
file delete -force test.db
|
||||
|
||||
# verify that a raw key with a bad salt will work if page HMAC is disabled
|
||||
# in which case the salt will not actually be used for anything
|
||||
# verify that a raw key with a bad salt *will* work if page HMAC is disabled
|
||||
# in this case the salt will not actually be used for anything
|
||||
# because the encryption key is provided explicitly
|
||||
do_test test-raw-key-with-invalid-salt-spec-no-hmac {
|
||||
sqlite_orig db test.db
|
||||
execsql "
|
||||
@@ -2526,7 +2527,7 @@ file delete -force test.db
|
||||
# when using a standard mode database and 32 byte
|
||||
# plaintext header, ensure that bytes 16 - 19
|
||||
# corresponding to the page size and file versions, and reserve size
|
||||
# are readable and equal to 1024, 1, 1, and 48
|
||||
# are readable and equal to 1024, 1, 1, and 48 respectively
|
||||
do_test test-plaintext-header-journal-delete-mode-readable {
|
||||
sqlite_orig db test.db
|
||||
execsql {
|
||||
@@ -2544,7 +2545,7 @@ file delete -force test.db
|
||||
# when using a WAL mode database and 32 byte
|
||||
# plaintext header, ensure that bytes 16 - 19
|
||||
# corresponding to the page size and file versions, and reserve size
|
||||
# are readable and equal to 1024, 2, 2 and 48
|
||||
# are readable and equal to 1024, 2, 2 and 48 respectively
|
||||
do_test test-plaintext-header-journal-wal-mode-readable {
|
||||
sqlite_orig db test.db
|
||||
execsql {
|
||||
@@ -2559,6 +2560,76 @@ do_test test-plaintext-header-journal-wal-mode-readable {
|
||||
} {1}
|
||||
file delete -force test.db
|
||||
|
||||
# verify that a valid default_cipher_plaintext_header_size leaves the
|
||||
# start of the database unencrypted right from the start
|
||||
# , i.e. "SQLite format 3\0"
|
||||
do_test test-valid-default-plaintext-header-size {
|
||||
set rc {}
|
||||
sqlite_orig db test.db
|
||||
set salt [execsql {
|
||||
PRAGMA cipher_default_plaintext_header_size = 16;
|
||||
PRAGMA key = 'test';
|
||||
CREATE TABLE t1(a,b);
|
||||
INSERT INTO t1(a,b) VALUES (1,2);
|
||||
PRAGMA cipher_salt;
|
||||
}]
|
||||
db close
|
||||
|
||||
lappend rc [hexio_read test.db 0 16]
|
||||
|
||||
sqlite_orig db test.db
|
||||
lappend rc [execsql "
|
||||
PRAGMA key = 'test';
|
||||
PRAGMA cipher_salt = \"x'$salt'\";
|
||||
SELECT count(*) FROM t1;
|
||||
PRAGMA cipher_plaintext_header_size;
|
||||
"]
|
||||
|
||||
# reset the default back to 0 or subsequent tests will fail
|
||||
execsql "PRAGMA cipher_default_plaintext_header_size = 0;"
|
||||
|
||||
lappend rc [string equal $salt "53514c69746520666f726d6174203300"]
|
||||
} {53514C69746520666F726D6174203300 {1 16} 0}
|
||||
db close
|
||||
file delete -force test.db
|
||||
|
||||
# verify that a valid default_cipher_plaintext_header_size
|
||||
# operates properly on an attached database, and that the
|
||||
# salt pragma operates on the attached database as well
|
||||
do_test test-valid-default-plaintext-header-size-attach {
|
||||
set rc {}
|
||||
sqlite_orig db test.db
|
||||
set salt [execsql {
|
||||
PRAGMA cipher_default_plaintext_header_size = 16;
|
||||
PRAGMA key = 'test';
|
||||
CREATE TABLE temp(a);
|
||||
ATTACH DATABASE 'test2.db' as db2;
|
||||
CREATE TABLE db2.t2(a,b);
|
||||
INSERT INTO db2.t2(a,b) VALUES (1,2);
|
||||
PRAGMA db2.cipher_salt;
|
||||
DETACH DATABASE db2;
|
||||
}]
|
||||
db close
|
||||
lappend rc [hexio_read test2.db 0 16]
|
||||
|
||||
sqlite_orig db test2.db
|
||||
lappend rc [execsql "
|
||||
PRAGMA key = 'test';
|
||||
PRAGMA cipher_salt = \"x'$salt'\";
|
||||
SELECT count(*) FROM t2;
|
||||
PRAGMA cipher_plaintext_header_size;
|
||||
"]
|
||||
|
||||
# reset the default back to 0 or subsequent tests will fail
|
||||
execsql "PRAGMA cipher_default_plaintext_header_size = 0;"
|
||||
|
||||
lappend rc [string equal $salt "53514c69746520666f726d6174203300"]
|
||||
} {53514C69746520666F726D6174203300 {1 16} 0}
|
||||
db close
|
||||
file delete -force test.db
|
||||
file delete -force test2.db
|
||||
|
||||
|
||||
# migrate a standard database in place to use a
|
||||
# plaintext header offset by opening it, adjusting
|
||||
# the pragma, and rewriting the first page
|
||||
|
||||
Reference in New Issue
Block a user