From 02cee4ca2aae516b293e6b59f53b2c130e3d98bd Mon Sep 17 00:00:00 2001 From: Stephen Lombardo Date: Wed, 5 Sep 2018 17:39:07 -0400 Subject: [PATCH] add support for HMAC-SHA256 and HMAC-SHA512 (default) for HMAC and PBKDF2 --- src/crypto.c | 95 ++++++++++++++++++++++++++++++++++ src/crypto.h | 11 ++++ src/crypto_cc.c | 48 ++++++++++++++--- src/crypto_impl.c | 108 ++++++++++++++++++++++++++++++--------- src/crypto_libtomcrypt.c | 67 ++++++++++++++++++++---- src/crypto_openssl.c | 51 +++++++++++++++--- src/sqlcipher.h | 21 ++++++-- test/crypto.test | 103 ++++++++++++++++++++++++++++++++++--- 8 files changed, 448 insertions(+), 56 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 3f5d88e..d2bc4a7 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -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; } diff --git a/src/crypto.h b/src/crypto.h index e48b8cc..c924932 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -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 */ diff --git a/src/crypto_cc.c b/src/crypto_cc.c index d2764f8..90793e6 100644 --- a/src/crypto_cc.c +++ b/src/crypto_cc.c @@ -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) { diff --git a/src/crypto_impl.c b/src/crypto_impl.c index c1f0161..a26b47d 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -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; } diff --git a/src/crypto_libtomcrypt.c b/src/crypto_libtomcrypt.c index aa9f0b8..49bcace 100644 --- a/src/crypto_libtomcrypt.c +++ b/src/crypto_libtomcrypt.c @@ -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; } diff --git a/src/crypto_openssl.c b/src/crypto_openssl.c index 72bdf6c..e8a119e 100644 --- a/src/crypto_openssl.c +++ b/src/crypto_openssl.c @@ -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) { diff --git a/src/sqlcipher.h b/src/sqlcipher.h index 6da1944..138c8e3 100644 --- a/src/sqlcipher.h +++ b/src/sqlcipher.h @@ -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); diff --git a/test/crypto.test b/test/crypto.test index b5cd7bb..2c48227 100644 --- a/test/crypto.test +++ b/test/crypto.test @@ -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