From 930b441e8175d101b8805fb14ebcd5691c15b56f Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Mon, 25 Nov 2013 10:34:09 -0600 Subject: [PATCH 01/12] Add PRAGMA cipher_add_random to source external entropy --- src/crypto.c | 9 ++++++++- src/crypto.h | 1 + src/crypto_impl.c | 28 +++++++++++++++++++++++++--- src/crypto_libtomcrypt.c | 12 ++++++++++-- 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 6038d5a..2696c33 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -88,7 +88,14 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef } CODEC_TRACE(("sqlcipher_codec_pragma: entered db=%p iDb=%d pParse=%p zLeft=%s zRight=%s ctx=%p\n", db, iDb, pParse, zLeft, zRight, ctx)); - + + if( sqlite3StrICmp(zLeft, "cipher_add_random")==0 && zRight ){ + if(ctx) { + char *add_random_status = sqlite3_mprintf("%d", sqlcipher_codec_add_random(ctx, zRight)); + codec_vdbe_return_static_string(pParse, "cipher_add_random", add_random_status); + sqlite3_free(add_random_status); + } + } else if( sqlite3StrICmp(zLeft, "cipher_migrate")==0 && !zRight ){ if(ctx){ char *migrate_status = sqlite3_mprintf("%d", sqlcipher_codec_ctx_migrate(ctx)); diff --git a/src/crypto.h b/src/crypto.h index ba0d399..805cfb0 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -213,6 +213,7 @@ int sqlcipher_codec_ctx_get_flag(codec_ctx *ctx, unsigned int flag, int for_ctx) const char* sqlcipher_codec_get_cipher_provider(codec_ctx *ctx); int sqlcipher_codec_ctx_migrate(codec_ctx *ctx); +int sqlcipher_codec_add_random(codec_ctx *ctx, const char *data); #endif #endif /* END SQLCIPHER */ diff --git a/src/crypto_impl.c b/src/crypto_impl.c index 7974f57..dac92f7 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -83,6 +83,7 @@ struct codec_ctx { cipher_ctx *read_ctx; cipher_ctx *write_ctx; unsigned int skip_read_hmac; + unsigned int need_kdf_salt; }; int sqlcipher_register_provider(sqlcipher_provider *p) { @@ -650,8 +651,7 @@ int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, sqlite3_f if((rc = sqlcipher_cipher_ctx_init(&ctx->write_ctx)) != SQLITE_OK) return rc; if(fd == NULL || sqlite3OsRead(fd, ctx->kdf_salt, FILE_HEADER_SZ, 0) != SQLITE_OK) { - /* if unable to read the bytes, generate random salt */ - if(ctx->read_ctx->provider->random(ctx->read_ctx->provider_ctx, ctx->kdf_salt, FILE_HEADER_SZ) != SQLITE_OK) return SQLITE_ERROR; + ctx->need_kdf_salt = 1; } if((rc = sqlcipher_codec_ctx_set_cipher(ctx, CIPHER, 0)) != SQLITE_OK) return rc; @@ -823,8 +823,13 @@ static int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) { c_ctx->pass, c_ctx->pass_sz, ctx->kdf_salt, ctx->kdf_salt_sz, c_ctx->kdf_iter, ctx->hmac_kdf_salt, c_ctx->fast_kdf_iter, c_ctx->key_sz)); - + if(c_ctx->pass && c_ctx->pass_sz) { // if pass is not null + + if(ctx->need_kdf_salt) { + if(ctx->read_ctx->provider->random(ctx->read_ctx->provider_ctx, ctx->kdf_salt, FILE_HEADER_SZ) != SQLITE_OK) return SQLITE_ERROR; + ctx->need_kdf_salt = 0; + } if (c_ctx->pass_sz == ((c_ctx->key_sz * 2) + 3) && sqlite3StrNICmp((const char *)c_ctx->pass ,"x'", 2) == 0) { int n = c_ctx->pass_sz - 3; /* adjust for leading x' and tailing ' */ const unsigned char *z = c_ctx->pass + 2; /* adjust lead offset of x' */ @@ -1119,6 +1124,23 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) { return rc; } +int sqlcipher_codec_add_random(codec_ctx *ctx, const char *zRight){ + int random_sz = strlen(zRight); + if (random_sz == ((ctx->read_ctx->key_sz * 2) + 3) && sqlite3StrNICmp((const char *)zRight ,"x'", 2) == 0) { + unsigned char *random; + int n = random_sz - 3; /* adjust for leading x' and tailing ' */ + const unsigned char *z = (const unsigned char *)zRight + 2; /* adjust lead offset of x' */ + CODEC_TRACE(("sqlcipher_codec_add_random: using raw random blob from hex\n")); + random = sqlcipher_malloc(n); + memset(random, 0, n); + cipher_hex2bin(z, n, random); + int rc = ctx->read_ctx->provider->add_random(ctx->read_ctx->provider_ctx, random, n); + sqlcipher_free(random, n); + return rc; + } + return SQLITE_ERROR; +} + #endif /* END SQLCIPHER */ diff --git a/src/crypto_libtomcrypt.c b/src/crypto_libtomcrypt.c index 9df5781..f9c5bd9 100644 --- a/src/crypto_libtomcrypt.c +++ b/src/crypto_libtomcrypt.c @@ -39,12 +39,20 @@ typedef struct { prng_state prng; } ltc_ctx; +static unsigned int random_block_sz = 32; static unsigned int ltc_init = 0; static int sqlcipher_ltc_add_random(void *ctx, void *buffer, int length) { ltc_ctx *ltc = (ltc_ctx*)ctx; - int rc = fortuna_add_entropy(buffer, length, &(ltc->prng)); - return rc != CRYPT_OK ? SQLITE_ERROR : SQLITE_OK; + int block_count = length / random_block_sz; + for(int block_idx = 0; block_idx < block_count; block_idx++){ + int rc = fortuna_add_entropy(buffer, random_block_sz, &(ltc->prng)); + buffer += random_block_sz; + if(rc != CRYPT_OK) { + return SQLITE_ERROR; + } + } + return SQLITE_OK; } static int sqlcipher_ltc_activate(void *ctx) { From bc058122a80e27294f149dc752dac6f5344ef903 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Mon, 25 Nov 2013 11:52:30 -0600 Subject: [PATCH 02/12] Static ltc prng state, add partitioned data to prng --- src/crypto_libtomcrypt.c | 49 ++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/src/crypto_libtomcrypt.c b/src/crypto_libtomcrypt.c index f9c5bd9..3907c2e 100644 --- a/src/crypto_libtomcrypt.c +++ b/src/crypto_libtomcrypt.c @@ -39,20 +39,31 @@ typedef struct { prng_state prng; } ltc_ctx; +static ltc_ctx *ltc_state = {0}; static unsigned int random_block_sz = 32; static unsigned int ltc_init = 0; +static unsigned int ltc_ref_count = 0; +static sqlite3_mutex* ltc_rand_mutex = NULL; static int sqlcipher_ltc_add_random(void *ctx, void *buffer, int length) { ltc_ctx *ltc = (ltc_ctx*)ctx; + int rc = 0; int block_count = length / random_block_sz; +#ifndef SQLCIPHER_LTC_NO_MUTEX_RAND + sqlite3_mutex_enter(ltc_rand_mutex); +#endif for(int block_idx = 0; block_idx < block_count; block_idx++){ - int rc = fortuna_add_entropy(buffer, random_block_sz, &(ltc->prng)); + rc = fortuna_add_entropy(buffer, random_block_sz, &(ltc->prng)); buffer += random_block_sz; - if(rc != CRYPT_OK) { - return SQLITE_ERROR; + rc = rc != CRYPT_OK ? SQLITE_ERROR : SQLITE_OK; + if(rc != SQLITE_OK) { + break; } } - return SQLITE_OK; +#ifndef SQLCIPHER_LTC_NO_MUTEX_RAND + sqlite3_mutex_leave(ltc_rand_mutex); +#endif + return rc; } static int sqlcipher_ltc_activate(void *ctx) { @@ -65,11 +76,16 @@ static int sqlcipher_ltc_activate(void *ctx) { if(register_prng(&fortuna_desc) != CRYPT_OK) return SQLITE_ERROR; if(register_cipher(&rijndael_desc) != CRYPT_OK) return SQLITE_ERROR; if(register_hash(&sha1_desc) != CRYPT_OK) return SQLITE_ERROR; +#ifndef SQLCIPHER_LTC_NO_MUTEX_RAND + if(ltc_rand_mutex == NULL){ + ltc_rand_mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + } +#endif + if(fortuna_start(&(ltc->prng)) != CRYPT_OK) { + return SQLITE_ERROR; + } ltc_init = 1; } - if(fortuna_start(&(ltc->prng)) != CRYPT_OK) { - return SQLITE_ERROR; - } sqlite3_randomness(random_buffer_sz, random_buffer); if(sqlcipher_ltc_add_random(ctx, random_buffer, random_buffer_sz) != SQLITE_OK) { return SQLITE_ERROR; @@ -81,12 +97,20 @@ static int sqlcipher_ltc_activate(void *ctx) { return SQLITE_ERROR; } sqlcipher_free(random_buffer, random_buffer_sz); + ltc_ref_count++; return SQLITE_OK; } static int sqlcipher_ltc_deactivate(void *ctx) { ltc_ctx *ltc = (ltc_ctx*)ctx; - fortuna_done(&(ltc->prng)); + ltc_ref_count--; + if(ltc_ref_count == 0){ + fortuna_done(&(ltc->prng)); +#ifndef SQLCIPHER_LTC_NO_MUTEX_RAND + sqlite3_mutex_free(ltc_rand_mutex); + ltc_rand_mutex = NULL; +#endif + } return SQLITE_OK; } @@ -190,7 +214,10 @@ static int sqlcipher_ltc_ctx_cmp(void *c1, void *c2) { } static int sqlcipher_ltc_ctx_init(void **ctx) { - *ctx = sqlcipher_malloc(sizeof(ltc_ctx)); + if(!ltc_state){ + ltc_state = sqlcipher_malloc(sizeof(ltc_ctx)); + } + *ctx = ltc_state; if(*ctx == NULL) return SQLITE_NOMEM; sqlcipher_ltc_activate(*ctx); return SQLITE_OK; @@ -198,7 +225,9 @@ static int sqlcipher_ltc_ctx_init(void **ctx) { static int sqlcipher_ltc_ctx_free(void **ctx) { sqlcipher_ltc_deactivate(&ctx); - sqlcipher_free(*ctx, sizeof(ltc_ctx)); + if(ltc_ref_count == 0){ + sqlcipher_free(*ctx, sizeof(ltc_ctx)); + } return SQLITE_OK; } From 8348d8e1ed469258271945141ad2ec773d7c49a4 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Mon, 25 Nov 2013 14:46:26 -0600 Subject: [PATCH 03/12] Fix compilation for Windows --- src/crypto_impl.c | 3 ++- src/crypto_libtomcrypt.c | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/crypto_impl.c b/src/crypto_impl.c index dac92f7..6ef38bd 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -1127,6 +1127,7 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) { int sqlcipher_codec_add_random(codec_ctx *ctx, const char *zRight){ int random_sz = strlen(zRight); if (random_sz == ((ctx->read_ctx->key_sz * 2) + 3) && sqlite3StrNICmp((const char *)zRight ,"x'", 2) == 0) { + int rc = 0; unsigned char *random; int n = random_sz - 3; /* adjust for leading x' and tailing ' */ const unsigned char *z = (const unsigned char *)zRight + 2; /* adjust lead offset of x' */ @@ -1134,7 +1135,7 @@ int sqlcipher_codec_add_random(codec_ctx *ctx, const char *zRight){ random = sqlcipher_malloc(n); memset(random, 0, n); cipher_hex2bin(z, n, random); - int rc = ctx->read_ctx->provider->add_random(ctx->read_ctx->provider_ctx, random, n); + rc = ctx->read_ctx->provider->add_random(ctx->read_ctx->provider_ctx, random, n); sqlcipher_free(random, n); return rc; } diff --git a/src/crypto_libtomcrypt.c b/src/crypto_libtomcrypt.c index 3907c2e..85ae059 100644 --- a/src/crypto_libtomcrypt.c +++ b/src/crypto_libtomcrypt.c @@ -47,14 +47,15 @@ static sqlite3_mutex* ltc_rand_mutex = NULL; static int sqlcipher_ltc_add_random(void *ctx, void *buffer, int length) { ltc_ctx *ltc = (ltc_ctx*)ctx; - int rc = 0; + int rc, block_idx = 0; int block_count = length / random_block_sz; + const unsigned char * data = (const unsigned char *)buffer; #ifndef SQLCIPHER_LTC_NO_MUTEX_RAND sqlite3_mutex_enter(ltc_rand_mutex); #endif - for(int block_idx = 0; block_idx < block_count; block_idx++){ - rc = fortuna_add_entropy(buffer, random_block_sz, &(ltc->prng)); - buffer += random_block_sz; + for(; block_idx < block_count; block_idx++){ + rc = fortuna_add_entropy(data, random_block_sz, &(ltc->prng)); + data += random_block_sz; rc = rc != CRYPT_OK ? SQLITE_ERROR : SQLITE_OK; if(rc != SQLITE_OK) { break; From b5ece4677962b99d2a44ef2c33fcf93c60a958ec Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Mon, 25 Nov 2013 17:39:26 -0600 Subject: [PATCH 04/12] Remove ltc_ctx, adjust sqlcipher_ltc_add_random behavior --- src/crypto_libtomcrypt.c | 70 ++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 43 deletions(-) diff --git a/src/crypto_libtomcrypt.c b/src/crypto_libtomcrypt.c index 85ae059..467f08a 100644 --- a/src/crypto_libtomcrypt.c +++ b/src/crypto_libtomcrypt.c @@ -35,32 +35,33 @@ #include "sqlcipher.h" #include -typedef struct { - prng_state prng; -} ltc_ctx; - -static ltc_ctx *ltc_state = {0}; +static prng_state prng; static unsigned int random_block_sz = 32; static unsigned int ltc_init = 0; static unsigned int ltc_ref_count = 0; static sqlite3_mutex* ltc_rand_mutex = NULL; static int sqlcipher_ltc_add_random(void *ctx, void *buffer, int length) { - ltc_ctx *ltc = (ltc_ctx*)ctx; - int rc, block_idx = 0; - int block_count = length / random_block_sz; + int rc = 0; + int data_to_read = length; + int block_sz = data_to_read < random_block_sz ? data_to_read : random_block_sz; const unsigned char * data = (const unsigned char *)buffer; #ifndef SQLCIPHER_LTC_NO_MUTEX_RAND sqlite3_mutex_enter(ltc_rand_mutex); #endif - for(; block_idx < block_count; block_idx++){ - rc = fortuna_add_entropy(data, random_block_sz, &(ltc->prng)); - data += random_block_sz; - rc = rc != CRYPT_OK ? SQLITE_ERROR : SQLITE_OK; - if(rc != SQLITE_OK) { - break; + while(data_to_read > 0){ + rc = fortuna_add_entropy(data, block_sz, &prng); + rc = rc != CRYPT_OK ? SQLITE_ERROR : SQLITE_OK; + if(rc != SQLITE_OK){ + break; + } + data_to_read -= block_sz; + if(data_to_read > 0){ + block_sz = data_to_read < random_block_sz ? data_to_read : random_block_sz; + data += block_sz; + } } - } + fortuna_ready(&prng); #ifndef SQLCIPHER_LTC_NO_MUTEX_RAND sqlite3_mutex_leave(ltc_rand_mutex); #endif @@ -68,11 +69,10 @@ static int sqlcipher_ltc_add_random(void *ctx, void *buffer, int length) { } static int sqlcipher_ltc_activate(void *ctx) { - ltc_ctx *ltc = (ltc_ctx*)ctx; int random_buffer_sz = sizeof(char) * 32; unsigned char *random_buffer = sqlcipher_malloc(random_buffer_sz); sqlcipher_memset(random_buffer, 0, random_buffer_sz); - + if(ltc_init == 0) { if(register_prng(&fortuna_desc) != CRYPT_OK) return SQLITE_ERROR; if(register_cipher(&rijndael_desc) != CRYPT_OK) return SQLITE_ERROR; @@ -82,7 +82,7 @@ static int sqlcipher_ltc_activate(void *ctx) { ltc_rand_mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); } #endif - if(fortuna_start(&(ltc->prng)) != CRYPT_OK) { + if(fortuna_start(&prng) != CRYPT_OK) { return SQLITE_ERROR; } ltc_init = 1; @@ -91,22 +91,15 @@ static int sqlcipher_ltc_activate(void *ctx) { if(sqlcipher_ltc_add_random(ctx, random_buffer, random_buffer_sz) != SQLITE_OK) { return SQLITE_ERROR; } - if(sqlcipher_ltc_add_random(ctx, <c, sizeof(ltc_ctx*)) != SQLITE_OK) { - return SQLITE_ERROR; - } - if(fortuna_ready(&(ltc->prng)) != CRYPT_OK) { - return SQLITE_ERROR; - } sqlcipher_free(random_buffer, random_buffer_sz); ltc_ref_count++; return SQLITE_OK; } static int sqlcipher_ltc_deactivate(void *ctx) { - ltc_ctx *ltc = (ltc_ctx*)ctx; ltc_ref_count--; if(ltc_ref_count == 0){ - fortuna_done(&(ltc->prng)); + fortuna_done(&prng); #ifndef SQLCIPHER_LTC_NO_MUTEX_RAND sqlite3_mutex_free(ltc_rand_mutex); ltc_rand_mutex = NULL; @@ -120,13 +113,14 @@ static const char* sqlcipher_ltc_get_provider_name(void *ctx) { } static int sqlcipher_ltc_random(void *ctx, void *buffer, int length) { - ltc_ctx *ltc = (ltc_ctx*)ctx; int rc; - - if((rc = fortuna_ready(&(ltc->prng))) != CRYPT_OK) { - return SQLITE_ERROR; - } - fortuna_read(buffer, length, &(ltc->prng)); +#ifndef SQLCIPHER_LTC_NO_MUTEX_RAND + sqlite3_mutex_enter(ltc_rand_mutex); +#endif + fortuna_read(buffer, length, &prng); +#ifndef SQLCIPHER_LTC_NO_MUTEX_RAND + sqlite3_mutex_leave(ltc_rand_mutex); +#endif return SQLITE_OK; } @@ -145,7 +139,6 @@ static int sqlcipher_ltc_hmac(void *ctx, unsigned char *hmac_key, int key_sz, un static int sqlcipher_ltc_kdf(void *ctx, const unsigned char *pass, int pass_sz, unsigned char* salt, int salt_sz, int workfactor, int key_sz, unsigned char *key) { int rc, hash_idx; - ltc_ctx *ltc = (ltc_ctx*)ctx; unsigned long outlen = key_sz; unsigned long random_buffer_sz = sizeof(char) * 256; unsigned char *random_buffer = sqlcipher_malloc(random_buffer_sz); @@ -206,7 +199,6 @@ static int sqlcipher_ltc_get_hmac_sz(void *ctx) { } static int sqlcipher_ltc_ctx_copy(void *target_ctx, void *source_ctx) { - memcpy(target_ctx, source_ctx, sizeof(ltc_ctx)); return SQLITE_OK; } @@ -215,20 +207,12 @@ static int sqlcipher_ltc_ctx_cmp(void *c1, void *c2) { } static int sqlcipher_ltc_ctx_init(void **ctx) { - if(!ltc_state){ - ltc_state = sqlcipher_malloc(sizeof(ltc_ctx)); - } - *ctx = ltc_state; - if(*ctx == NULL) return SQLITE_NOMEM; - sqlcipher_ltc_activate(*ctx); + sqlcipher_ltc_activate(NULL); return SQLITE_OK; } static int sqlcipher_ltc_ctx_free(void **ctx) { sqlcipher_ltc_deactivate(&ctx); - if(ltc_ref_count == 0){ - sqlcipher_free(*ctx, sizeof(ltc_ctx)); - } return SQLITE_OK; } From 4b31a370062721200ca6c624057190cac6d01bd9 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Tue, 26 Nov 2013 09:52:55 -0600 Subject: [PATCH 05/12] Enforce prefix and suffix format for cipher_add_random --- src/crypto_impl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/crypto_impl.c b/src/crypto_impl.c index 6ef38bd..9a94582 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -1126,7 +1126,8 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) { int sqlcipher_codec_add_random(codec_ctx *ctx, const char *zRight){ int random_sz = strlen(zRight); - if (random_sz == ((ctx->read_ctx->key_sz * 2) + 3) && sqlite3StrNICmp((const char *)zRight ,"x'", 2) == 0) { + const char *suffix = &zRight[random_sz-1]; + if (sqlite3StrNICmp((const char *)zRight ,"x'", 2) == 0 && sqlite3StrNICmp(suffix, "'", 1) == 0) { int rc = 0; unsigned char *random; int n = random_sz - 3; /* adjust for leading x' and tailing ' */ From 200b3146a35949451ab5cd764f02f57ff1115783 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Tue, 3 Dec 2013 13:32:05 -0600 Subject: [PATCH 06/12] Adjustment to ltc crypto provider and cipher_add_random --- src/crypto.c | 2 +- src/crypto.h | 2 +- src/crypto_impl.c | 19 ++++++++------ src/crypto_libtomcrypt.c | 50 +++++++++++++++++++++++-------------- test/crypto.test | 53 ++++++++++++++++++++++++++++++++++++++-- 5 files changed, 95 insertions(+), 31 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 2696c33..e326840 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -91,7 +91,7 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef if( sqlite3StrICmp(zLeft, "cipher_add_random")==0 && zRight ){ if(ctx) { - char *add_random_status = sqlite3_mprintf("%d", sqlcipher_codec_add_random(ctx, zRight)); + char *add_random_status = sqlite3_mprintf("%d", sqlcipher_codec_add_random(ctx, zRight, sqlite3Strlen30(zRight))); codec_vdbe_return_static_string(pParse, "cipher_add_random", add_random_status); sqlite3_free(add_random_status); } diff --git a/src/crypto.h b/src/crypto.h index 805cfb0..ce5cf0b 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -213,7 +213,7 @@ int sqlcipher_codec_ctx_get_flag(codec_ctx *ctx, unsigned int flag, int for_ctx) const char* sqlcipher_codec_get_cipher_provider(codec_ctx *ctx); int sqlcipher_codec_ctx_migrate(codec_ctx *ctx); -int sqlcipher_codec_add_random(codec_ctx *ctx, const char *data); +int sqlcipher_codec_add_random(codec_ctx *ctx, const char *data, int random_sz); #endif #endif /* END SQLCIPHER */ diff --git a/src/crypto_impl.c b/src/crypto_impl.c index 9a94582..47ff0e7 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -1124,20 +1124,23 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) { return rc; } -int sqlcipher_codec_add_random(codec_ctx *ctx, const char *zRight){ - int random_sz = strlen(zRight); +int sqlcipher_codec_add_random(codec_ctx *ctx, const char *zRight, int random_sz){ const char *suffix = &zRight[random_sz-1]; - if (sqlite3StrNICmp((const char *)zRight ,"x'", 2) == 0 && sqlite3StrNICmp(suffix, "'", 1) == 0) { + int n = random_sz - 3; /* adjust for leading x' and tailing ' */ + if (n > 0 && + sqlite3StrNICmp((const char *)zRight ,"x'", 2) == 0 && + sqlite3StrNICmp(suffix, "'", 1) == 0 && + n % 2 == 0) { int rc = 0; + int buffer_sz = n / 2; unsigned char *random; - int n = random_sz - 3; /* adjust for leading x' and tailing ' */ const unsigned char *z = (const unsigned char *)zRight + 2; /* adjust lead offset of x' */ CODEC_TRACE(("sqlcipher_codec_add_random: using raw random blob from hex\n")); - random = sqlcipher_malloc(n); - memset(random, 0, n); + random = sqlcipher_malloc(buffer_sz); + memset(random, 0, buffer_sz); cipher_hex2bin(z, n, random); - rc = ctx->read_ctx->provider->add_random(ctx->read_ctx->provider_ctx, random, n); - sqlcipher_free(random, n); + rc = ctx->read_ctx->provider->add_random(ctx->read_ctx->provider_ctx, random, buffer_sz); + sqlcipher_free(random, buffer_sz); return rc; } return SQLITE_ERROR; diff --git a/src/crypto_libtomcrypt.c b/src/crypto_libtomcrypt.c index 467f08a..382073c 100644 --- a/src/crypto_libtomcrypt.c +++ b/src/crypto_libtomcrypt.c @@ -35,8 +35,8 @@ #include "sqlcipher.h" #include +#define FORTUNA_MAX_SZ 32 static prng_state prng; -static unsigned int random_block_sz = 32; static unsigned int ltc_init = 0; static unsigned int ltc_ref_count = 0; static sqlite3_mutex* ltc_rand_mutex = NULL; @@ -44,7 +44,7 @@ static sqlite3_mutex* ltc_rand_mutex = NULL; static int sqlcipher_ltc_add_random(void *ctx, void *buffer, int length) { int rc = 0; int data_to_read = length; - int block_sz = data_to_read < random_block_sz ? data_to_read : random_block_sz; + int block_sz = data_to_read < FORTUNA_MAX_SZ ? data_to_read : FORTUNA_MAX_SZ; const unsigned char * data = (const unsigned char *)buffer; #ifndef SQLCIPHER_LTC_NO_MUTEX_RAND sqlite3_mutex_enter(ltc_rand_mutex); @@ -56,10 +56,8 @@ static int sqlcipher_ltc_add_random(void *ctx, void *buffer, int length) { break; } data_to_read -= block_sz; - if(data_to_read > 0){ - block_sz = data_to_read < random_block_sz ? data_to_read : random_block_sz; - data += block_sz; - } + data += block_sz; + block_sz = data_to_read < FORTUNA_MAX_SZ ? data_to_read : FORTUNA_MAX_SZ; } fortuna_ready(&prng); #ifndef SQLCIPHER_LTC_NO_MUTEX_RAND @@ -69,42 +67,56 @@ static int sqlcipher_ltc_add_random(void *ctx, void *buffer, int length) { } static int sqlcipher_ltc_activate(void *ctx) { - int random_buffer_sz = sizeof(char) * 32; - unsigned char *random_buffer = sqlcipher_malloc(random_buffer_sz); - sqlcipher_memset(random_buffer, 0, random_buffer_sz); - + unsigned char random_buffer[FORTUNA_MAX_SZ]; +#ifndef SQLCIPHER_LTC_NO_MUTEX_RAND + if(ltc_rand_mutex == NULL){ + ltc_rand_mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + } + sqlite3_mutex_enter(ltc_rand_mutex); +#endif + sqlcipher_memset(random_buffer, 0, FORTUNA_MAX_SZ); if(ltc_init == 0) { if(register_prng(&fortuna_desc) != CRYPT_OK) return SQLITE_ERROR; if(register_cipher(&rijndael_desc) != CRYPT_OK) return SQLITE_ERROR; if(register_hash(&sha1_desc) != CRYPT_OK) return SQLITE_ERROR; -#ifndef SQLCIPHER_LTC_NO_MUTEX_RAND - if(ltc_rand_mutex == NULL){ - ltc_rand_mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); - } -#endif if(fortuna_start(&prng) != CRYPT_OK) { return SQLITE_ERROR; } ltc_init = 1; } - sqlite3_randomness(random_buffer_sz, random_buffer); - if(sqlcipher_ltc_add_random(ctx, random_buffer, random_buffer_sz) != SQLITE_OK) { + ltc_ref_count++; +#ifndef SQLCIPHER_TEST + sqlite3_randomness(FORTUNA_MAX_SZ, random_buffer); +#endif +#ifndef SQLCIPHER_LTC_NO_MUTEX_RAND + sqlite3_mutex_leave(ltc_rand_mutex); +#endif + if(sqlcipher_ltc_add_random(ctx, random_buffer, FORTUNA_MAX_SZ) != SQLITE_OK) { return SQLITE_ERROR; } - sqlcipher_free(random_buffer, random_buffer_sz); - ltc_ref_count++; + sqlcipher_memset(random_buffer, 0, FORTUNA_MAX_SZ); return SQLITE_OK; } static int sqlcipher_ltc_deactivate(void *ctx) { +#ifndef SQLCIPHER_LTC_NO_MUTEX_RAND + sqlite3_mutex_enter(ltc_rand_mutex); +#endif ltc_ref_count--; if(ltc_ref_count == 0){ fortuna_done(&prng); + sqlcipher_memset((void *)&prng, 0, sizeof(prng)); #ifndef SQLCIPHER_LTC_NO_MUTEX_RAND + sqlite3_mutex_leave(ltc_rand_mutex); sqlite3_mutex_free(ltc_rand_mutex); ltc_rand_mutex = NULL; #endif } +#ifndef SQLCIPHER_LTC_NO_MUTEX_RAND + else { + sqlite3_mutex_leave(ltc_rand_mutex); + } +#endif return SQLITE_OK; } diff --git a/test/crypto.test b/test/crypto.test index 75c7f16..91ff009 100644 --- a/test/crypto.test +++ b/test/crypto.test @@ -87,6 +87,21 @@ proc if_built_with_commoncrypto {name cmd expected} { } } +proc cmpFilesChunked {file1 file2 {chunksize 16384}} { + set f1 [open $file1]; fconfigure $f1 -translation binary + set f2 [open $file2]; fconfigure $f2 -translation binary + while {1} { + set d1 [read $f1 $chunksize] + set d2 [read $f2 $chunksize] + set diff [string compare $d1 $d2] + if {$diff != 0 || [eof $f1] || [eof $f2]} { + close $f1; close $f2 + return $diff + } + } + return 0 +} + # The database is initially empty. # set an hex key create some basic data # create table and insert operations should work @@ -413,9 +428,9 @@ file delete -force test.db setup test.db "'testkey'" do_test attach-database-with-default-key { sqlite_orig db2 test2.db - execsql { PRAGMA key = 'testkey'; + PRAGMA cipher_add_random = "x'deadbaad'"; CREATE TABLE t2(a,b); INSERT INTO t2 VALUES ('test1', 'test2'); } db2 @@ -423,7 +438,7 @@ do_test attach-database-with-default-key { catchsql { ATTACH 'test.db' AS db; } db2 - + } {1 {file is encrypted or is not a database}} db2 close file delete -force test.db @@ -2114,5 +2129,39 @@ db close file delete -force test.db file delete -force new.db +# Requires SQLCipher to be built with -DSQLCIPHER_TEST +if_built_with_libtomcrypt verify-random-data-alters-file-content { + file delete -force test.db + file delete -force test2.db + file delete -force test3.db + set rc {} + + sqlite_orig db test.db + execsql { + PRAGMA key="x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; + create table t1(a,b); + } + db close + sqlite_orig db test2.db + execsql { + PRAGMA key="x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; + create table t1(a,b); + } + db close + sqlite_orig db test3.db + execsql { + PRAGMA key="x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; + PRAGMA cipher_add_random = "x'deadbaad'"; + create table t1(a,b); + } + db close + lappend rc [cmpFilesChunked test.db test2.db] + lappend rc [cmpFilesChunked test2.db test3.db] +} {0 1} +file delete -force test.db +file delete -force test2.db +file delete -force test3.db + + sqlite3_test_control_pending_byte $old_pending_byte finish_test From b03221fc90598cc3af37ebbf743ea436a767a646 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Tue, 3 Dec 2013 13:37:56 -0600 Subject: [PATCH 07/12] Remove unused variable --- src/crypto_libtomcrypt.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/crypto_libtomcrypt.c b/src/crypto_libtomcrypt.c index 382073c..22f4efc 100644 --- a/src/crypto_libtomcrypt.c +++ b/src/crypto_libtomcrypt.c @@ -125,7 +125,6 @@ static const char* sqlcipher_ltc_get_provider_name(void *ctx) { } static int sqlcipher_ltc_random(void *ctx, void *buffer, int length) { - int rc; #ifndef SQLCIPHER_LTC_NO_MUTEX_RAND sqlite3_mutex_enter(ltc_rand_mutex); #endif From bba319a716a713815008c1935d8449de1af72420 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Fri, 6 Dec 2013 11:03:50 -0600 Subject: [PATCH 08/12] Fix for cipher_migrate on passphrases longer than 64 characters and raw keys --- src/crypto_impl.c | 6 +++--- test/crypto.test | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/crypto_impl.c b/src/crypto_impl.c index 47ff0e7..2170f20 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -995,14 +995,14 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) { char *attach_command = sqlite3_mprintf("ATTACH DATABASE '%s-migrated' as migrate KEY '%q';", db_filename, key); - int rc = sqlcipher_check_connection(db_filename, key, key_sz, "", &user_version); + int rc = sqlcipher_check_connection(db_filename, key, ctx->read_ctx->pass_sz, "", &user_version); if(rc == SQLITE_OK){ CODEC_TRACE(("No upgrade required - exiting\n")); goto exit; } // Version 2 - check for 4k with hmac format - rc = sqlcipher_check_connection(db_filename, key, key_sz, pragma_4k_kdf_iter, &user_version); + rc = sqlcipher_check_connection(db_filename, key, ctx->read_ctx->pass_sz, pragma_4k_kdf_iter, &user_version); if(rc == SQLITE_OK) { CODEC_TRACE(("Version 2 format found\n")); upgrade_4k_format = 1; @@ -1011,7 +1011,7 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) { // 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, key_sz, pragma_1x_and_4k, &user_version); + rc = sqlcipher_check_connection(db_filename, key, ctx->read_ctx->pass_sz, pragma_1x_and_4k, &user_version); sqlite3_free(pragma_1x_and_4k); if(rc == SQLITE_OK) { CODEC_TRACE(("Version 1 format found\n")); diff --git a/test/crypto.test b/test/crypto.test index 91ff009..5dd4515 100644 --- a/test/crypto.test +++ b/test/crypto.test @@ -2162,6 +2162,42 @@ file delete -force test.db file delete -force test2.db file delete -force test3.db +do_test can-migrate-with-keys-longer-than-64-characters { + sqlite_orig db test.db + execsql { + PRAGMA key = "012345678901234567890123456789012345678901234567890123456789012345"; + PRAGMA kdf_iter = 4000; + PRAGMA user_version = 5; + } + db close + sqlite_orig db test.db + execsql { + PRAGMA key = "012345678901234567890123456789012345678901234567890123456789012345"; + PRAGMA cipher_migrate; + PRAGMA user_version; + } +} {0 5} +db close +file delete -force test.db + +do_test can-migrate-with-raw-hex-key { + sqlite_orig db test.db + execsql { + PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; + PRAGMA kdf_iter = 4000; + PRAGMA cipher_use_hmac = off; + PRAGMA user_version = 5; + } + db close + sqlite_orig db test.db + execsql { + PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; + PRAGMA cipher_migrate; + PRAGMA user_version; + } +} {0 5} +db close +file delete -force test.db sqlite3_test_control_pending_byte $old_pending_byte finish_test From c5360e120ea8d801619485b30161eb37fc2ac677 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Fri, 6 Dec 2013 11:12:48 -0600 Subject: [PATCH 09/12] Nop for adding random to commoncrypto --- src/crypto_cc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/crypto_cc.c b/src/crypto_cc.c index c994c91..707deca 100644 --- a/src/crypto_cc.c +++ b/src/crypto_cc.c @@ -36,6 +36,10 @@ #include #include +static int sqlcipher_cc_add_random(void *ctx, void *buffer, int length) { + return SQLITE_OK; +} + /* generate a defined number of random bytes */ static int sqlcipher_cc_random (void *ctx, void *buffer, int length) { return (SecRandomCopyBytes(kSecRandomDefault, length, (uint8_t *)buffer) == 0) ? SQLITE_OK : SQLITE_ERROR; @@ -132,6 +136,7 @@ int sqlcipher_cc_setup(sqlcipher_provider *p) { p->ctx_cmp = sqlcipher_cc_ctx_cmp; p->ctx_init = sqlcipher_cc_ctx_init; p->ctx_free = sqlcipher_cc_ctx_free; + p->add_random = sqlcipher_cc_add_random; return SQLITE_OK; } From fb1780bceb24b3400310e82135aa1a1e597c7a19 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Fri, 6 Dec 2013 11:14:50 -0600 Subject: [PATCH 10/12] Bump cipher version --- src/crypto.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto.h b/src/crypto.h index ce5cf0b..7b76c08 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -44,7 +44,7 @@ #define FILE_HEADER_SZ 16 #ifndef CIPHER_VERSION -#define CIPHER_VERSION "3.0.0" +#define CIPHER_VERSION "3.0.1" #endif #ifndef CIPHER From 8f110848f3088aafe05c410fc6f73ea03377556e Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Fri, 6 Dec 2013 11:33:40 -0600 Subject: [PATCH 11/12] Adjust cipher_version test --- test/crypto.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/crypto.test b/test/crypto.test index 5dd4515..1998ee3 100644 --- a/test/crypto.test +++ b/test/crypto.test @@ -1498,7 +1498,7 @@ do_test verify-pragma-cipher-version { execsql { PRAGMA cipher_version; } -} {3.0.0} +} {3.0.1} db close file delete -force test.db From 8d0acdb9082bb1d83c79818681f41c8fa59604b8 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Fri, 6 Dec 2013 11:34:26 -0600 Subject: [PATCH 12/12] Explicitly close db in tests following cipher_migrate --- test/crypto.test | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/test/crypto.test b/test/crypto.test index 1998ee3..825f034 100644 --- a/test/crypto.test +++ b/test/crypto.test @@ -2170,13 +2170,20 @@ do_test can-migrate-with-keys-longer-than-64-characters { PRAGMA user_version = 5; } db close + sqlite_orig db test.db execsql { - PRAGMA key = "012345678901234567890123456789012345678901234567890123456789012345"; + PRAGMA key = "012345678901234567890123456789012345678901234567890123456789012345"; PRAGMA cipher_migrate; + } + db close + + sqlite_orig db test.db + execsql { + PRAGMA key = "012345678901234567890123456789012345678901234567890123456789012345"; PRAGMA user_version; } -} {0 5} +} {5} db close file delete -force test.db @@ -2189,13 +2196,20 @@ do_test can-migrate-with-raw-hex-key { PRAGMA user_version = 5; } db close + sqlite_orig db test.db execsql { - PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; + PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; PRAGMA cipher_migrate; + } + + sqlite_orig db test.db + execsql { + PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'"; PRAGMA user_version; } -} {0 5} + +} {5} db close file delete -force test.db