8000 Add PRAGMA cipher_store_pass · githubzhaoliang/sqlcipher@90606b3 · GitHub
[go: up one dir, main page]

Skip to content

Commit 90606b3

Browse files
Add PRAGMA cipher_store_pass
PRAGMA cipher_store_pass allows the passphrase to remain in memory which will allow an ATTACH statement to succeed without providing the key value during ATTACH when both databases use the same passphrase, but have different salt values. Previously, in order to ATTACH with this scneario, calling ATTACH required providing the key value inline.
1 parent aa2e37e commit 90606b3

File tree

4 files changed

+81
-7
lines changed

4 files changed

+81
-7
lines changed

src/crypto.c

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,16 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef
8888
}
8989

9090
CODEC_TRACE(("sqlcipher_codec_pragma: entered db=%p iDb=%d pParse=%p zLeft=%s zRight=%s ctx=%p\n", db, iDb, pParse, zLeft, zRight, ctx));
91-
92-
93-
if( sqlite3StrICmp(zLeft, "cipher_profile")== 0 && zRight ){
91+
92+
if( sqlite3StrICmp(zLeft, "cipher_store_pass")==0 && zRight ) {
93+
sqlcipher_codec_set_store_pass(ctx, sqlite3GetBoolean(zRight, 1));
94+
} else
95+
if( sqlite3StrICmp(zLeft, "cipher_store_pass")==0 && !zRight ) {
96+
char *store_pass_value = sqlite3_mprintf("%d", sqlcipher_codec_get_store_pass(ctx));
97+
codec_vdbe_return_static_string(pParse, "cipher_store_pass", store_pass_value);
98+
sqlite3_free(store_pass_value);
99+< 8000 /span>
}
100+
if( sqlite3StrICmp(zLeft, "cipher_profile")== 0 && zRight ){
94101
char *profile_status = sqlite3_mprintf("%d", sqlcipher_cipher_profile(db, zRight));
95102
codec_vdbe_return_static_string(pParse, "cipher_profile", profile_status);
96103
sqlite3_free(profile_status);
@@ -471,8 +478,12 @@ void sqlite3CodecGetKey(sqlite3* db, int nDb, void **zKey, int *nKey) {
471478
if( pDb->pBt ) {
472479
codec_ctx *ctx;
473480
sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
474-
if(ctx) { /* if the codec has an attached codec_context user the raw key data */
475-
sqlcipher_codec_get_keyspec(ctx, zKey, nKey);
481+
if(ctx) {
482+
if(sqlcipher_codec_get_store_pass(ctx) == 1) {
483+
sqlcipher_codec_get_pass(ctx, zKey, nKey);
484+
} else {
485+
sqlcipher_codec_get_keyspec(ctx, zKey, nKey);
486+
}
476487
} else {
477488
*zKey = NULL;
478489
*nKey = 0;

src/crypto.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,10 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx);
216216
int sqlcipher_codec_add_random(codec_ctx *ctx, const char *data, int random_sz);
217217
int sqlcipher_cipher_profile(sqlite3 *db, const char *destination);
218218
static void sqlcipher_profile_callback(void *file, const char *sql, sqlite3_uint64 run_time);
219+
static int sqlcipher_codec_get_store_pass(codec_ctx *ctx);
220+
static void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey);
221+
static void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value);
222+
219223
#endif
220224
#endif
221225
/* END SQLCIPHER */

src/crypto_impl.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
to keep track of read / write state separately. The following
4848
struct and associated functions are defined here */
4949
typedef struct {
50+< 8000 div class="diff-text-inner"> int store_pass;
5051
int derive_key;
5152
int kdf_iter;
5253
int fast_kdf_iter;
@@ -401,6 +402,19 @@ static int sqlcipher_cipher_ctx_set_keyspec(cipher_ctx *ctx, const unsigned char
401402
return SQLITE_OK;
402403
}
403404

405+
static int sqlcipher_codec_get_store_pass(codec_ctx *ctx) {
406+
return ctx->read_ctx->store_pass;
407+
}
408+
409+
static void sqlcipher_codec_set_store_pass(codec_ctx *ctx, int value) {
410+
ctx->read_ctx->store_pass = value;
411+
}
412+
413+
static void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey) {
414+
*zKey = ctx->read_ctx->pass;
415+
*nKey = ctx->read_ctx->pass_sz;
416+
}
417+
404418
/**
405419
* Set the passphrase for the cipher_ctx
406420
*
@@ -897,8 +911,10 @@ int sqlcipher_codec_key_derive(codec_ctx *ctx) {
897911
}
898912

899913
/* TODO: wipe and free passphrase after key derivation */
900-
sqlcipher_cipher_ctx_set_pass(ctx->read_ctx, NULL, 0);
901-
sqlcipher_cipher_ctx_set_pass(ctx->write_ctx, NULL, 0);
914+
if(ctx->read_ctx->store_pass != 1) {
915+
sqlcipher_cipher_ctx_set_pass(ctx->read_ctx, NULL, 0);
916+
sqlcipher_cipher_ctx_set_pass(ctx->write_ctx, NULL, 0);
917+
}
902918

903919
return SQLITE_OK;
904920
}

test/crypto.test

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,49 @@ db2 close
444444
file delete -force test.db
445445
file delete -force test2.db
446446

447+
# attach an encrypted database
448+
# without specifying key, verify it attaches
449+
# correctly when PRAGMA cipher_store_pass = 1
450+
# is set.
451+
do_test attach-database-with-default-key-using-cipher-store-pass {
452+
453+
sqlite_orig db1 test.db
454+
execsql {
455+
PRAGMA key = 'testkey';
456+
CREATE TABLE t1(a,b);
457+
INSERT INTO t1(a,b) VALUES('foo', 'bar');
458+
} db1
459+
db1 close
460+
461+
sqlite_orig db2 test2.db
462+
execsql {
463+
PRAGMA key = 'testkey';
464+
CREATE TABLE t2(a,b);
465+
INSERT INTO t2 VALUES ('test1', 'test2');
466+
} db2
467+
db2 close
468+
469+
sqlite_orig db1 test.db
470+
execsql {
471+
PRAGMA key = 'testkey';
472+
PRAGMA cipher_store_pass = 1;
473+
ATTACH DATABASE 'test2.db' as db2;
474+
SELECT sqlcipher_export('db2');
475+
DETACH DATABASE db2;
476+
} db1
477+
db1 close
478+
479+
sqlite_orig db2 test2.db
480+
execsql {
481+
PRAGMA key = 'testkey';
482+
SELECT * FROM t1;
483+
} db2
484+
485+
} {foo bar}
486+
db2 close
487+
file delete -force test.db
488+
file delete -force test2.db
489+
447490
# attach an encrypted database
448491
# where both database have the same
449492
# key explicitly

0 commit comments

Comments
 (0)
0