add support for HMAC-SHA256 and HMAC-SHA512 (default) for HMAC and PBKDF2

This commit is contained in:
Stephen Lombardo 2018-09-05 17:39:07 -04:00
parent a0320d99b3
commit 02cee4ca2a
8 changed files with 448 additions and 56 deletions

View File

@ -35,6 +35,7 @@
#include "sqliteInt.h"
#include "btreeInt.h"
#include "crypto.h"
#include "sqlcipher.h"
static const char* codec_get_cipher_version() {
return CIPHER_VERSION;
@ -328,6 +329,100 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef
sqlite3_free(salt);
}
}
}else
if( sqlite3StrICmp(zLeft,"cipher_hmac_algorithm")==0 ){
if(ctx) {
if(zRight) {
int rc = SQLITE_ERROR;
if(sqlite3StrICmp(zRight, SQLCIPHER_HMAC_SHA1_LABEL) == 0) {
rc = sqlcipher_codec_ctx_set_hmac_algorithm(ctx, SQLCIPHER_HMAC_SHA1);
} else if(sqlite3StrICmp(zRight, SQLCIPHER_HMAC_SHA256_LABEL) == 0) {
rc = sqlcipher_codec_ctx_set_hmac_algorithm(ctx, SQLCIPHER_HMAC_SHA256);
} else if(sqlite3StrICmp(zRight, SQLCIPHER_HMAC_SHA512_LABEL) == 0) {
rc = sqlcipher_codec_ctx_set_hmac_algorithm(ctx, SQLCIPHER_HMAC_SHA512);
}
if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
rc = codec_set_btree_to_codec_pagesize(db, pDb, ctx);
if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
} else {
int algorithm = sqlcipher_codec_ctx_get_hmac_algorithm(ctx);
if(algorithm == SQLCIPHER_HMAC_SHA1) {
codec_vdbe_return_static_string(pParse, "cipher_hmac_algorithm", SQLCIPHER_HMAC_SHA1_LABEL);
} else if(algorithm == SQLCIPHER_HMAC_SHA256) {
codec_vdbe_return_static_string(pParse, "cipher_hmac_algorithm", SQLCIPHER_HMAC_SHA256_LABEL);
} else if(algorithm == SQLCIPHER_HMAC_SHA512) {
codec_vdbe_return_static_string(pParse, "cipher_hmac_algorithm", SQLCIPHER_HMAC_SHA512_LABEL);
}
}
}
}else
if( sqlite3StrICmp(zLeft,"cipher_default_hmac_algorithm")==0 ){
if(zRight) {
int rc = SQLITE_ERROR;
if(sqlite3StrICmp(zRight, SQLCIPHER_HMAC_SHA1_LABEL) == 0) {
rc = sqlcipher_set_default_hmac_algorithm(SQLCIPHER_HMAC_SHA1);
} else if(sqlite3StrICmp(zRight, SQLCIPHER_HMAC_SHA256_LABEL) == 0) {
rc = sqlcipher_set_default_hmac_algorithm(SQLCIPHER_HMAC_SHA256);
} else if(sqlite3StrICmp(zRight, SQLCIPHER_HMAC_SHA512_LABEL) == 0) {
rc = sqlcipher_set_default_hmac_algorithm(SQLCIPHER_HMAC_SHA512);
}
if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
} else {
int algorithm = sqlcipher_get_default_hmac_algorithm();
if(algorithm == SQLCIPHER_HMAC_SHA1) {
codec_vdbe_return_static_string(pParse, "cipher_default_hmac_algorithm", SQLCIPHER_HMAC_SHA1_LABEL);
} else if(algorithm == SQLCIPHER_HMAC_SHA256) {
codec_vdbe_return_static_string(pParse, "cipher_default_hmac_algorithm", SQLCIPHER_HMAC_SHA256_LABEL);
} else if(algorithm == SQLCIPHER_HMAC_SHA512) {
codec_vdbe_return_static_string(pParse, "cipher_default_hmac_algorithm", SQLCIPHER_HMAC_SHA512_LABEL);
}
}
}else
if( sqlite3StrICmp(zLeft,"cipher_kdf_algorithm")==0 ){
if(ctx) {
if(zRight) {
int rc = SQLITE_ERROR;
if(sqlite3StrICmp(zRight, SQLCIPHER_PBKDF2_HMAC_SHA1_LABEL) == 0) {
rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, SQLCIPHER_PBKDF2_HMAC_SHA1);
} else if(sqlite3StrICmp(zRight, SQLCIPHER_PBKDF2_HMAC_SHA256_LABEL) == 0) {
rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, SQLCIPHER_PBKDF2_HMAC_SHA256);
} else if(sqlite3StrICmp(zRight, SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL) == 0) {
rc = sqlcipher_codec_ctx_set_kdf_algorithm(ctx, SQLCIPHER_PBKDF2_HMAC_SHA512);
}
if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
} else {
int algorithm = sqlcipher_codec_ctx_get_kdf_algorithm(ctx);
if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA1) {
codec_vdbe_return_static_string(pParse, "cipher_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA1_LABEL);
} else if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA256) {
codec_vdbe_return_static_string(pParse, "cipher_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA256_LABEL);
} else if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA512) {
codec_vdbe_return_static_string(pParse, "cipher_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL);
}
}
}
}else
if( sqlite3StrICmp(zLeft,"cipher_default_kdf_algorithm")==0 ){
if(zRight) {
int rc = SQLITE_ERROR;
if(sqlite3StrICmp(zRight, SQLCIPHER_PBKDF2_HMAC_SHA1_LABEL) == 0) {
rc = sqlcipher_set_default_kdf_algorithm(SQLCIPHER_PBKDF2_HMAC_SHA1);
} else if(sqlite3StrICmp(zRight, SQLCIPHER_PBKDF2_HMAC_SHA256_LABEL) == 0) {
rc = sqlcipher_set_default_kdf_algorithm(SQLCIPHER_PBKDF2_HMAC_SHA256);
} else if(sqlite3StrICmp(zRight, SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL) == 0) {
rc = sqlcipher_set_default_kdf_algorithm(SQLCIPHER_PBKDF2_HMAC_SHA512);
}
if (rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, SQLITE_ERROR);
} else {
int algorithm = sqlcipher_get_default_kdf_algorithm();
if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA1) {
codec_vdbe_return_static_string(pParse, "cipher_default_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA1_LABEL);
} else if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA256) {
codec_vdbe_return_static_string(pParse, "cipher_default_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA256_LABEL);
} else if(algorithm == SQLCIPHER_PBKDF2_HMAC_SHA512) {
codec_vdbe_return_static_string(pParse, "cipher_default_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL);
}
}
}else {
return 0;
}

View File

@ -267,6 +267,17 @@ int sqlcipher_get_default_plaintext_header_size();
int sqlcipher_codec_ctx_set_plaintext_header_size(codec_ctx *ctx, int size);
int sqlcipher_codec_ctx_get_plaintext_header_size(codec_ctx *ctx);
int sqlcipher_set_default_hmac_algorithm(int algorithm);
int sqlcipher_get_default_hmac_algorithm();
int sqlcipher_codec_ctx_set_hmac_algorithm(codec_ctx *ctx, int algorithm);
int sqlcipher_codec_ctx_get_hmac_algorithm(codec_ctx *ctx);
int sqlcipher_set_default_kdf_algorithm(int algorithm);
int sqlcipher_get_default_kdf_algorithm();
int sqlcipher_codec_ctx_set_kdf_algorithm(codec_ctx *ctx, int algorithm);
int sqlcipher_codec_ctx_get_kdf_algorithm(codec_ctx *ctx);
#endif
#endif
/* END SQLCIPHER */

View File

@ -64,18 +64,42 @@ static const char* sqlcipher_cc_get_provider_version(void *ctx) {
#endif
}
static int sqlcipher_cc_hmac(void *ctx, unsigned char *hmac_key, int key_sz, unsigned char *in, int in_sz, unsigned char *in2, int in2_sz, unsigned char *out) {
static int sqlcipher_cc_hmac(void *ctx, int algorithm, unsigned char *hmac_key, int key_sz, unsigned char *in, int in_sz, unsigned char *in2, int in2_sz, unsigned char *out) {
CCHmacContext hmac_context;
if(in == NULL) return SQLITE_ERROR;
CCHmacInit(&hmac_context, kCCHmacAlgSHA1, hmac_key, key_sz);
switch(algorithm) {
case SQLCIPHER_HMAC_SHA1:
CCHmacInit(&hmac_context, kCCHmacAlgSHA1, hmac_key, key_sz);
break;
case SQLCIPHER_HMAC_SHA256:
CCHmacInit(&hmac_context, kCCHmacAlgSHA256, hmac_key, key_sz);
break;
case SQLCIPHER_HMAC_SHA512:
CCHmacInit(&hmac_context, kCCHmacAlgSHA512, hmac_key, key_sz);
break;
default:
return SQLITE_ERROR;
}
CCHmacUpdate(&hmac_context, in, in_sz);
if(in2 != NULL) CCHmacUpdate(&hmac_context, in2, in2_sz);
CCHmacFinal(&hmac_context, out);
return SQLITE_OK;
}
static int sqlcipher_cc_kdf(void *ctx, const unsigned char *pass, int pass_sz, unsigned char* salt, int salt_sz, int workfactor, int key_sz, unsigned char *key) {
CCKeyDerivationPBKDF(kCCPBKDF2, (const char *)pass, pass_sz, salt, salt_sz, kCCPRFHmacAlgSHA1, workfactor, key, key_sz);
static int sqlcipher_cc_kdf(void *ctx, int algorithm, const unsigned char *pass, int pass_sz, unsigned char* salt, int salt_sz, int workfactor, int key_sz, unsigned char *key) {
switch(algorithm) {
case SQLCIPHER_HMAC_SHA1:
CCKeyDerivationPBKDF(kCCPBKDF2, (const char *)pass, pass_sz, salt, salt_sz, kCCPRFHmacAlgSHA1, workfactor, key, key_sz);
break;
case SQLCIPHER_HMAC_SHA256:
CCKeyDerivationPBKDF(kCCPBKDF2, (const char *)pass, pass_sz, salt, salt_sz, kCCPRFHmacAlgSHA256, workfactor, key, key_sz);
break;
case SQLCIPHER_HMAC_SHA512:
CCKeyDerivationPBKDF(kCCPBKDF2, (const char *)pass, pass_sz, salt, salt_sz, kCCPRFHmacAlgSHA512, workfactor, key, key_sz);
break;
default:
return SQLITE_ERROR;
}
return SQLITE_OK;
}
@ -116,8 +140,20 @@ static int sqlcipher_cc_get_block_sz(void *ctx) {
return kCCBlockSizeAES128;
}
static int sqlcipher_cc_get_hmac_sz(void *ctx) {
return CC_SHA1_DIGEST_LENGTH;
static int sqlcipher_cc_get_hmac_sz(void *ctx, int algorithm) {
switch(algorithm) {
case SQLCIPHER_HMAC_SHA1:
return CC_SHA1_DIGEST_LENGTH;
break;
case SQLCIPHER_HMAC_SHA256:
return CC_SHA256_DIGEST_LENGTH;
break;
case SQLCIPHER_HMAC_SHA512:
return CC_SHA512_DIGEST_LENGTH;
break;
default:
return 0;
}
}
static int sqlcipher_cc_ctx_copy(void *target_ctx, void *source_ctx) {

View File

@ -68,6 +68,7 @@ typedef struct {
char *keyspec;
sqlcipher_provider *provider;
void *provider_ctx;
codec_ctx *codec;
} cipher_ctx;
static unsigned int default_flags = DEFAULT_CIPHER_FLAGS;
@ -75,6 +76,8 @@ static unsigned char hmac_salt_mask = HMAC_SALT_MASK;
static int default_kdf_iter = PBKDF2_ITER;
static int default_page_size = 4096;
static int default_plaintext_header_sz = 0;
static int default_hmac_algorithm = SQLCIPHER_HMAC_SHA512;
static int default_kdf_algorithm = SQLCIPHER_PBKDF2_HMAC_SHA512;
static unsigned int sqlcipher_activate_count = 0;
static sqlite3_mutex* sqlcipher_provider_mutex = NULL;
static sqlcipher_provider *default_provider = NULL;
@ -83,6 +86,8 @@ struct codec_ctx {
int kdf_salt_sz;
int page_sz;
int plaintext_header_sz;
int hmac_algorithm;
int kdf_algorithm;
unsigned char *kdf_salt;
unsigned char *hmac_kdf_salt;
unsigned char *buffer;
@ -571,6 +576,29 @@ void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey) {
*nKey = ctx->read_ctx->pass_sz;
}
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);
if(sqlcipher_codec_ctx_get_use_hmac(ctx, 0))
reserve += ctx->read_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;
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);
ctx->write_ctx->reserve_sz = ctx->read_ctx->reserve_sz = reserve;
return SQLITE_OK;
}
/**
* Set the passphrase for the cipher_ctx
*
@ -619,9 +647,10 @@ int sqlcipher_codec_ctx_set_cipher(codec_ctx *ctx, const char *cipher_name, int
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->hmac_sz = c_ctx->provider->get_hmac_sz(c_ctx->provider_ctx);
c_ctx->derive_key = 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;
@ -701,28 +730,13 @@ unsigned char sqlcipher_get_hmac_salt_mask() {
/* 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 = CIPHER_MAX_IV_SZ; /* base reserve size will be IV only */
if(use) reserve += ctx->read_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;
CODEC_TRACE("sqlcipher_codec_ctx_set_use_hmac: use=%d block_sz=%d md_size=%d reserve=%d\n",
use, ctx->read_ctx->block_sz, ctx->read_ctx->hmac_sz, reserve);
if(use) {
sqlcipher_codec_ctx_set_flag(ctx, CIPHER_FLAG_HMAC);
} else {
sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_HMAC);
}
ctx->write_ctx->reserve_sz = ctx->read_ctx->reserve_sz = reserve;
return SQLITE_OK;
return sqlcipher_codec_ctx_reserve_setup(ctx);
}
int sqlcipher_codec_ctx_get_use_hmac(codec_ctx *ctx, int for_ctx) {
@ -756,6 +770,44 @@ int sqlcipher_codec_ctx_get_plaintext_header_size(codec_ctx *ctx) {
return ctx->plaintext_header_sz;
}
/* manipulate HMAC algorithm */
int sqlcipher_set_default_hmac_algorithm(int algorithm) {
default_hmac_algorithm = algorithm;
return SQLITE_OK;
}
int sqlcipher_codec_ctx_set_hmac_algorithm(codec_ctx *ctx, int algorithm) {
ctx->hmac_algorithm = algorithm;
return sqlcipher_codec_ctx_reserve_setup(ctx);
}
int sqlcipher_get_default_hmac_algorithm() {
return default_hmac_algorithm;
}
int sqlcipher_codec_ctx_get_hmac_algorithm(codec_ctx *ctx) {
return ctx->hmac_algorithm;
}
/* manipulate KDF algorithm */
int sqlcipher_set_default_kdf_algorithm(int algorithm) {
default_kdf_algorithm = algorithm;
return SQLITE_OK;
}
int sqlcipher_codec_ctx_set_kdf_algorithm(codec_ctx *ctx, int algorithm) {
ctx->kdf_algorithm = algorithm;
return SQLITE_OK;
}
int sqlcipher_get_default_kdf_algorithm() {
return default_kdf_algorithm;
}
int sqlcipher_codec_ctx_get_kdf_algorithm(codec_ctx *ctx) {
return ctx->kdf_algorithm;
}
int sqlcipher_codec_ctx_set_flag(codec_ctx *ctx, unsigned int flag) {
ctx->write_ctx->flags |= flag;
ctx->read_ctx->flags |= flag;
@ -875,9 +927,11 @@ int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, sqlite3_f
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) {
@ -896,6 +950,12 @@ int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, sqlite3_f
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: 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");
@ -955,7 +1015,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->hmac_key,
ctx->provider_ctx, ctx->codec->hmac_algorithm, ctx->hmac_key,
ctx->key_sz, in,
in_sz, (unsigned char*) &pgno_raw,
sizeof(pgno), out);
@ -1084,7 +1144,7 @@ static int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) {
cipher_hex2bin(z + (c_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, c_ctx->pass, c_ctx->pass_sz,
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);
}
@ -1112,7 +1172,7 @@ 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, c_ctx->key, c_ctx->key_sz,
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);
}
@ -1209,9 +1269,9 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) {
sqlite3 *db = ctx->pBt->db;
const char *db_filename = sqlite3_db_filename(db, "main");
char *migrated_db_filename = sqlite3_mprintf("%s-migrated", db_filename);
char *v1_pragmas = "PRAGMA cipher_use_hmac = OFF; PRAGMA kdf_iter = 4000; PRAGMA cipher_page_size = 1024;";
char *v2_pragmas = "PRAGMA kdf_iter = 4000; PRAGMA cipher_page_size = 1024;";
char *v3_pragmas = "PRAGMA kdf_iter = 64000; PRAGMA cipher_page_size = 1024;";
char *v1_pragmas = "PRAGMA cipher_use_hmac = OFF; PRAGMA kdf_iter = 4000; PRAGMA cipher_page_size = 1024; PRAGMA cipher_hmac_algorithm = HMAC_SHA1; PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;";
char *v2_pragmas = "PRAGMA kdf_iter = 4000; PRAGMA cipher_page_size = 1024; PRAGMA cipher_hmac_algorithm = HMAC_SHA1; PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;";
char *v3_pragmas = "PRAGMA kdf_iter = 64000; PRAGMA cipher_page_size = 1024; PRAGMA cipher_hmac_algorithm = HMAC_SHA1; PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;";
char *set_user_version, *key;
Btree *pDest = NULL, *pSrc = NULL;
static const unsigned char aCopy[] = {
@ -1457,7 +1517,7 @@ const char* sqlcipher_codec_get_provider_version(codec_ctx *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, (unsigned char *)hmac_key, key_sz, in, in_sz, in2, in2_sz, 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);
return SQLITE_OK;
}

View File

@ -76,9 +76,11 @@ static int sqlcipher_ltc_activate(void *ctx) {
#endif
sqlcipher_memset(random_buffer, 0, FORTUNA_MAX_SZ);
if(ltc_init == 0) {
if(register_prng(&fortuna_desc) != CRYPT_OK) return SQLITE_ERROR;
if(register_cipher(&rijndael_desc) != CRYPT_OK) return SQLITE_ERROR;
if(register_hash(&sha1_desc) != CRYPT_OK) return SQLITE_ERROR;
if(register_prng(&fortuna_desc) < 0) return SQLITE_ERROR;
if(register_cipher(&rijndael_desc) < 0) return SQLITE_ERROR;
if(register_hash(&sha512_desc) < 0) return SQLITE_ERROR;
if(register_hash(&sha256_desc) < 0) return SQLITE_ERROR;
if(register_hash(&sha1_desc) < 0) return SQLITE_ERROR;
if(fortuna_start(&prng) != CRYPT_OK) {
return SQLITE_ERROR;
}
@ -139,12 +141,27 @@ static int sqlcipher_ltc_random(void *ctx, void *buffer, int length) {
return SQLITE_OK;
}
static int sqlcipher_ltc_hmac(void *ctx, unsigned char *hmac_key, int key_sz, unsigned char *in, int in_sz, unsigned char *in2, int in2_sz, unsigned char *out) {
static int sqlcipher_ltc_hmac(void *ctx, int algorithm, unsigned char *hmac_key, int key_sz, unsigned char *in, int in_sz, unsigned char *in2, int in2_sz, unsigned char *out) {
int rc, hash_idx;
hmac_state hmac;
unsigned long outlen = key_sz;
unsigned long outlen;
switch(algorithm) {
case SQLCIPHER_HMAC_SHA1:
hash_idx = find_hash("sha1");
break;
case SQLCIPHER_HMAC_SHA256:
hash_idx = find_hash("sha256");
break;
case SQLCIPHER_HMAC_SHA512:
hash_idx = find_hash("sha512");
break;
default:
return SQLITE_ERROR;
}
if(hash_idx < 0) return SQLITE_ERROR;
outlen = hash_descriptor[hash_idx].hashsize;
hash_idx = find_hash("sha1");
if(in == NULL) return SQLITE_ERROR;
if((rc = hmac_init(&hmac, hash_idx, hmac_key, key_sz)) != CRYPT_OK) return SQLITE_ERROR;
if((rc = hmac_process(&hmac, in, in_sz)) != CRYPT_OK) return SQLITE_ERROR;
@ -153,14 +170,28 @@ static int sqlcipher_ltc_hmac(void *ctx, unsigned char *hmac_key, int key_sz, un
return SQLITE_OK;
}
static int sqlcipher_ltc_kdf(void *ctx, const unsigned char *pass, int pass_sz, unsigned char* salt, int salt_sz, int workfactor, int key_sz, unsigned char *key) {
static int sqlcipher_ltc_kdf(void *ctx, int algorithm, const unsigned char *pass, int pass_sz, unsigned char* salt, int salt_sz, int workfactor, int key_sz, unsigned char *key) {
int rc, hash_idx;
unsigned long outlen = key_sz;
unsigned long random_buffer_sz = sizeof(char) * 256;
unsigned char *random_buffer = sqlcipher_malloc(random_buffer_sz);
sqlcipher_memset(random_buffer, 0, random_buffer_sz);
hash_idx = find_hash("sha1");
switch(algorithm) {
case SQLCIPHER_HMAC_SHA1:
hash_idx = find_hash("sha1");
break;
case SQLCIPHER_HMAC_SHA256:
hash_idx = find_hash("sha256");
break;
case SQLCIPHER_HMAC_SHA512:
hash_idx = find_hash("sha512");
break;
default:
return SQLITE_ERROR;
}
if(hash_idx < 0) return SQLITE_ERROR;
if((rc = pkcs_5_alg2(pass, pass_sz, salt, salt_sz,
workfactor, hash_idx, key, &outlen)) != CRYPT_OK) {
return SQLITE_ERROR;
@ -209,8 +240,24 @@ static int sqlcipher_ltc_get_block_sz(void *ctx) {
return cipher_descriptor[cipher_idx].block_length;
}
static int sqlcipher_ltc_get_hmac_sz(void *ctx) {
int hash_idx = find_hash("sha1");
static int sqlcipher_ltc_get_hmac_sz(void *ctx, int algorithm) {
int hash_idx;
switch(algorithm) {
case SQLCIPHER_HMAC_SHA1:
hash_idx = find_hash("sha1");
break;
case SQLCIPHER_HMAC_SHA256:
hash_idx = find_hash("sha256");
break;
case SQLCIPHER_HMAC_SHA512:
hash_idx = find_hash("sha512");
break;
default:
return 0;
}
if(hash_idx < 0) return 0;
return hash_descriptor[hash_idx].hashsize;
}

View File

@ -204,11 +204,26 @@ static int sqlcipher_openssl_random (void *ctx, void *buffer, int length) {
return (rc == 1) ? SQLITE_OK : SQLITE_ERROR;
}
static int sqlcipher_openssl_hmac(void *ctx, unsigned char *hmac_key, int key_sz, unsigned char *in, int in_sz, unsigned char *in2, int in2_sz, unsigned char *out) {
static int sqlcipher_openssl_hmac(void *ctx, int algorithm, unsigned char *hmac_key, int key_sz, unsigned char *in, int in_sz, unsigned char *in2, int in2_sz, unsigned char *out) {
unsigned int outlen;
HMAC_CTX* hctx = HMAC_CTX_new();
if(hctx == NULL || in == NULL) return SQLITE_ERROR;
HMAC_Init_ex(hctx, hmac_key, key_sz, EVP_sha1(), NULL);
switch(algorithm) {
case SQLCIPHER_HMAC_SHA1:
HMAC_Init_ex(hctx, hmac_key, key_sz, EVP_sha1(), NULL);
break;
case SQLCIPHER_HMAC_SHA256:
HMAC_Init_ex(hctx, hmac_key, key_sz, EVP_sha256(), NULL);
return EVP_MD_size(EVP_sha256());;
break;
case SQLCIPHER_HMAC_SHA512:
HMAC_Init_ex(hctx, hmac_key, key_sz, EVP_sha512(), NULL);
break;
default:
return SQLITE_ERROR;
}
HMAC_Update(hctx, in, in_sz);
if(in2 != NULL) HMAC_Update(hctx, in2, in2_sz);
HMAC_Final(hctx, out, &outlen);
@ -216,8 +231,20 @@ static int sqlcipher_openssl_hmac(void *ctx, unsigned char *hmac_key, int key_sz
return SQLITE_OK;
}
static int sqlcipher_openssl_kdf(void *ctx, const unsigned char *pass, int pass_sz, unsigned char* salt, int salt_sz, int workfactor, int key_sz, unsigned char *key) {
PKCS5_PBKDF2_HMAC_SHA1((const char *)pass, pass_sz, salt, salt_sz, workfactor, key_sz, key);
static int sqlcipher_openssl_kdf(void *ctx, int algorithm, const unsigned char *pass, int pass_sz, unsigned char* salt, int salt_sz, int workfactor, int key_sz, unsigned char *key) {
switch(algorithm) {
case SQLCIPHER_HMAC_SHA1:
PKCS5_PBKDF2_HMAC((const char *)pass, pass_sz, salt, salt_sz, workfactor, EVP_sha1(), key_sz, key);
break;
case SQLCIPHER_HMAC_SHA256:
PKCS5_PBKDF2_HMAC((const char *)pass, pass_sz, salt, salt_sz, workfactor, EVP_sha256(), key_sz, key);
break;
case SQLCIPHER_HMAC_SHA512:
PKCS5_PBKDF2_HMAC((const char *)pass, pass_sz, salt, salt_sz, workfactor, EVP_sha512(), key_sz, key);
break;
default:
return SQLITE_ERROR;
}
return SQLITE_OK;
}
@ -263,8 +290,20 @@ static int sqlcipher_openssl_get_block_sz(void *ctx) {
return EVP_CIPHER_block_size(((openssl_ctx *)ctx)->evp_cipher);
}
static int sqlcipher_openssl_get_hmac_sz(void *ctx) {
return EVP_MD_size(EVP_sha1());
static int sqlcipher_openssl_get_hmac_sz(void *ctx, int algorithm) {
switch(algorithm) {
case SQLCIPHER_HMAC_SHA1:
return EVP_MD_size(EVP_sha1());
break;
case SQLCIPHER_HMAC_SHA256:
return EVP_MD_size(EVP_sha256());
break;
case SQLCIPHER_HMAC_SHA512:
return EVP_MD_size(EVP_sha512());
break;
default:
return 0;
}
}
static int sqlcipher_openssl_ctx_copy(void *target_ctx, void *source_ctx) {

View File

@ -35,6 +35,21 @@
#ifndef SQLCIPHER_H
#define SQLCIPHER_H
#define SQLCIPHER_HMAC_SHA1 0
#define SQLCIPHER_HMAC_SHA1_LABEL "HMAC_SHA1"
#define SQLCIPHER_HMAC_SHA256 1
#define SQLCIPHER_HMAC_SHA256_LABEL "HMAC_SHA256"
#define SQLCIPHER_HMAC_SHA512 2
#define SQLCIPHER_HMAC_SHA512_LABEL "HMAC_SHA512"
#define SQLCIPHER_PBKDF2_HMAC_SHA1 0
#define SQLCIPHER_PBKDF2_HMAC_SHA1_LABEL "PBKDF2_HMAC_SHA1"
#define SQLCIPHER_PBKDF2_HMAC_SHA256 1
#define SQLCIPHER_PBKDF2_HMAC_SHA256_LABEL "PBKDF2_HMAC_SHA256"
#define SQLCIPHER_PBKDF2_HMAC_SHA512 2
#define SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL "PBKDF2_HMAC_SHA512"
typedef struct {
int (*activate)(void *ctx);
@ -42,15 +57,15 @@ typedef struct {
const char* (*get_provider_name)(void *ctx);
int (*add_random)(void *ctx, void *buffer, int length);
int (*random)(void *ctx, void *buffer, int length);
int (*hmac)(void *ctx, unsigned char *hmac_key, int key_sz, unsigned char *in, int in_sz, unsigned char *in2, int in2_sz, unsigned char *out);
int (*kdf)(void *ctx, const unsigned char *pass, int pass_sz, unsigned char* salt, int salt_sz, int workfactor, int key_sz, unsigned char *key);
int (*hmac)(void *ctx, int algorithm, unsigned char *hmac_key, int key_sz, unsigned char *in, int in_sz, unsigned char *in2, int in2_sz, unsigned char *out);
int (*kdf)(void *ctx, int algorithm, const unsigned char *pass, int pass_sz, unsigned char* salt, int salt_sz, int workfactor, int key_sz, unsigned char *key);
int (*cipher)(void *ctx, int mode, unsigned char *key, int key_sz, unsigned char *iv, unsigned char *in, int in_sz, unsigned char *out);
int (*set_cipher)(void *ctx, const char *cipher_name);
const char* (*get_cipher)(void *ctx);
int (*get_key_sz)(void *ctx);
int (*get_iv_sz)(void *ctx);
int (*get_block_sz)(void *ctx);
int (*get_hmac_sz)(void *ctx);
int (*get_hmac_sz)(void *ctx, int algorithm);
int (*ctx_copy)(void *target_ctx, void *source_ctx);
int (*ctx_cmp)(void *c1, void *c2);
int (*ctx_init)(void **ctx);

View File

@ -1003,6 +1003,7 @@ do_test open-1.1.8-database {
PRAGMA cipher_use_hmac = off;
PRAGMA kdf_iter = 4000;
PRAGMA cipher_page_size = 1024;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;
SELECT count(*) FROM t1;
SELECT distinct * FROM t1;
}
@ -1019,6 +1020,7 @@ do_test attach-and-copy-1.1.8 {
PRAGMA cipher_use_hmac = OFF;
PRAGMA kdf_iter = 4000;
PRAGMA cipher_page_size = 1024;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;
ATTACH DATABASE 'test.db' AS db2 KEY 'testkey-hmac';
CREATE TABLE db2.t1(a,b);
INSERT INTO db2.t1 SELECT * FROM main.t1;
@ -1488,6 +1490,7 @@ do_test default-hmac-kdf-attach {
PRAGMA cipher_default_use_hmac = OFF;
PRAGMA cipher_default_kdf_iter = 4000;
PRAGMA cipher_default_page_size = 1024;
PRAGMA cipher_default_kdf_algorithm = PBKDF2_HMAC_SHA1;
PRAGMA key = 'testkey';
SELECT count(*) FROM t1;
ATTACH 'sqlcipher-1.1.8-testkey.db' AS db2 KEY 'testkey';
@ -1495,6 +1498,7 @@ do_test default-hmac-kdf-attach {
PRAGMA cipher_default_use_hmac = ON;
PRAGMA cipher_default_kdf_iter = 128000;
PRAGMA cipher_default_page_size = 4096;
PRAGMA cipher_default_kdf_algorithm = PBKDF2_HMAC_SHA512;
}
} {75709 75709}
db close
@ -1539,11 +1543,13 @@ do_test change-default-hmac-kdf-attach {
PRAGMA cipher_default_use_hmac = OFF;
PRAGMA cipher_default_kdf_iter = 4000;
PRAGMA cipher_default_page_size = 1024;
PRAGMA cipher_default_kdf_algorithm = PBKDF2_HMAC_SHA1;
ATTACH 'sqlcipher-1.1.8-testkey.db' AS db2 KEY 'testkey';
SELECT count(*) from db2.t1;
PRAGMA cipher_default_use_hmac = ON;
PRAGMA cipher_default_kdf_iter = 128000;
PRAGMA cipher_default_page_size = 4096;
PRAGMA cipher_default_kdf_algorithm = PBKDF2_HMAC_SHA512;
}
} {1 75709}
db close
@ -1728,6 +1734,8 @@ do_test open-3.0-le-database {
PRAGMA key = 'testkey';
PRAGMA cipher_page_size = 1024;
PRAGMA kdf_iter = 64000;
PRAGMA cipher_hmac_algorithm = HMAC_SHA1;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;
SELECT count(*) FROM t1;
SELECT distinct * FROM t1;
}
@ -1742,6 +1750,8 @@ do_test open-2.0-le-database {
PRAGMA key = 'testkey';
PRAGMA kdf_iter = 4000;
PRAGMA cipher_page_size = 1024;
PRAGMA cipher_hmac_algorithm = HMAC_SHA1;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;
SELECT count(*) FROM t1;
SELECT distinct * FROM t1;
}
@ -1757,6 +1767,8 @@ do_test open-2.0-be-database {
PRAGMA cipher_hmac_pgno = be;
PRAGMA kdf_iter = 4000;
PRAGMA cipher_page_size = 1024;
PRAGMA cipher_hmac_algorithm = HMAC_SHA1;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;
SELECT count(*) FROM t1;
SELECT distinct * FROM t1;
}
@ -1775,6 +1787,8 @@ do_test be-to-le-migration {
PRAGMA cipher_hmac_pgno = be;
PRAGMA kdf_iter = 4000;
PRAGMA cipher_page_size = 1024;
PRAGMA cipher_hmac_algorithm = HMAC_SHA1;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;
ATTACH DATABASE 'test.db' AS db2 KEY 'testkey';
CREATE TABLE db2.t1(a,b);
INSERT INTO db2.t1 SELECT * FROM main.t1;
@ -2044,6 +2058,8 @@ do_test open-2.0-beta-database {
PRAGMA fast_kdf_iter = 4000;
PRAGMA cipher_hmac_salt_mask = "x'00'";
PRAGMA cipher_page_size = 1024;
PRAGMA cipher_hmac_algorithm = HMAC_SHA1;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;
SELECT count(*) FROM t1;
SELECT distinct * FROM t1;
}
@ -2063,6 +2079,8 @@ do_test 2.0-beta-to-2.0-migration {
PRAGMA kdf_iter = 4000;
PRAGMA fast_kdf_iter = 4000;
PRAGMA cipher_page_size = 1024;
PRAGMA cipher_hmac_algorithm = HMAC_SHA1;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;
SELECT count(*) FROM sqlite_master;
PRAGMA cipher_hmac_salt_mask = "x'3a'";
@ -2265,6 +2283,8 @@ do_test can-migrate-with-keys-longer-than-64-characters {
PRAGMA key = "012345678901234567890123456789012345678901234567890123456789012345";
PRAGMA cipher_page_size = 1024;
PRAGMA kdf_iter = 4000;
PRAGMA cipher_hmac_algorithm = HMAC_SHA1;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;
PRAGMA user_version = 5;
}
db close
@ -2559,7 +2579,7 @@ file delete -force test.db
# when using a standard mode database and 32 byte
# plaintext header, ensure that bytes 16 - 19
# corresponding to the page size and file versions, and reserve size
# are readable and equal to 1024, 1, 1, and 48 respectively
# are readable and equal to 1024, 1, 1, and 80 respectively
do_test test-plaintext-header-journal-delete-mode-readable {
sqlite_orig db test.db
execsql {
@ -2569,7 +2589,7 @@ do_test test-plaintext-header-journal-delete-mode-readable {
INSERT INTO t1(a,b) VALUES (1,2);
}
db close
string equal [hexio_read test.db 16 5] "0400010130"
string equal [hexio_read test.db 16 5] "0400010150"
} {1}
file delete -force test.db
@ -2577,7 +2597,7 @@ file delete -force test.db
# when using a WAL mode database and 32 byte
# plaintext header, ensure that bytes 16 - 19
# corresponding to the page size and file versions, and reserve size
# are readable and equal to 1024, 2, 2 and 48 respectively
# are readable and equal to 1024, 2, 2 and 80 respectively
do_test test-plaintext-header-journal-wal-mode-readable {
sqlite_orig db test.db
execsql {
@ -2588,7 +2608,7 @@ do_test test-plaintext-header-journal-wal-mode-readable {
INSERT INTO t1(a,b) VALUES (1,2);
}
db close
string equal [hexio_read test.db 16 5] "0400020230"
string equal [hexio_read test.db 16 5] "0400020250"
} {1}
file delete -force test.db
@ -2694,7 +2714,7 @@ do_test test-plaintext-header-migrate-journal-delete {
SELECT count(*) FROM t1;
"]
} {01010101010101010101010101010101 53514C69746520666F726D61742033000400010130 1}
} {01010101010101010101010101010101 53514C69746520666F726D61742033000400010150 1}
db close
file delete -force test.db
@ -2734,7 +2754,7 @@ do_test test-plaintext-header-migrate-journal-wal {
PRAGMA journal_mode;
"]
} {01010101010101010101010101010101 {1 wal 0 1 1} 53514C69746520666F726D61742033000400020230 {1 wal}}
} {01010101010101010101010101010101 {1 wal 0 1 1} 53514C69746520666F726D61742033000400020250 {1 wal}}
db close
file delete -force test.db
@ -2776,7 +2796,76 @@ do_test test-plaintext-header-migrate-journal-wal-string-key-random-salt {
PRAGMA journal_mode;
"]
} {{1 wal 0 1 1} 53514C69746520666F726D61742033000400020230 {1 wal}}
} {{1 wal 0 1 1} 53514C69746520666F726D61742033000400020250 {1 wal}}
db close
file delete -force test.db
# verify the pragma cipher_hmac_algorithm works properly
do_test verify-pragma-cipher-hmac-algorithm-reports-default {
sqlite_orig db test.db
execsql {
PRAGMA key = 'test';
PRAGMA cipher_hmac_algorithm;
}
} {HMAC_SHA512}
db close
file delete -force test.db
do_test verify-pragma-cipher-hmac-algorithm-reports-value-changed {
sqlite_orig db test.db
execsql {
PRAGMA key = 'test';
PRAGMA cipher_hmac_algorithm = HMAC_SHA1;
PRAGMA cipher_hmac_algorithm;
}
} {HMAC_SHA1}
db close
file delete -force test.db
do_test verify-pragma-cipher-default-hmac-algorithm {
sqlite_orig db test.db
execsql {
PRAGMA cipher_default_hmac_algorithm;
PRAGMA cipher_default_hmac_algorithm = HMAC_SHA1;
PRAGMA cipher_default_hmac_algorithm;
PRAGMA cipher_default_hmac_algorithm = HMAC_SHA512;
}
} {HMAC_SHA512 HMAC_SHA1}
db close
file delete -force test.db
# verify the pragma cipher_kdf_algorithm works properly
do_test verify-pragma-cipher-kdf-algorithm-reports-default {
sqlite_orig db test.db
execsql {
PRAGMA key = 'test';
PRAGMA cipher_kdf_algorithm;
}
} {PBKDF2_HMAC_SHA512}
db close
file delete -force test.db
do_test verify-pragma-cipher-kdf-algorithm-reports-value-changed {
sqlite_orig db test.db
execsql {
PRAGMA key = 'test';
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;
PRAGMA cipher_kdf_algorithm;
}
} {PBKDF2_HMAC_SHA1}
db close
file delete -force test.db
do_test verify-pragma-cipher-default-kdf-algorithm {
sqlite_orig db test.db
execsql {
PRAGMA cipher_default_kdf_algorithm;
PRAGMA cipher_default_kdf_algorithm = PBKDF2_HMAC_SHA1;
PRAGMA cipher_default_kdf_algorithm;
PRAGMA cipher_default_kdf_algorithm = PBKDF2_HMAC_SHA512;
}
} {PBKDF2_HMAC_SHA512 PBKDF2_HMAC_SHA1}
db close
file delete -force test.db