8000 improved HMAC key derivation · PHPDOTSQL/sqlcipher@9c0dd8d · GitHub
[go: up one dir, main page]

Skip to content

Commit 9c0dd8d

Browse files
committed
improved HMAC key derivation
- ensure that the HMAC key derivation salt is different from that used to generate the encryption key - allow the number of pbkdf2 iterations used for HMAC key derivation to be configured at runtime via pragma
1 parent 0d1e810 commit 9c0dd8d

File tree

5 files changed

+137
-7
lines changed

5 files changed

+137
-7
lines changed

src/crypto.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ int codec_set_kdf_iter(sqlite3* db, int nDb, int kdf_iter, int for_ctx) {
5050
return SQLITE_ERROR;
5151
}
5252

53+
int codec_set_hmac_kdf_iter(sqlite3* db, int nDb, int kdf_iter, int for_ctx) {
54+
struct Db *pDb = &db->aDb[nDb];
55+
CODEC_TRACE(("codec_set_kdf_iter: entered db=%d nDb=%d kdf_iter=%d for_ctx=%d\n", db, nDb, kdf_iter, for_ctx));
56+
57+
if(pDb->pBt) {
58+
codec_ctx *ctx;
59+
sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
60+
return sqlcipher_codec_ctx_set_hmac_kdf_iter(ctx, kdf_iter, for_ctx);
61+
}
62+
return SQLITE_ERROR;
63+
}
64+
5365
static int codec_set_btree_to_codec_pagesize(sqlite3 *db, Db *pDb, codec_ctx *ctx) {
5466
int rc, page_sz, reserve_sz;
5567

src/crypto.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,25 @@
5656
#define DEFAULT_USE_HMAC 1
5757
#endif
5858

59+
/* by default, sqlcipher will use an equal number of rounds to generate
60+
the HMAC key as it will to generate the encryption key */
61+
#ifndef HMAC_PBKDF2_ITER
62+
#define HMAC_PBKDF2_ITER PBKDF2_ITER
63+
#endif
64+
65+
/* this if a fixed random array that will be xor'd with the database salt to ensure that the
66+
salt passed to the HMAC key derivation function is not the same as that used to derive
67+
the encryption key. This can be overridden at compile time but it will make the resulting
68+
binary incompatible with the default builds when using HMAC. A future version of SQLcipher
69+
will likely allow this to be defined at runtime via pragma */
70+
#ifndef HMAC_FIXED_SALT
71+
#define HMAC_FIXED_SALT {42,172,104,131,19,119,84,255,184,238,54,135,186,222,53,250}
72+
#endif
73+
74+
#ifndef HMAC_FIXED_SALT_SZ
75+
#define HMAC_FIXED_SALT_SZ 16
76+
#endif
77+
5978
#ifdef CODEC_DEBUG
6079
#define CODEC_TRACE(X) {printf X;fflush(stdout);}
6180
#else
@@ -125,6 +144,8 @@ int sqlcipher_codec_ctx_get_reservesize(codec_ctx *);
125144
int sqlcipher_codec_ctx_set_kdf_iter(codec_ctx *, int, int);
126145
void* sqlcipher_codec_ctx_get_kdf_salt(codec_ctx *ctx);
127146

147+
int sqlcipher_codec_ctx_set_hmac_kdf_iter(codec_ctx *, int, int);
148+
128149
int sqlcipher_codec_ctx_set_cipher(codec_ctx *, const char *, int);
129150

130151
void* sqlcipher_codec_ctx_get_data(codec_ctx *);

src/crypto_impl.c

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#endif
4848
#endif
4949

50+
static unsigned char cipher_hmac_fixed_salt[HMAC_FIXED_SALT_SZ] = HMAC_FIXED_SALT;
5051

5152
/* the default implementation of SQLCipher uses a cipher_ctx
5253
to keep track of read / write state separately. The following
@@ -57,6 +58,7 @@ typedef struct {
5758
EVP_CIPHER_CTX ectx;
5859
HMAC_CTX hctx;
5960
int kdf_iter;
61+
int hmac_kdf_iter;
6062
int key_sz;
6163
int iv_sz;
6264
int block_sz;
@@ -74,7 +76,7 @@ int sqlcipher_cipher_ctx_cmp(cipher_ctx *, cipher_ctx *);
7476
int sqlcipher_cipher_ctx_copy(cipher_ctx *, cipher_ctx *);
7577
int sqlcipher_cipher_ctx_init(cipher_ctx **);
7678
int sqlcipher_cipher_ctx_set_pass(cipher_ctx *, const void *, int);
77-
int sqlcipher_cipher_ctx_key_derive(codec_ctx *, cipher_ctx *);
79+
int sqlcipher_cipher_ctx_key_derive(codec_ctx *, cipher_ctx *);
7880

7981
/* prototype for pager HMAC function */
8082
int sqlcipher_page_hmac(cipher_ctx *, Pgno, unsigned char *, int, unsigned char *);
@@ -83,6 +85,7 @@ struct codec_ctx {
8385
int kdf_salt_sz;
8486
int page_sz;
8587
unsigned char *kdf_salt;
88+
unsigned char *hmac_kdf_salt;
8689
unsigned char *buffer;
8790
Btree *pBt;
8891
cipher_ctx *read_ctx;
@@ -202,6 +205,7 @@ int sqlcipher_cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) {
202205
c1->evp_cipher == c2->evp_cipher
203206
&& c1->iv_sz == c2->iv_sz
204207
&& c1->kdf_iter == c2->kdf_iter
208+
&& c1->hmac_kdf_iter == c2->hmac_kdf_iter
205209
&& c1->key_sz == c2->key_sz
206210
&& c1->pass_sz == c2->pass_sz
207211
&& (
@@ -309,6 +313,21 @@ int sqlcipher_codec_ctx_set_kdf_iter(codec_ctx *ctx, int kdf_iter, int for_ctx)
309313
return SQLITE_OK;
310314
}
311315

316+
int sqlcipher_codec_ctx_set_hmac_kdf_iter(codec_ctx *ctx, int hmac_kdf_iter, int for_ctx) {
317+
cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
318+
int rc;
319+
320+
c_ctx->hmac_kdf_iter = hmac_kdf_iter;
321+
c_ctx->derive_key = 1;
322+
323+
if(for_ctx == 2)
324+
if((rc = sqlcipher_cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx)) != SQLITE_OK)
325+
return rc;
326+
327+
return SQLITE_OK;
328+
}
329+
330+
312331
int sqlcipher_codec_ctx_set_use_hmac(codec_ctx *ctx, int use) {
313332
int reserve = EVP_MAX_IV_LENGTH; /* base reserve size will be IV only */
314333

@@ -386,6 +405,13 @@ int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, sqlite3_f
386405
ctx->kdf_salt = sqlcipher_malloc(ctx->kdf_salt_sz);
387406
if(ctx->kdf_salt == NULL) return SQLITE_NOMEM;
388407

408+
/* allocate space for separate hmac salt data. We want the
409+
HMAC derivation salt to be different than the encryption
410+
key derivation salt */
411+
ctx->hmac_kdf_salt = sqlcipher_malloc(ctx->kdf_salt_sz);
412+
if(ctx->hmac_kdf_salt == NULL) return SQLITE_NOMEM;
413+
414+
389415
/*
390416
Always overwrite page size and set to the default because the first page of the database
391417
in encrypted and thus sqlite can't effectively determine the pagesize. this causes an issue in
@@ -403,6 +429,7 @@ int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, sqlite3_f
403429

404430
if((rc = sqlcipher_codec_ctx_set_cipher(ctx, CIPHER, 0)) != SQLITE_OK) return rc;
405431
if((rc = sqlcipher_codec_ctx_set_kdf_iter(ctx, PBKDF2_ITER, 0)) != SQLITE_OK) return rc;
432+
if((rc = sqlcipher_codec_ctx_set_hmac_kdf_iter(ctx, HMAC_PBKDF2_ITER, 0)) != SQLITE_OK) return rc;
406433
if((rc = sqlcipher_codec_ctx_set_pass(ctx, zKey, nKey, 0)) != SQLITE_OK) return rc;
407434

408435
/* Use HMAC signatures by default. Note that codec_set_use_hmac will implicity call
@@ -422,6 +449,7 @@ void sqlcipher_codec_ctx_free(codec_ctx **iCtx) {
422449
codec_ctx *ctx = *iCtx;
423450
CODEC_TRACE(("codec_ctx_free: entered iCtx=%d\n", iCtx));
424451
sqlcipher_free(ctx->kdf_salt, ctx->kdf_salt_sz);
452+
sqlcipher_free(ctx->hmac_kdf_salt, ctx->kdf_salt_sz);
425453
sqlcipher_free(ctx->buffer, 0);
426454
sqlcipher_cipher_ctx_free(&ctx->read_ctx);
427455
sqlcipher_cipher_ctx_free(&ctx->write_ctx);
@@ -532,9 +560,11 @@ int sqlcipher_page_cipher(codec_ctx *ctx, int for_ctx, Pgno pgno, int mode, int
532560
*/
< 10000 code>533561
int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) {
534562
CODEC_TRACE(("codec_key_derive: entered c_ctx->pass=%s, c_ctx->pass_sz=%d \
535-
ctx->kdf_salt=%d ctx->kdf_salt_sz=%d c_ctx->kdf_iter=%d c_ctx->key_sz=%d\n",
536-
c_ctx->pass, c_ctx->pass_sz, ctx->kdf_salt, ctx->kdf_salt_sz,
537-
c_ctx->kdf_iter, c_ctx->key_sz));
563+
ctx->kdf_salt=%d ctx->kdf_salt_sz=%d c_ctx->kdf_iter=%d \
564+
ctx->hmac_kdf_salt=%d, c_ctx->hmac_kdf_iter=%d c_ctx->key_sz=%d\n",
565+
c_ctx->pass, c_ctx->pass_sz, ctx->kdf_salt, ctx->kdf_salt_sz, c_ctx->kdf_iter,
566+
ctx->hmac_kdf_salt, c_ctx->hmac_kdf_iter, c_ctx->key_sz));
567+
538568

539569
if(c_ctx->pass && c_ctx->pass_sz) { // if pass is not null
540570
if (c_ctx->pass_sz == ((c_ctx->key_sz*2)+3) && sqlite3StrNICmp(c_ctx->pass ,"x'", 2) == 0) {
@@ -554,10 +584,23 @@ int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) {
554584
key for HMAC. In this case, we use the output of the previous KDF as the input to
555585
this KDF run. This ensures a distinct but predictable HMAC key. */
556586
if(c_ctx->use_hmac) {
557-
CODEC_TRACE(("codec_key_derive: deriving hmac key using PBKDF2\n"));
587+
int i;
588+
589+
/* start by copying the kdf key into the hmac salt slot
590+
then XOR it with the fixed hmac salt defined at compile time
591+
this ensures that the salt passed in to derive the hmac key, while
592+
easy to derive and publically known, is not the same as the salt used
593+
to generate the encryption key */
594+
memcpy(ctx->hmac_kdf_salt, ctx->kdf_salt, ctx->kdf_salt_sz);
595+
for(i = 0; i < HMAC_FIXED_SALT_SZ && i < ctx->kdf_salt_sz; i++) {
596+
ctx->hmac_kdf_salt[i] = ctx->hmac_kdf_salt[i] ^ cipher_hmac_fixed_salt[i];
597+
}
598+
599+
CODEC_TRACE(("codec_key_derive: deriving hmac key from encryption key using PBKDF2 with %d iterations\n",
600+
HMAC_PBKDF2_ITER));
558601
PKCS5_PBKDF2_HMAC_SHA1( (const char*)c_ctx->key, c_ctx->key_sz,
559-
ctx->kdf_salt, ctx->kdf_salt_sz,
560-
c_ctx->kdf_iter, c_ctx->key_sz, c_ctx->hmac_key);
602+
ctx->hmac_kdf_salt, ctx->kdf_salt_sz,
603+
c_ctx->hmac_kdf_iter, c_ctx->key_sz, c_ctx->hmac_key);
561604
}
562605

563606
c_ctx->derive_key = 0;

src/pragma.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,6 +1503,10 @@ void sqlite3Pragma(
15031503
extern int codec_set_kdf_iter(sqlite3*, int, int, int);
15041504
codec_set_kdf_iter(db, iDb, atoi(zRight), 2); // change of RW PBKDF2 iteration
15051505
}else
1506+
if( sqlite3StrICmp(zLeft, "hmac_kdf_iter")==0 && zRight ){
1507+
extern int codec_set_hmac_kdf_iter(sqlite3*, int, int, int);
1508+
codec_set_hmac_kdf_iter(db, iDb, atoi(zRight), 2); // change of RW PBKDF2 iteration
1509+
}else
15061510
if( sqlite3StrICmp(zLeft, "rekey_kdf_iter")==0 && zRight ){
15071511
extern int codec_set_kdf_iter(sqlite3*, int, int, int);
15081512
codec_set_kdf_iter(db, iDb, atoi(zRight), 1); // change # if W iterations

test/crypto.test

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -925,4 +925,54 @@ do_test multiple-key-calls-safe-3 {
925925
db close
926926
file delete -force test.db
927927

928+
# 1. create a database with a custom hmac kdf iteration count,
929+
# 2. create table and insert operations should work
930+
# 3. close database, open it again with the same
931+
# key and hmac kdf iteration count
932+
# 4. verify that the table is readable
933+
# and the data just inserted is visible
934+
do_test custom-hmac-kdf-iter {
935+
sqlite_orig db test.db
936+
937+
execsql {
938+
PRAGMA key = 'testkey';
939+
PRAGMA hmac_kdf_iter = 10;
940+
CREATE table t1(a,b);
941+
BEGIN;
942+
}
943+
944+
for {set i 1} {$i<=1000} {incr i} {
945+
set r [expr {int(rand()*500000)}]
946+
execsql "INSERT INTO t1 VALUES($i,'value $r');"
947+
}
948+
949+
execsql {
950+
COMMIT;
951+
}
952+
953+
db close
954+
sqlite_orig db test.db
955+
956+
execsql {
957+
PRAGMA key = 'testkey';
958+
PRAGMA hmac_kdf_iter = 10;
959+
SELECT count(*) FROM t1;
960+
}
961+
962+
} {1000}
963+
db close
964+
965+
# open the database with the default hmac
966+
# kdf iteration count
967+
# to verify that it is not readable
968+
do_test custom-hmac-kdf-iter-must-match {
969+
sqlite_orig db test.db
970+
catchsql {
971+
PRAGMA key = 'testkey';
972+
SELECT name FROM sqlite_master WHERE type='table';
973+
}
974+
} {1 {file is encrypted or is not a database}}
975+
db close
976+
file delete -force test.db
977+
928978
finish_test

0 commit comments

Comments
 (0)
0