summaryrefslogtreecommitdiff
path: root/src/crypto_impl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto_impl.c')
-rw-r--r--src/crypto_impl.c72
1 files changed, 52 insertions, 20 deletions
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));