From 487e15dc239ccdb3344d1c99ce120e872bab4a74 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 20 Sep 2012 18:34:38 -0400 Subject: Imported Upstream version 2.0.6 --- src/crypto_impl.c | 72 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 20 deletions(-) (limited to 'src/crypto_impl.c') diff --git a/src/crypto_impl.c b/src/crypto_impl.c index 336afbd..c58ae60 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -79,6 +79,8 @@ int sqlcipher_cipher_ctx_key_derive(codec_ctx *, cipher_ctx *); /* prototype for pager HMAC function */ int sqlcipher_page_hmac(cipher_ctx *, Pgno, unsigned char *, int, unsigned char *); +static int default_use_hmac = DEFAULT_USE_HMAC; + struct codec_ctx { int kdf_salt_sz; int page_sz; @@ -98,6 +100,14 @@ void sqlcipher_activate() { sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); } +/* fixed time zero memory check tests every position of a memory segement + matches a single value (i.e. the memory is all zeros)*/ +int sqlcipher_ismemset(const unsigned char *a0, unsigned char value, int len) { + int i = 0, noMatch = 0; + for(i = 0; i < len; i++) noMatch = (noMatch || (a0[i] != value)); + return noMatch; +} + /* fixed time memory comparison routine */ int sqlcipher_memcmp(const unsigned char *a0, const unsigned char *a1, int len) { int i = 0, noMatch = 0; @@ -183,7 +193,7 @@ int sqlcipher_cipher_ctx_init(cipher_ctx **iCtx) { */ void sqlcipher_cipher_ctx_free(cipher_ctx **iCtx) { cipher_ctx *ctx = *iCtx; - CODEC_TRACE(("cipher_ctx_free: entered iCtx=%d\n", iCtx)); + CODEC_TRACE(("cipher_ctx_free: entered iCtx=%p\n", iCtx)); sqlcipher_free(ctx->key, ctx->key_sz); sqlcipher_free(ctx->hmac_key, ctx->key_sz); sqlcipher_free(ctx->pass, ctx->pass_sz); @@ -197,7 +207,7 @@ void sqlcipher_cipher_ctx_free(cipher_ctx **iCtx) { * returns 1 otherwise */ int sqlcipher_cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) { - CODEC_TRACE(("sqlcipher_cipher_ctx_cmp: entered c1=%d c2=%d\n", c1, c2)); + CODEC_TRACE(("sqlcipher_cipher_ctx_cmp: entered c1=%p c2=%p\n", c1, c2)); if( c1->evp_cipher == c2->evp_cipher @@ -206,6 +216,8 @@ int sqlcipher_cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) { && c1->fast_kdf_iter == c2->fast_kdf_iter && c1->key_sz == c2->key_sz && c1->pass_sz == c2->pass_sz + && c1->use_hmac == c2->use_hmac + && c1->hmac_sz == c2->hmac_sz && ( c1->pass == c2->pass || !sqlcipher_memcmp((const unsigned char*)c1->pass, @@ -228,7 +240,7 @@ int sqlcipher_cipher_ctx_copy(cipher_ctx *target, cipher_ctx *source) { void *key = target->key; void *hmac_key = target->hmac_key; - CODEC_TRACE(("sqlcipher_cipher_ctx_copy: entered target=%d, source=%d\n", target, source)); + CODEC_TRACE(("sqlcipher_cipher_ctx_copy: entered target=%p, source=%p\n", target, source)); sqlcipher_free(target->pass, target->pass_sz); memcpy(target, source, sizeof(cipher_ctx)); @@ -325,7 +337,12 @@ int sqlcipher_codec_ctx_set_fast_kdf_iter(codec_ctx *ctx, int fast_kdf_iter, int return SQLITE_OK; } +/* set the global default flag for HMAC */ +void sqlcipher_set_default_use_hmac(int use) { + default_use_hmac = use; +} +/* set the codec flag for whether this individual database should be using hmac */ int sqlcipher_codec_ctx_set_use_hmac(codec_ctx *ctx, int use) { int reserve = EVP_MAX_IV_LENGTH; /* base reserve size will be IV only */ @@ -346,7 +363,9 @@ int sqlcipher_codec_ctx_set_use_hmac(codec_ctx *ctx, int use) { } void sqlcipher_codec_ctx_set_error(codec_ctx *ctx, int error) { - ctx->pBt->db->errCode = error; + CODEC_TRACE(("sqlcipher_codec_ctx_set_error: ctx=%p, error=%d\n", ctx, error)); + sqlite3pager_sqlite3PagerSetError(ctx->pBt->pBt->pPager, error); + ctx->pBt->pBt->db->errCode = error; } int sqlcipher_codec_ctx_get_pagesize(codec_ctx *ctx) { @@ -432,7 +451,7 @@ int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, sqlite3_f /* Use HMAC signatures by default. Note that codec_set_use_hmac will implicity call codec_set_page_size to set the default */ - if((rc = sqlcipher_codec_ctx_set_use_hmac(ctx, DEFAULT_USE_HMAC)) != SQLITE_OK) return rc; + if((rc = sqlcipher_codec_ctx_set_use_hmac(ctx, default_use_hmac)) != SQLITE_OK) return rc; if((rc = sqlcipher_cipher_ctx_copy(ctx->write_ctx, ctx->read_ctx)) != SQLITE_OK) return rc; @@ -445,7 +464,7 @@ int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, sqlite3_f */ void sqlcipher_codec_ctx_free(codec_ctx **iCtx) { codec_ctx *ctx = *iCtx; - CODEC_TRACE(("codec_ctx_free: entered iCtx=%d\n", iCtx)); + CODEC_TRACE(("codec_ctx_free: entered iCtx=%p\n", iCtx)); sqlcipher_free(ctx->kdf_salt, ctx->kdf_salt_sz); sqlcipher_free(ctx->hmac_kdf_salt, ctx->kdf_salt_sz); sqlcipher_free(ctx->buffer, 0); @@ -494,12 +513,13 @@ int sqlcipher_page_cipher(codec_ctx *ctx, int for_ctx, Pgno pgno, int mode, int out_start = out; /* note the original position of the output buffer pointer, as out will be rewritten during encryption */ CODEC_TRACE(("codec_cipher:entered pgno=%d, mode=%d, size=%d\n", pgno, mode, size)); + CODEC_HEXDUMP("codec_cipher: input page data", in, page_sz); - /* just copy raw data from in to out when key size is 0 - * i.e. during a rekey of a plaintext database */ + /* the key size should never be zero. If it is, error out. */ if(c_ctx->key_sz == 0) { - memcpy(out, in, size); - return SQLITE_OK; + CODEC_TRACE(("codec_cipher: error possible context corruption, key_sz is zero for pgno=%d\n", pgno)); + memset(out, 0, page_sz); + return SQLITE_ERROR; } if(mode == CIPHER_ENCRYPT) { @@ -516,14 +536,24 @@ int sqlcipher_page_cipher(codec_ctx *ctx, int for_ctx, Pgno pgno, int mode, int return SQLITE_ERROR; } - CODEC_TRACE(("codec_cipher: comparing hmac on in=%d out=%d hmac_sz=%d\n", hmac_in, hmac_out, c_ctx->hmac_sz)); - if(sqlcipher_memcmp(hmac_in, hmac_out, c_ctx->hmac_sz) != 0) { - /* the hmac check failed, which means the data was tampered with or - corrupted in some way. we will return an error, and zero out the page data - to force an error */ - memset(out, 0, page_sz); - CODEC_TRACE(("codec_cipher: hmac check failed for pgno=%d\n", pgno)); - return SQLITE_ERROR; + CODEC_TRACE(("codec_cipher: comparing hmac on in=%p out=%p hmac_sz=%d\n", hmac_in, hmac_out, c_ctx->hmac_sz)); + if(sqlcipher_memcmp(hmac_in, hmac_out, c_ctx->hmac_sz) != 0) { /* the hmac check failed */ + if(sqlcipher_ismemset(in, 0, page_sz) == 0) { + /* first check if the entire contents of the page is zeros. If so, this page + resulted from a short read (i.e. sqlite attempted to pull a page after the end of the file. these + short read failures must be ignored for autovaccum mode to work so wipe the output buffer + and return SQLITE_OK to skip the decryption step. */ + CODEC_TRACE(("codec_cipher: zeroed page (short read) for pgno %d, encryption but returning SQLITE_OK\n", pgno)); + memset(out, 0, page_sz); + return SQLITE_OK; + } else { + /* if the page memory is not all zeros, it means the there was data and a hmac on the page. + since the check failed, the page was either tampered with or corrupted. wipe the output buffer, + and return SQLITE_ERROR to the caller */ + CODEC_TRACE(("codec_cipher: hmac check failed for pgno=%d returning SQLITE_ERROR\n", pgno)); + memset(out, 0, page_sz); + return SQLITE_ERROR; + } } } @@ -542,6 +572,8 @@ int sqlcipher_page_cipher(codec_ctx *ctx, int for_ctx, Pgno pgno, int mode, int sqlcipher_page_hmac(c_ctx, pgno, out_start, size + c_ctx->iv_sz, hmac_out); } + CODEC_HEXDUMP("codec_cipher: output page data", out_start, page_sz); + return SQLITE_OK; } @@ -558,8 +590,8 @@ int sqlcipher_page_cipher(codec_ctx *ctx, int for_ctx, Pgno pgno, int mode, int */ int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) { CODEC_TRACE(("codec_key_derive: entered c_ctx->pass=%s, c_ctx->pass_sz=%d \ - ctx->kdf_salt=%d ctx->kdf_salt_sz=%d c_ctx->kdf_iter=%d \ - ctx->hmac_kdf_salt=%d, c_ctx->fast_kdf_iter=%d c_ctx->key_sz=%d\n", + ctx->kdf_salt=%p ctx->kdf_salt_sz=%d c_ctx->kdf_iter=%d \ + ctx->hmac_kdf_salt=%p, c_ctx->fast_kdf_iter=%d c_ctx->key_sz=%d\n", 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)); -- cgit v1.2.3