disable rekey_cipher & rekey_kdf_iter; major simplification of internal contexts

This commit is contained in:
Stephen Lombardo 2018-09-06 12:11:44 -04:00
parent 1cdb2fcdce
commit 915a0a4686
4 changed files with 228 additions and 350 deletions

View File

@ -163,7 +163,9 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef
}
}else
if( sqlite3StrICmp(zLeft, "rekey_cipher")==0 && zRight ){
if(ctx) sqlcipher_codec_ctx_set_cipher(ctx, zRight, 1); // change write cipher only
const char* message = "PRAGMA rekey_cipher is no longer supported.";
codec_vdbe_return_static_string(pParse, "rekey_cipher", message);
sqlite3_log(SQLITE_WARNING, message);
}else
if( sqlite3StrICmp(zLeft,"cipher_default_kdf_iter")==0 ){
if( zRight ) {
@ -177,9 +179,9 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef
if( sqlite3StrICmp(zLeft, "kdf_iter")==0 ){
if(ctx) {
if( zRight ) {
sqlcipher_codec_ctx_set_kdf_iter(ctx, atoi(zRight), 2); // change of RW PBKDF2 iteration
sqlcipher_codec_ctx_set_kdf_iter(ctx, atoi(zRight)); // change of RW PBKDF2 iteration
} else {
char *kdf_iter = sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_kdf_iter(ctx, 2));
char *kdf_iter = sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_kdf_iter(ctx));
codec_vdbe_return_static_string(pParse, "kdf_iter", kdf_iter);
sqlite3_free(kdf_iter);
}
@ -188,16 +190,18 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef
if( sqlite3StrICmp(zLeft, "fast_kdf_iter")==0){
if(ctx) {
if( zRight ) {
sqlcipher_codec_ctx_set_fast_kdf_iter(ctx, atoi(zRight), 2); // change of RW PBKDF2 iteration
sqlcipher_codec_ctx_set_fast_kdf_iter(ctx, atoi(zRight)); // change of RW PBKDF2 iteration
} else {
char *fast_kdf_iter = sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_fast_kdf_iter(ctx, 2));
char *fast_kdf_iter = sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_fast_kdf_iter(ctx));
codec_vdbe_return_static_string(pParse, "fast_kdf_iter", fast_kdf_iter);
sqlite3_free(fast_kdf_iter);
}
}
}else
if( sqlite3StrICmp(zLeft, "rekey_kdf_iter")==0 && zRight ){
if(ctx) sqlcipher_codec_ctx_set_kdf_iter(ctx, atoi(zRight), 1); // write iterations only
const char* message = "PRAGMA rekey_kdf_iter is no longer supported.";
codec_vdbe_return_static_string(pParse, "rekey_kdf_iter", message);
sqlite3_log(SQLITE_WARNING, message);
}else
if( sqlite3StrICmp(zLeft,"cipher_page_size")==0 ){
if(ctx) {

View File

@ -235,17 +235,17 @@ int sqlcipher_get_default_pagesize();
void sqlcipher_set_default_kdf_iter(int iter);
int sqlcipher_get_default_kdf_iter();
int sqlcipher_codec_ctx_set_kdf_iter(codec_ctx *, int, int);
int sqlcipher_codec_ctx_get_kdf_iter(codec_ctx *ctx, int);
int sqlcipher_codec_ctx_set_kdf_iter(codec_ctx *, int);
int sqlcipher_codec_ctx_get_kdf_iter(codec_ctx *ctx);
int sqlcipher_codec_ctx_set_kdf_salt(codec_ctx *ctx, unsigned char *salt, int sz);
void* sqlcipher_codec_ctx_get_kdf_salt(codec_ctx *ctx);
int sqlcipher_codec_ctx_set_fast_kdf_iter(codec_ctx *, int, int);
int sqlcipher_codec_ctx_get_fast_kdf_iter(codec_ctx *, int);
int sqlcipher_codec_ctx_set_fast_kdf_iter(codec_ctx *, int);
int sqlcipher_codec_ctx_get_fast_kdf_iter(codec_ctx *);
int sqlcipher_codec_ctx_set_cipher(codec_ctx *, const char *, int);
const char* sqlcipher_codec_ctx_get_cipher(codec_ctx *ctx, int for_ctx);
int sqlcipher_codec_ctx_set_cipher(codec_ctx *, const char *);
const char* sqlcipher_codec_ctx_get_cipher(codec_ctx *ctx);
void* sqlcipher_codec_ctx_get_data(codec_ctx *);
@ -256,11 +256,11 @@ void sqlcipher_set_hmac_salt_mask(unsigned char mask);
unsigned char sqlcipher_get_hmac_salt_mask();
int sqlcipher_codec_ctx_set_use_hmac(codec_ctx *ctx, int use);
int sqlcipher_codec_ctx_get_use_hmac(codec_ctx *ctx, int for_ctx);
int sqlcipher_codec_ctx_get_use_hmac(codec_ctx *ctx);
int sqlcipher_codec_ctx_set_flag(codec_ctx *ctx, unsigned int flag);
int sqlcipher_codec_ctx_unset_flag(codec_ctx *ctx, unsigned int flag);
int sqlcipher_codec_ctx_get_flag(codec_ctx *ctx, unsigned int flag, int for_ctx);
int sqlcipher_codec_ctx_get_flag(codec_ctx *ctx, unsigned int flag);
const char* sqlcipher_codec_get_cipher_provider(codec_ctx *ctx);
int sqlcipher_codec_ctx_migrate(codec_ctx *ctx);

View File

@ -44,31 +44,6 @@
#endif
#endif
/* the default implementation of SQLCipher uses a cipher_ctx
to keep track of read / write state separately. The following
struct and associated functions are defined here */
typedef struct {
int store_pass;
int derive_key;
int kdf_iter;
int fast_kdf_iter;
int key_sz;
int iv_sz;
int block_sz;
int pass_sz;
int reserve_sz;
int hmac_sz;
int keyspec_sz;
unsigned int flags;
unsigned char *key;
unsigned char *hmac_key;
unsigned char *pass;
char *keyspec;
sqlcipher_provider *provider;
void *provider_ctx;
codec_ctx *codec;
} cipher_ctx;
static unsigned int default_flags = DEFAULT_CIPHER_FLAGS;
static unsigned char hmac_salt_mask = HMAC_SALT_MASK;
static int default_kdf_iter = PBKDF2_ITER;
@ -80,20 +55,45 @@ static unsigned int sqlcipher_activate_count = 0;
static sqlite3_mutex* sqlcipher_provider_mutex = NULL;
static sqlcipher_provider *default_provider = NULL;
/* the default implementation of SQLCipher uses a cipher_ctx
to keep track of read / write state separately. The following
struct and associated functions are defined here */
typedef struct {
int derive_key;
int pass_sz;
unsigned char *key;
unsigned char *hmac_key;
unsigned char *pass;
char *keyspec;
} cipher_ctx;
struct codec_ctx {
int store_pass;
int kdf_iter;
int fast_kdf_iter;
int kdf_salt_sz;
int key_sz;
int iv_sz;
int block_sz;
int page_sz;
int keyspec_sz;
int reserve_sz;
int hmac_sz;
int plaintext_header_sz;
int hmac_algorithm;
int kdf_algorithm;
unsigned int skip_read_hmac;
unsigned int need_kdf_salt;
unsigned int flags;
unsigned char *kdf_salt;
unsigned char *hmac_kdf_salt;
unsigned char *buffer;
Btree *pBt;
cipher_ctx *read_ctx;
cipher_ctx *write_ctx;
unsigned int skip_read_hmac;
unsigned int need_kdf_salt;
sqlcipher_provider *provider;
void *provider_ctx;
};
static sqlite3_mem_methods default_mem_methods;
@ -372,43 +372,22 @@ void* sqlcipher_malloc(int sz) {
* returns SQLITE_OK if initialization was successful
* returns SQLITE_NOMEM if an error occured allocating memory
*/
static int sqlcipher_cipher_ctx_init(cipher_ctx **iCtx) {
static int sqlcipher_cipher_ctx_init(codec_ctx *ctx, cipher_ctx **iCtx) {
int rc;
cipher_ctx *ctx;
cipher_ctx *c_ctx;
CODEC_TRACE("sqlcipher_cipher_ctx_init: allocating context\n");
*iCtx = (cipher_ctx *) sqlcipher_malloc(sizeof(cipher_ctx));
ctx = *iCtx;
if(ctx == NULL) return SQLITE_NOMEM;
CODEC_TRACE("sqlcipher_cipher_ctx_init: allocating provider\n");
ctx->provider = (sqlcipher_provider *) sqlcipher_malloc(sizeof(sqlcipher_provider));
if(ctx->provider == NULL) return SQLITE_NOMEM;
/* make a copy of the provider to be used for the duration of the context */
CODEC_TRACE_MUTEX("sqlcipher_cipher_ctx_init: entering sqlcipher provider mutex %p\n", sqlcipher_provider_mutex);
sqlite3_mutex_enter(sqlcipher_provider_mutex);
CODEC_TRACE_MUTEX("sqlcipher_cipher_ctx_init: entered sqlcipher provider mutex %p\n", sqlcipher_provider_mutex);
memcpy(ctx->provider, default_provider, sizeof(sqlcipher_provider));
CODEC_TRACE_MUTEX("sqlcipher_cipher_ctx_init: leaving sqlcipher provider mutex %p\n", sqlcipher_provider_mutex);
sqlite3_mutex_leave(sqlcipher_provider_mutex);
CODEC_TRACE_MUTEX("sqlcipher_cipher_ctx_init: left sqlcipher provider mutex %p\n", sqlcipher_provider_mutex);
CODEC_TRACE("sqlcipher_cipher_ctx_init: calling provider ctx_init\n");
if((rc = ctx->provider->ctx_init(&ctx->provider_ctx)) != SQLITE_OK) return rc;
c_ctx = *iCtx;
if(c_ctx == NULL) return SQLITE_NOMEM;
CODEC_TRACE("sqlcipher_cipher_ctx_init: allocating key\n");
ctx->key = (unsigned char *) sqlcipher_malloc(CIPHER_MAX_KEY_SZ);
c_ctx->key = (unsigned char *) sqlcipher_malloc(ctx->key_sz);
CODEC_TRACE("sqlcipher_cipher_ctx_init: allocating hmac_key\n");
ctx->hmac_key = (unsigned char *) sqlcipher_malloc(CIPHER_MAX_KEY_SZ);
c_ctx->hmac_key = (unsigned char *) sqlcipher_malloc(ctx->key_sz);
if(ctx->key == NULL) return SQLITE_NOMEM;
if(ctx->hmac_key == NULL) return SQLITE_NOMEM;
/* setup default flags */
ctx->flags = default_flags;
if(c_ctx->key == NULL) return SQLITE_NOMEM;
if(c_ctx->hmac_key == NULL) return SQLITE_NOMEM;
return SQLITE_OK;
}
@ -416,35 +395,33 @@ static int sqlcipher_cipher_ctx_init(cipher_ctx **iCtx) {
/**
* Free and wipe memory associated with a cipher_ctx
*/
static void sqlcipher_cipher_ctx_free(cipher_ctx **iCtx) {
cipher_ctx *ctx = *iCtx;
static void sqlcipher_cipher_ctx_free(codec_ctx* ctx, cipher_ctx **iCtx) {
cipher_ctx *c_ctx = *iCtx;
CODEC_TRACE("cipher_ctx_free: entered iCtx=%p\n", iCtx);
ctx->provider->ctx_free(&ctx->provider_ctx);
sqlcipher_free(ctx->provider, sizeof(sqlcipher_provider));
sqlcipher_free(ctx->key, ctx->key_sz);
sqlcipher_free(ctx->hmac_key, ctx->key_sz);
sqlcipher_free(ctx->pass, ctx->pass_sz);
sqlcipher_free(ctx->keyspec, ctx->keyspec_sz);
sqlcipher_free(ctx, sizeof(cipher_ctx));
sqlcipher_free(c_ctx->key, ctx->key_sz);
sqlcipher_free(c_ctx->hmac_key, ctx->key_sz);
sqlcipher_free(c_ctx->pass, c_ctx->pass_sz);
sqlcipher_free(c_ctx->keyspec, ctx->keyspec_sz);
sqlcipher_free(c_ctx, sizeof(cipher_ctx));
}
static int sqlcipher_codec_ctx_reserve_setup(codec_ctx *ctx) {
int base_reserve = CIPHER_MAX_IV_SZ; /* base reserve size will be IV only */
int reserve = base_reserve;
ctx->write_ctx->hmac_sz = ctx->read_ctx->hmac_sz = ctx->read_ctx->provider->get_hmac_sz(ctx->read_ctx->provider_ctx, ctx->hmac_algorithm);
ctx->hmac_sz = ctx->provider->get_hmac_sz(ctx->provider_ctx, ctx->hmac_algorithm);
if(sqlcipher_codec_ctx_get_use_hmac(ctx, 0))
reserve += ctx->read_ctx->hmac_sz; /* if reserve will include hmac, update that size */
if(sqlcipher_codec_ctx_get_use_hmac(ctx))
reserve += ctx->hmac_sz; /* if reserve will include hmac, update that size */
/* calculate the amount of reserve needed in even increments of the cipher block size */
reserve = ((reserve % ctx->read_ctx->block_sz) == 0) ? reserve :
((reserve / ctx->read_ctx->block_sz) + 1) * ctx->read_ctx->block_sz;
reserve = ((reserve % ctx->block_sz) == 0) ? reserve :
((reserve / ctx->block_sz) + 1) * ctx->block_sz;
CODEC_TRACE("sqlcipher_codec_ctx_reserve_setup: base_reserve=%d block_sz=%d md_size=%d reserve=%d\n",
base_reserve, ctx->read_ctx->block_sz, ctx->read_ctx->hmac_sz, reserve);
base_reserve, ctx->block_sz, ctx->hmac_sz, reserve);
ctx->write_ctx->reserve_sz = ctx->read_ctx->reserve_sz = reserve;
ctx->reserve_sz = reserve;
return SQLITE_OK;
}
@ -457,14 +434,7 @@ static int sqlcipher_codec_ctx_reserve_setup(codec_ctx *ctx) {
*/
static int sqlcipher_cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) {
int are_equal = (
c1->iv_sz == c2->iv_sz
&& c1->kdf_iter == c2->kdf_iter
&& c1->fast_kdf_iter == c2->fast_kdf_iter
&& c1->key_sz == c2->key_sz
&& c1->pass_sz == c2->pass_sz
&& c1->flags == c2->flags
&& c1->hmac_sz == c2->hmac_sz
&& c1->provider->ctx_cmp(c1->provider_ctx, c2->provider_ctx)
c1->pass_sz == c2->pass_sz
&& (
c1->pass == c2->pass
|| !sqlcipher_memcmp((const unsigned char*)c1->pass,
@ -474,32 +444,16 @@ static int sqlcipher_cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) {
CODEC_TRACE("sqlcipher_cipher_ctx_cmp: entered \
c1=%p c2=%p \
c1->iv_sz=%d c2->iv_sz=%d \
c1->kdf_iter=%d c2->kdf_iter=%d \
c1->fast_kdf_iter=%d c2->fast_kdf_iter=%d \
c1->key_sz=%d c2->key_sz=%d \
c1->pass_sz=%d c2->pass_sz=%d \
c1->flags=%d c2->flags=%d \
c1->hmac_sz=%d c2->hmac_sz=%d \
c1->provider_ctx=%p c2->provider_ctx=%p \
c1->pass=%p c2->pass=%p \
c1->pass=%s c2->pass=%s \
provider->ctx_cmp=%d \
sqlcipher_memcmp=%d \
are_equal=%d \
\n",
c1, c2,
c1->iv_sz, c2->iv_sz,
c1->kdf_iter, c2->kdf_iter,
c1->fast_kdf_iter, c2->fast_kdf_iter,
c1->key_sz, c2->key_sz,
c1->pass_sz, c2->pass_sz,
c1->flags, c2->flags,
c1->hmac_sz, c2->hmac_sz,
c1->provider_ctx, c2->provider_ctx,
c1->pass, c2->pass,
c1->pass, c2->pass,
c1->provider->ctx_cmp(c1->provider_ctx, c2->provider_ctx),
(c1->pass == NULL || c2->pass == NULL)
? -1 : sqlcipher_memcmp(
(const unsigned char*)c1->pass,
@ -519,38 +473,30 @@ static int sqlcipher_cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) {
* returns SQLITE_OK if initialization was successful
* returns SQLITE_NOMEM if an error occured allocating memory
*/
static int sqlcipher_cipher_ctx_copy(cipher_ctx *target, cipher_ctx *source) {
static int sqlcipher_cipher_ctx_copy(codec_ctx *ctx, cipher_ctx *target, cipher_ctx *source) {
void *key = target->key;
void *hmac_key = target->hmac_key;
void *provider = target->provider;
void *provider_ctx = target->provider_ctx;
CODEC_TRACE("sqlcipher_cipher_ctx_copy: entered target=%p, source=%p\n", target, source);
sqlcipher_free(target->pass, target->pass_sz);
sqlcipher_free(target->keyspec, target->keyspec_sz);
sqlcipher_free(target->keyspec, ctx->keyspec_sz);
memcpy(target, source, sizeof(cipher_ctx));
target->key = key; //restore pointer to previously allocated key data
memcpy(target->key, source->key, CIPHER_MAX_KEY_SZ);
memcpy(target->key, source->key, ctx->key_sz);
target->hmac_key = hmac_key; //restore pointer to previously allocated hmac key data
memcpy(target->hmac_key, source->hmac_key, CIPHER_MAX_KEY_SZ);
target->provider = provider; // restore pointer to previouly allocated provider;
memcpy(target->provider, source->provider, sizeof(sqlcipher_provider));
target->provider_ctx = provider_ctx; // restore pointer to previouly allocated provider context;
target->provider->ctx_copy(target->provider_ctx, source->provider_ctx);
memcpy(target->hmac_key, source->hmac_key, ctx->key_sz);
if(source->pass && source->pass_sz) {
target->pass = sqlcipher_malloc(source->pass_sz);
if(target->pass == NULL) return SQLITE_NOMEM;
memcpy(target->pass, source->pass, source->pass_sz);
}
if(source->keyspec && source->keyspec_sz) {
target->keyspec = sqlcipher_malloc(source->keyspec_sz);
if(source->keyspec) {
target->keyspec = sqlcipher_malloc(ctx->keyspec_sz);
if(target->keyspec == NULL) return SQLITE_NOMEM;
memcpy(target->keyspec, source->keyspec, source->keyspec_sz);
memcpy(target->keyspec, source->keyspec, ctx->keyspec_sz);
}
return SQLITE_OK;
}
@ -561,33 +507,28 @@ static int sqlcipher_cipher_ctx_copy(cipher_ctx *target, cipher_ctx *source) {
* returns SQLITE_OK if assignment was successfull
* returns SQLITE_NOMEM if an error occured allocating memory
*/
static int sqlcipher_cipher_ctx_set_keyspec(cipher_ctx *ctx, const unsigned char *key, int key_sz, const unsigned char *salt, int salt_sz) {
static int sqlcipher_cipher_ctx_set_keyspec(codec_ctx *ctx, cipher_ctx *c_ctx, const unsigned char *key) {
/* free, zero existing pointers and size */
sqlcipher_free(c_ctx->keyspec, ctx->keyspec_sz);
c_ctx->keyspec = NULL;
/* free, zero existing pointers and size */
sqlcipher_free(ctx->keyspec, ctx->keyspec_sz);
ctx->keyspec = NULL;
ctx->keyspec_sz = 0;
c_ctx->keyspec = sqlcipher_malloc(ctx->keyspec_sz);
if(c_ctx->keyspec == NULL) return SQLITE_NOMEM;
/* establic a hex-formated key specification, containing the raw encryption key and
the salt used to generate it */
ctx->keyspec_sz = ((key_sz + salt_sz) * 2) + 3;
ctx->keyspec = sqlcipher_malloc(ctx->keyspec_sz);
if(ctx->keyspec == NULL) return SQLITE_NOMEM;
ctx->keyspec[0] = 'x';
ctx->keyspec[1] = '\'';
cipher_bin2hex(key, key_sz, ctx->keyspec + 2);
cipher_bin2hex(salt, salt_sz, ctx->keyspec + (key_sz * 2) + 2);
ctx->keyspec[ctx->keyspec_sz - 1] = '\'';
c_ctx->keyspec[0] = 'x';
c_ctx->keyspec[1] = '\'';
cipher_bin2hex(key, ctx->key_sz, c_ctx->keyspec + 2);
cipher_bin2hex(ctx->kdf_salt, ctx->kdf_salt_sz, c_ctx->keyspec + (ctx->key_sz * 2) + 2);
c_ctx->keyspec[ctx->keyspec_sz - 1] = '\'';
return SQLITE_OK;
}
int sqlcipher_codec_get_store_pass(codec_ctx *ctx) {
return ctx->read_ctx->store_pass;
return ctx->store_pass;
}
void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value) {
ctx->read_ctx->store_pass = value;
ctx->store_pass = value;
}
void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey) {
@ -595,6 +536,11 @@ void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey) {
*nKey = ctx->read_ctx->pass_sz;
}
static int sqlcipher_set_derive_key(codec_ctx *ctx, int derive) {
if(ctx->read_ctx != NULL) ctx->read_ctx->derive_key = 1;
if(ctx->write_ctx != NULL) ctx->write_ctx->derive_key = 1;
}
/**
* Set the passphrase for the cipher_ctx
*
@ -624,38 +570,32 @@ int sqlcipher_codec_ctx_set_pass(codec_ctx *ctx, const void *zKey, int nKey, int
c_ctx->derive_key = 1;
if(for_ctx == 2)
if((rc = sqlcipher_cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx)) != SQLITE_OK)
if((rc = sqlcipher_cipher_ctx_copy(ctx, for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx)) != SQLITE_OK)
return rc;
return SQLITE_OK;
}
int sqlcipher_codec_ctx_set_cipher(codec_ctx *ctx, const char *cipher_name, int for_ctx) {
cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
int sqlcipher_codec_ctx_set_cipher(codec_ctx *ctx, const char *cipher_name) {
int rc;
rc = c_ctx->provider->set_cipher(c_ctx->provider_ctx, cipher_name);
rc = ctx->provider->set_cipher(ctx->provider_ctx, cipher_name);
if(rc != SQLITE_OK){
sqlcipher_codec_ctx_set_error(ctx, rc);
return rc;
}
c_ctx->key_sz = c_ctx->provider->get_key_sz(c_ctx->provider_ctx);
c_ctx->iv_sz = c_ctx->provider->get_iv_sz(c_ctx->provider_ctx);
c_ctx->block_sz = c_ctx->provider->get_block_sz(c_ctx->provider_ctx);
c_ctx->derive_key = 1;
ctx->key_sz = ctx->provider->get_key_sz(ctx->provider_ctx);
ctx->iv_sz = ctx->provider->get_iv_sz(ctx->provider_ctx);
ctx->block_sz = ctx->provider->get_block_sz(ctx->provider_ctx);
sqlcipher_set_derive_key(ctx, 1);
sqlcipher_codec_ctx_reserve_setup(ctx);
if(for_ctx == 2)
if((rc = sqlcipher_cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx)) != SQLITE_OK)
return rc;
return SQLITE_OK;
}
const char* sqlcipher_codec_ctx_get_cipher(codec_ctx *ctx, int for_ctx) {
cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
return c_ctx->provider->get_cipher(c_ctx->provider_ctx);
const char* sqlcipher_codec_ctx_get_cipher(codec_ctx *ctx) {
return ctx->provider->get_cipher(ctx->provider_ctx);
}
/* set the global default KDF iteration */
@ -667,42 +607,24 @@ int sqlcipher_get_default_kdf_iter() {
return default_kdf_iter;
}
int sqlcipher_codec_ctx_set_kdf_iter(codec_ctx *ctx, int kdf_iter, int for_ctx) {
cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
int rc;
c_ctx->kdf_iter = kdf_iter;
c_ctx->derive_key = 1;
if(for_ctx == 2)
if((rc = sqlcipher_cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx)) != SQLITE_OK)
return rc;
int sqlcipher_codec_ctx_set_kdf_iter(codec_ctx *ctx, int kdf_iter) {
ctx->kdf_iter = kdf_iter;
sqlcipher_set_derive_key(ctx, 1);
return SQLITE_OK;
}
int sqlcipher_codec_ctx_get_kdf_iter(codec_ctx *ctx, int for_ctx) {
cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
return c_ctx->kdf_iter;
int sqlcipher_codec_ctx_get_kdf_iter(codec_ctx *ctx) {
return ctx->kdf_iter;
}
int sqlcipher_codec_ctx_set_fast_kdf_iter(codec_ctx *ctx, int fast_kdf_iter, int for_ctx) {
cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
int rc;
c_ctx->fast_kdf_iter = fast_kdf_iter;
c_ctx->derive_key = 1;
if(for_ctx == 2)
if((rc = sqlcipher_cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx)) != SQLITE_OK)
return rc;
int sqlcipher_codec_ctx_set_fast_kdf_iter(codec_ctx *ctx, int fast_kdf_iter) {
ctx->fast_kdf_iter = fast_kdf_iter;
sqlcipher_set_derive_key(ctx, 1);
return SQLITE_OK;
}
int sqlcipher_codec_ctx_get_fast_kdf_iter(codec_ctx *ctx, int for_ctx) {
cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
return c_ctx->fast_kdf_iter;
int sqlcipher_codec_ctx_get_fast_kdf_iter(codec_ctx *ctx) {
return ctx->fast_kdf_iter;
}
/* set the global default flag for HMAC */
@ -734,9 +656,8 @@ int sqlcipher_codec_ctx_set_use_hmac(codec_ctx *ctx, int use) {
return sqlcipher_codec_ctx_reserve_setup(ctx);
}
int sqlcipher_codec_ctx_get_use_hmac(codec_ctx *ctx, int for_ctx) {
cipher_ctx * c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
return (c_ctx->flags & CIPHER_FLAG_HMAC) != 0;
int sqlcipher_codec_ctx_get_use_hmac(codec_ctx *ctx) {
return (ctx->flags & CIPHER_FLAG_HMAC) != 0;
}
/* the length of plaintext header size must be:
@ -750,7 +671,7 @@ int sqlcipher_set_default_plaintext_header_size(int size) {
}
int sqlcipher_codec_ctx_set_plaintext_header_size(codec_ctx *ctx, int size) {
if(size >= 0 && (size % ctx->read_ctx->block_sz) == 0 && size < (ctx->page_sz - ctx->read_ctx->reserve_sz)) {
if(size >= 0 && (size % ctx->block_sz) == 0 && size < (ctx->page_sz - ctx->reserve_sz)) {
ctx->plaintext_header_sz = size;
return SQLITE_OK;
}
@ -804,20 +725,17 @@ int sqlcipher_codec_ctx_get_kdf_algorithm(codec_ctx *ctx) {
}
int sqlcipher_codec_ctx_set_flag(codec_ctx *ctx, unsigned int flag) {
ctx->write_ctx->flags |= flag;
ctx->read_ctx->flags |= flag;
ctx->flags |= flag;
return SQLITE_OK;
}
int sqlcipher_codec_ctx_unset_flag(codec_ctx *ctx, unsigned int flag) {
ctx->write_ctx->flags &= ~flag;
ctx->read_ctx->flags &= ~flag;
ctx->flags &= ~flag;
return SQLITE_OK;
}
int sqlcipher_codec_ctx_get_flag(codec_ctx *ctx, unsigned int flag, int for_ctx) {
cipher_ctx * c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
return (c_ctx->flags & flag) != 0;
int sqlcipher_codec_ctx_get_flag(codec_ctx *ctx, unsigned int flag) {
return (ctx->flags & flag) != 0;
}
void sqlcipher_codec_ctx_set_error(codec_ctx *ctx, int error) {
@ -827,7 +745,7 @@ void sqlcipher_codec_ctx_set_error(codec_ctx *ctx, int error) {
}
int sqlcipher_codec_ctx_get_reservesize(codec_ctx *ctx) {
return ctx->read_ctx->reserve_sz;
return ctx->reserve_sz;
}
void* sqlcipher_codec_ctx_get_data(codec_ctx *ctx) {
@ -849,7 +767,7 @@ void* sqlcipher_codec_ctx_get_kdf_salt(codec_ctx *ctx) {
void sqlcipher_codec_get_keyspec(codec_ctx *ctx, void **zKey, int *nKey) {
*zKey = ctx->read_ctx->keyspec;
*nKey = ctx->read_ctx->keyspec_sz;
*nKey = ctx->keyspec_sz;
}
int sqlcipher_codec_ctx_set_pagesize(codec_ctx *ctx, int size) {
@ -911,6 +829,42 @@ int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, sqlite3_f
ctx->hmac_kdf_salt = sqlcipher_malloc(ctx->kdf_salt_sz);
if(ctx->hmac_kdf_salt == NULL) return SQLITE_NOMEM;
/* setup default flags */
ctx->flags = default_flags;
/* read salt from header, if present */
CODEC_TRACE("sqlcipher_codec_ctx_init: reading file header\n");
if(fd == NULL || sqlite3OsRead(fd, ctx->kdf_salt, ctx->kdf_salt_sz, 0) != SQLITE_OK) {
ctx->need_kdf_salt = 1;
}
/* setup the crypto provider */
CODEC_TRACE("sqlcipher_codec_ctx_init: allocating provider\n");
ctx->provider = (sqlcipher_provider *) sqlcipher_malloc(sizeof(sqlcipher_provider));
if(ctx->provider == NULL) return SQLITE_NOMEM;
/* make a copy of the provider to be used for the duration of the context */
CODEC_TRACE_MUTEX("sqlcipher_codec_ctx_init: entering sqlcipher provider mutex %p\n", sqlcipher_provider_mutex);
sqlite3_mutex_enter(sqlcipher_provider_mutex);
CODEC_TRACE_MUTEX("sqlcipher_codec_ctx_init: entered sqlcipher provider mutex %p\n", sqlcipher_provider_mutex);
memcpy(ctx->provider, default_provider, sizeof(sqlcipher_provider));
CODEC_TRACE_MUTEX("sqlcipher_codec_ctx_init: leaving sqlcipher provider mutex %p\n", sqlcipher_provider_mutex);
sqlite3_mutex_leave(sqlcipher_provider_mutex);
CODEC_TRACE_MUTEX("sqlcipher_codec_ctx_init: left sqlcipher provider mutex %p\n", sqlcipher_provider_mutex);
CODEC_TRACE("sqlcipher_codec_ctx_init: calling provider ctx_init\n");
if((rc = ctx->provider->ctx_init(&ctx->provider_ctx)) != SQLITE_OK) return rc;
/* setup the cipher to establish the key_sz, iv_sz, etc */
CODEC_TRACE("sqlcipher_codec_ctx_init: setting cipher\n");
if((rc = sqlcipher_codec_ctx_set_cipher(ctx, CIPHER)) != SQLITE_OK) return rc;
/* establic the size for a hex-formated key specification, containing the
raw encryption key and the salt used to generate it format. will be x'hexkey...hexsalt'
so oversize by 3 bytes */
ctx->keyspec_sz = ((ctx->key_sz + ctx->kdf_salt_sz) * 2) + 3;
/*
Always overwrite page size and set to the default because the first page of the database
@ -920,48 +874,43 @@ int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, sqlite3_f
CODEC_TRACE("sqlcipher_codec_ctx_init: calling sqlcipher_codec_ctx_set_pagesize with %d\n", default_page_size);
if((rc = sqlcipher_codec_ctx_set_pagesize(ctx, default_page_size)) != SQLITE_OK) return rc;
CODEC_TRACE("sqlcipher_codec_ctx_init: initializing read_ctx\n");
if((rc = sqlcipher_cipher_ctx_init(&ctx->read_ctx)) != SQLITE_OK) return rc;
ctx->read_ctx->codec = ctx;
CODEC_TRACE("sqlcipher_codec_ctx_init: initializing write_ctx\n");
if((rc = sqlcipher_cipher_ctx_init(&ctx->write_ctx)) != SQLITE_OK) return rc;
ctx->write_ctx->codec = ctx;
CODEC_TRACE("sqlcipher_codec_ctx_init: reading file header\n");
if(fd == NULL || sqlite3OsRead(fd, ctx->kdf_salt, FILE_HEADER_SZ, 0) != SQLITE_OK) {
ctx->need_kdf_salt = 1;
}
CODEC_TRACE("sqlcipher_codec_ctx_init: setting cipher\n");
if((rc = sqlcipher_codec_ctx_set_cipher(ctx, CIPHER, 0)) != SQLITE_OK) return rc;
/* establish settings for the KDF iterations and fast (HMAC) KDF iterations */
CODEC_TRACE("sqlcipher_codec_ctx_init: setting default_kdf_iter\n");
if((rc = sqlcipher_codec_ctx_set_kdf_iter(ctx, default_kdf_iter, 0)) != SQLITE_OK) return rc;
if((rc = sqlcipher_codec_ctx_set_kdf_iter(ctx, default_kdf_iter)) != SQLITE_OK) return rc;
CODEC_TRACE("sqlcipher_codec_ctx_init: setting fast_kdf_iter\n");
if((rc = sqlcipher_codec_ctx_set_fast_kdf_iter(ctx, FAST_PBKDF2_ITER, 0)) != SQLITE_OK) return rc;
CODEC_TRACE("sqlcipher_codec_ctx_init: setting pass key\n");
if((rc = sqlcipher_codec_ctx_set_pass(ctx, zKey, nKey, 0)) != SQLITE_OK) return rc;
if((rc = sqlcipher_codec_ctx_set_fast_kdf_iter(ctx, FAST_PBKDF2_ITER)) != SQLITE_OK) return rc;
/* set the default HMAC and KDF algorithms which will determine the reserve size */
CODEC_TRACE("sqlcipher_codec_ctx_init: calling sqlcipher_codec_ctx_set_hmac_algorithm with %d\n", default_hmac_algorithm);
if((rc = sqlcipher_codec_ctx_set_hmac_algorithm(ctx, default_hmac_algorithm)) != SQLITE_OK) return rc;
CODEC_TRACE("sqlcipher_codec_ctx_init: calling sqlcipher_codec_ctx_set_kdf_algorithm with %d\n", default_kdf_algorithm);
if((rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, default_kdf_algorithm)) != SQLITE_OK) return rc;
/* Note that use_hmac is a special case that requires recalculation of page size
so we call set_use_hmac to perform setup */
CODEC_TRACE("sqlcipher_codec_ctx_init: setting use_hmac\n");
if((rc = sqlcipher_codec_ctx_set_use_hmac(ctx, default_flags & CIPHER_FLAG_HMAC)) != SQLITE_OK) return rc;
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_kdf_algorithm with %d\n", default_kdf_algorithm);
if((rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, default_kdf_algorithm)) != SQLITE_OK) return rc;
/* setup the default plaintext header size */
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;
/* initialize the read and write sub-contexts. this must happen after key_sz is established */
CODEC_TRACE("sqlcipher_codec_ctx_init: initializing read_ctx\n");
if((rc = sqlcipher_cipher_ctx_init(ctx, &ctx->read_ctx)) != SQLITE_OK) return rc;
CODEC_TRACE("sqlcipher_codec_ctx_init: initializing write_ctx\n");
if((rc = sqlcipher_cipher_ctx_init(ctx, &ctx->write_ctx)) != SQLITE_OK) return rc;
/* set the key material on one of the sub cipher contexts and sync them up */
CODEC_TRACE("sqlcipher_codec_ctx_init: setting pass key\n");
if((rc = sqlcipher_codec_ctx_set_pass(ctx, zKey, nKey, 0)) != SQLITE_OK) return rc;
CODEC_TRACE("sqlcipher_codec_ctx_init: copying write_ctx to read_ctx\n");
if((rc = sqlcipher_cipher_ctx_copy(ctx, ctx->write_ctx, ctx->read_ctx)) != SQLITE_OK) return rc;
return SQLITE_OK;
}
@ -975,8 +924,12 @@ void sqlcipher_codec_ctx_free(codec_ctx **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);
sqlcipher_cipher_ctx_free(&ctx->read_ctx);
sqlcipher_cipher_ctx_free(&ctx->write_ctx);
ctx->provider->ctx_free(&ctx->provider_ctx);
sqlcipher_free(ctx->provider, sizeof(sqlcipher_provider));
sqlcipher_cipher_ctx_free(ctx, &ctx->read_ctx);
sqlcipher_cipher_ctx_free(ctx, &ctx->write_ctx);
sqlcipher_free(ctx, sizeof(codec_ctx));
}
@ -988,7 +941,7 @@ static void sqlcipher_put4byte_le(unsigned char *p, u32 v) {
p[3] = (u8)(v>>24);
}
static int sqlcipher_page_hmac(cipher_ctx *ctx, Pgno pgno, unsigned char *in, int in_sz, unsigned char *out) {
static int sqlcipher_page_hmac(codec_ctx *ctx, cipher_ctx *c_ctx, Pgno pgno, unsigned char *in, int in_sz, unsigned char *out) {
unsigned char pgno_raw[sizeof(pgno)];
/* we may convert page number to consistent representation before calculating MAC for
compatibility across big-endian and little-endian platforms.
@ -1010,7 +963,7 @@ static int sqlcipher_page_hmac(cipher_ctx *ctx, Pgno pgno, unsigned char *in, in
prevent both tampering with the ciphertext, manipulation of the IV, or resequencing otherwise
valid pages out of order in a database */
ctx->provider->hmac(
ctx->provider_ctx, ctx->codec->hmac_algorithm, ctx->hmac_key,
ctx->provider_ctx, ctx->hmac_algorithm, c_ctx->hmac_key,
ctx->key_sz, in,
in_sz, (unsigned char*) &pgno_raw,
sizeof(pgno), out);
@ -1031,21 +984,21 @@ int sqlcipher_page_cipher(codec_ctx *ctx, int for_ctx, Pgno pgno, int mode, int
int size;
/* calculate some required positions into various buffers */
size = page_sz - c_ctx->reserve_sz; /* adjust size to useable size and memset reserve at end of page */
size = page_sz - ctx->reserve_sz; /* adjust size to useable size and memset reserve at end of page */
iv_out = out + size;
iv_in = in + size;
/* hmac will be written immediately after the initialization vector. the remainder of the page reserve will contain
random bytes. note, these pointers are only valid when using hmac */
hmac_in = in + size + c_ctx->iv_sz;
hmac_out = out + size + c_ctx->iv_sz;
hmac_in = in + size + ctx->iv_sz;
hmac_out = out + size + ctx->iv_sz;
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);
/* the key size should never be zero. If it is, error out. */
if(c_ctx->key_sz == 0) {
if(ctx->key_sz == 0) {
CODEC_TRACE("codec_cipher: error possible context corruption, key_sz is zero for pgno=%d\n", pgno);
sqlcipher_memset(out, 0, page_sz);
return SQLITE_ERROR;
@ -1053,20 +1006,20 @@ int sqlcipher_page_cipher(codec_ctx *ctx, int for_ctx, Pgno pgno, int mode, int
if(mode == CIPHER_ENCRYPT) {
/* start at front of the reserve block, write random data to the end */
if(c_ctx->provider->random(c_ctx->provider_ctx, iv_out, c_ctx->reserve_sz) != SQLITE_OK) return SQLITE_ERROR;
if(ctx->provider->random(ctx->provider_ctx, iv_out, ctx->reserve_sz) != SQLITE_OK) return SQLITE_ERROR;
} else { /* CIPHER_DECRYPT */
memcpy(iv_out, iv_in, c_ctx->iv_sz); /* copy the iv from the input to output buffer */
memcpy(iv_out, iv_in, ctx->iv_sz); /* copy the iv from the input to output buffer */
}
if((c_ctx->flags & CIPHER_FLAG_HMAC) && (mode == CIPHER_DECRYPT) && !ctx->skip_read_hmac) {
if(sqlcipher_page_hmac(c_ctx, pgno, in, size + c_ctx->iv_sz, hmac_out) != SQLITE_OK) {
if((ctx->flags & CIPHER_FLAG_HMAC) && (mode == CIPHER_DECRYPT) && !ctx->skip_read_hmac) {
if(sqlcipher_page_hmac(ctx, c_ctx, pgno, in, size + ctx->iv_sz, hmac_out) != SQLITE_OK) {
sqlcipher_memset(out, 0, page_sz);
CODEC_TRACE("codec_cipher: hmac operations 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 */
CODEC_TRACE("codec_cipher: comparing hmac on in=%p out=%p hmac_sz=%d\n", hmac_in, hmac_out, ctx->hmac_sz);
if(sqlcipher_memcmp(hmac_in, hmac_out, 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
@ -1086,10 +1039,10 @@ int sqlcipher_page_cipher(codec_ctx *ctx, int for_ctx, Pgno pgno, int mode, int
}
}
c_ctx->provider->cipher(c_ctx->provider_ctx, mode, c_ctx->key, c_ctx->key_sz, iv_out, in, size, out);
ctx->provider->cipher(ctx->provider_ctx, mode, c_ctx->key, ctx->key_sz, iv_out, in, size, out);
if((c_ctx->flags & CIPHER_FLAG_HMAC) && (mode == CIPHER_ENCRYPT)) {
sqlcipher_page_hmac(c_ctx, pgno, out_start, size + c_ctx->iv_sz, hmac_out);
if((ctx->flags & CIPHER_FLAG_HMAC) && (mode == CIPHER_ENCRYPT)) {
sqlcipher_page_hmac(ctx, c_ctx, pgno, out_start, size + ctx->iv_sz, hmac_out);
}
CODEC_HEXDUMP("codec_cipher: output page data", out_start, page_sz);
@ -1116,41 +1069,41 @@ static int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) {
int rc;
CODEC_TRACE("cipher_ctx_key_derive: entered c_ctx->pass=%s, c_ctx->pass_sz=%d \
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",
ctx->hmac_kdf_salt=%p, c_ctx->fast_kdf_iter=%d 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);
ctx->hmac_kdf_salt, c_ctx->fast_kdf_iter, 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;
if(ctx->provider->random(ctx->provider_ctx, ctx->kdf_salt, ctx->kdf_salt_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 && cipher_isHex(c_ctx->pass + 2, c_ctx->key_sz * 2)) {
if (c_ctx->pass_sz == ((ctx->key_sz * 2) + 3) && sqlite3StrNICmp((const char *)c_ctx->pass ,"x'", 2) == 0 && cipher_isHex(c_ctx->pass + 2, ctx->key_sz * 2)) {
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' */
CODEC_TRACE("cipher_ctx_key_derive: using raw key from hex\n");
cipher_hex2bin(z, n, c_ctx->key);
} else if (c_ctx->pass_sz == (((c_ctx->key_sz + ctx->kdf_salt_sz) * 2) + 3) && sqlite3StrNICmp((const char *)c_ctx->pass ,"x'", 2) == 0 && cipher_isHex(c_ctx->pass + 2, (c_ctx->key_sz + ctx->kdf_salt_sz) * 2)) {
} else if (c_ctx->pass_sz == (((ctx->key_sz + ctx->kdf_salt_sz) * 2) + 3) && sqlite3StrNICmp((const char *)c_ctx->pass ,"x'", 2) == 0 && cipher_isHex(c_ctx->pass + 2, (ctx->key_sz + ctx->kdf_salt_sz) * 2)) {
const unsigned char *z = c_ctx->pass + 2; /* adjust lead offset of x' */
CODEC_TRACE("cipher_ctx_key_derive: using raw key from hex\n");
cipher_hex2bin(z, (c_ctx->key_sz * 2), c_ctx->key);
cipher_hex2bin(z + (c_ctx->key_sz * 2), (ctx->kdf_salt_sz * 2), ctx->kdf_salt);
cipher_hex2bin(z, (ctx->key_sz * 2), c_ctx->key);
cipher_hex2bin(z + (ctx->key_sz * 2), (ctx->kdf_salt_sz * 2), ctx->kdf_salt);
} else {
CODEC_TRACE("cipher_ctx_key_derive: deriving key using full PBKDF2 with %d iterations\n", c_ctx->kdf_iter);
c_ctx->provider->kdf(c_ctx->provider_ctx, ctx->kdf_algorithm, c_ctx->pass, c_ctx->pass_sz,
ctx->kdf_salt, ctx->kdf_salt_sz, c_ctx->kdf_iter,
c_ctx->key_sz, c_ctx->key);
ctx->provider->kdf(ctx->provider_ctx, ctx->kdf_algorithm, c_ctx->pass, c_ctx->pass_sz,
ctx->kdf_salt, ctx->kdf_salt_sz, ctx->kdf_iter,
ctx->key_sz, c_ctx->key);
}
/* set the context "keyspec" containing the hex-formatted key and salt to be used when attaching databases */
if((rc = sqlcipher_cipher_ctx_set_keyspec(c_ctx, c_ctx->key, c_ctx->key_sz, ctx->kdf_salt, ctx->kdf_salt_sz)) != SQLITE_OK) return rc;
if((rc = sqlcipher_cipher_ctx_set_keyspec(ctx, c_ctx, c_ctx->key)) != SQLITE_OK) return rc;
/* if this context is setup to use hmac checks, generate a seperate and different
key for HMAC. In this case, we use the output of the previous KDF as the input to
this KDF run. This ensures a distinct but predictable HMAC key. */
if(c_ctx->flags & CIPHER_FLAG_HMAC) {
if(ctx->flags & CIPHER_FLAG_HMAC) {
int i;
/* start by copying the kdf key into the hmac salt slot
@ -1167,9 +1120,9 @@ static int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) {
c_ctx->fast_kdf_iter);
c_ctx->provider->kdf(c_ctx->provider_ctx, ctx->kdf_algorithm, c_ctx->key, c_ctx->key_sz,
ctx->hmac_kdf_salt, ctx->kdf_salt_sz, c_ctx->fast_kdf_iter,
c_ctx->key_sz, c_ctx->hmac_key);
ctx->provider->kdf(ctx->provider_ctx, ctx->kdf_algorithm, c_ctx->key, ctx->key_sz,
ctx->hmac_kdf_salt, ctx->kdf_salt_sz, ctx->fast_kdf_iter,
ctx->key_sz, c_ctx->hmac_key);
}
c_ctx->derive_key = 0;
@ -1187,14 +1140,14 @@ int sqlcipher_codec_key_derive(codec_ctx *ctx) {
if(ctx->write_ctx->derive_key) {
if(sqlcipher_cipher_ctx_cmp(ctx->write_ctx, ctx->read_ctx) == 0) {
/* the relevant parameters are the same, just copy read key */
if(sqlcipher_cipher_ctx_copy(ctx->write_ctx, ctx->read_ctx) != SQLITE_OK) return SQLITE_ERROR;
if(sqlcipher_cipher_ctx_copy(ctx, ctx->write_ctx, ctx->read_ctx) != SQLITE_OK) return SQLITE_ERROR;
} else {
if(sqlcipher_cipher_ctx_key_derive(ctx, ctx->write_ctx) != SQLITE_OK) return SQLITE_ERROR;
}
}
/* TODO: wipe and free passphrase after key derivation */
if(ctx->read_ctx->store_pass != 1) {
if(ctx->store_pass != 1) {
sqlcipher_cipher_ctx_set_pass(ctx->read_ctx, NULL, 0);
sqlcipher_cipher_ctx_set_pass(ctx->write_ctx, NULL, 0);
}
@ -1204,14 +1157,14 @@ int sqlcipher_codec_key_derive(codec_ctx *ctx) {
int sqlcipher_codec_key_copy(codec_ctx *ctx, int source) {
if(source == CIPHER_READ_CTX) {
return sqlcipher_cipher_ctx_copy(ctx->write_ctx, ctx->read_ctx);
return sqlcipher_cipher_ctx_copy(ctx, ctx->write_ctx, ctx->read_ctx);
} else {
return sqlcipher_cipher_ctx_copy(ctx->read_ctx, ctx->write_ctx);
return sqlcipher_cipher_ctx_copy(ctx, ctx->read_ctx, ctx->write_ctx);
}
}
const char* sqlcipher_codec_get_cipher_provider(codec_ctx *ctx) {
return ctx->read_ctx->provider->get_provider_name(ctx->read_ctx);
return ctx->provider->get_provider_name(ctx->provider_ctx);
}
@ -1459,7 +1412,7 @@ int sqlcipher_codec_add_random(codec_ctx *ctx, const char *zRight, int random_sz
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, buffer_sz);
rc = ctx->provider->add_random(ctx->provider_ctx, random, buffer_sz);
sqlcipher_free(random, buffer_sz);
return rc;
}
@ -1500,17 +1453,17 @@ int sqlcipher_cipher_profile(sqlite3 *db, const char *destination){
}
int sqlcipher_codec_fips_status(codec_ctx *ctx) {
return ctx->read_ctx->provider->fips_status(ctx->read_ctx);
return ctx->provider->fips_status(ctx->provider_ctx);
}
const char* sqlcipher_codec_get_provider_version(codec_ctx *ctx) {
return ctx->read_ctx->provider->get_provider_version(ctx->read_ctx);
return ctx->provider->get_provider_version(ctx->provider_ctx);
}
int sqlcipher_codec_hmac(const codec_ctx *ctx, const unsigned char *hmac_key, int key_sz,
unsigned char* in, int in_sz, unsigned char *in2, int in2_sz,
unsigned char *out) {
ctx->read_ctx->provider->hmac(ctx->read_ctx, SQLCIPHER_HMAC_SHA1, (unsigned char *)hmac_key, key_sz, in, in_sz, in2, in2_sz, out);
ctx->provider->hmac(ctx->provider_ctx, SQLCIPHER_HMAC_SHA1, (unsigned char *)hmac_key, key_sz, in, in_sz, in2, in2_sz, out);
return SQLITE_OK;
}

View File

@ -600,93 +600,14 @@ file delete -force test.db
# test alterations of KDF iterations and ciphers
# rekey then add
setup test.db "'testkey'"
do_test non-standard-kdf-and-ciphers {
do_test verify-errors-for-rekey-kdf-and-cipher-changes {
sqlite_orig db test.db
execsql {
PRAGMA key = 'testkey';
PRAGMA rekey_kdf_iter = 1000;
PRAGMA rekey_cipher = 'aes-256-cfb';
PRAGMA rekey = 'testkey2';
INSERT INTO t1 VALUES (1,2);
PRAGMA rekey_cipher = 'aes-256-ecb';
}
db close
sqlite_orig db test.db
execsql {
PRAGMA key = 'testkey2';
PRAGMA kdf_iter = 1000;
PRAGMA cipher = 'aes-256-cfb';
SELECT count(*) FROM t1;
}
} {{PRAGMA cipher command is deprecated, please remove from usage.} 2}
db close
file delete -force test.db
# test alterations of CIPHER from CBC Mode requiring
# IV to ECB mode that does not
setup test.db "'testkey'"
do_test rekey-from-cbc-to-ecb-no-iv {
sqlite_orig db test.db
execsql {
PRAGMA key = 'testkey';
BEGIN;
}
for {set i 1} {$i<=1000} {incr i} {
set r [expr {int(rand()*500000)}]
execsql "INSERT INTO t1 VALUES($i,$r);"
}
execsql {
COMMIT;
PRAGMA rekey_kdf_iter = 1000;
PRAGMA rekey_cipher = 'aes-128-ecb';
PRAGMA rekey = 'testkey';
}
db close
sqlite_orig db test.db
execsql {
PRAGMA key = 'testkey';
PRAGMA kdf_iter = 1000;
PRAGMA cipher = 'aes-128-ecb';
SELECT count(*) FROM t1;
}
} {{PRAGMA cipher command is deprecated, please remove from usage.} 1001}
db close
file delete -force test.db
# test alterations of CIPHER from ECB Mode (no IV) to CBC Mode
do_test rekey-from-ecb-to-cbc-with-iv {
sqlite_orig db test.db
execsql {
PRAGMA key = 'testkey';
PRAGMA cipher = 'aes-256-ecb';
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,$r);"
}
execsql {
COMMIT;
PRAGMA rekey_cipher = 'aes-256-cbc';
PRAGMA rekey = 'testkey';
}
db close
sqlite_orig db test.db
execsql {
PRAGMA key = 'testkey';
SELECT count(*) FROM t1;
}
} {1000}
} {{PRAGMA rekey_kdf_iter is no longer supported.} {PRAGMA rekey_cipher is no longer supported.}}
db close
file delete -force test.db
@ -1121,7 +1042,7 @@ do_test export-database {
CREATE VIEW v1 AS
SELECT c FROM t1;
CREATE VIRTUAL TABLE fts USING fts3(a,b);
CREATE VIRTUAL TABLE fts USING fts5(a,b);
BEGIN;
-- start with one known value