mirror of
https://github.com/status-im/sqlcipher.git
synced 2025-02-22 16:58:14 +00:00
disable rekey_cipher & rekey_kdf_iter; major simplification of internal contexts
This commit is contained in:
parent
1cdb2fcdce
commit
915a0a4686
16
src/crypto.c
16
src/crypto.c
@ -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) {
|
||||
|
16
src/crypto.h
16
src/crypto.h
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user