support BLOB syntax for specifying binary keys
This commit is contained in:
parent
1d25ff34fe
commit
0cc240ac78
4
README
4
README
|
@ -40,7 +40,7 @@ use this method it is your responsibility to ensure that the data you provide a
|
|||
64 character hex string, which will be converted directly to 32 bytes (256 bits) of
|
||||
key data.
|
||||
|
||||
PRAGMA hexkey = '2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99';
|
||||
PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'";
|
||||
|
||||
To encrypt a database programatically you can use the sqlite3_key function. The data provided
|
||||
in pKey is converted to an encryption key according to the same rules as PRAGMA key.
|
||||
|
@ -59,7 +59,7 @@ after you've supplied the correct database password;
|
|||
|
||||
The hexrekey pragma may be used to rekey to a specific binary value
|
||||
|
||||
PRAGMA hexrekey = '2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99';
|
||||
PRAGMA rekey = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'";
|
||||
|
||||
This can be accomplished programtically by using sqlite3_rekey;
|
||||
|
||||
|
|
29
src/crypto.c
29
src/crypto.c
|
@ -55,6 +55,7 @@ typedef struct {
|
|||
Btree *pBt;
|
||||
} codec_ctx;
|
||||
|
||||
static int convertnosalt = 0;
|
||||
|
||||
/*
|
||||
* The following two functions PKCS5_PBKDF2_HMAC_SHA256 and h__dump implement a
|
||||
|
@ -129,11 +130,18 @@ static int PKCS5_PBKDF2_HMAC_SHA256(const char *pass, int passlen,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void codec_prepare_key(const void *zKey, int nKey, void *salt, int nSalt, void *out, int *nOut) {
|
||||
static void codec_prepare_key(sqlite3 *db, const void *zKey, int nKey, void *salt, int nSalt, void *out, int *nOut) {
|
||||
/* if key data lenth is exactly 256 bits / 32 bytes use the data directly */
|
||||
if (nKey == 32) {
|
||||
memcpy(out, zKey, nKey);
|
||||
*nOut = nKey;
|
||||
if (nKey == 35 && sqlite3StrNICmp(zKey ,"x'", 2) == 0) {
|
||||
int n = nKey - 3; /* adjust for leading x' and tailing ' */
|
||||
int half_n = n/2;
|
||||
const char *z = zKey + 2; /* adjust lead offset of x' */
|
||||
void *key = sqlite3HexToBlob(db, z, n);
|
||||
memcpy(out, key, half_n);
|
||||
*nOut = half_n;
|
||||
memset(key, 0, half_n); /* cleanup temporary key data */
|
||||
sqlite3DbFree(db, key);
|
||||
fprintf(stderr, "\nusing hex key\n");
|
||||
/* otherwise the key is provided as a string so hash it to get key data */
|
||||
} else {
|
||||
*nOut = SHA_DIGEST_LENGTH;
|
||||
|
@ -216,7 +224,7 @@ void* sqlite3Codec(void *iCtx, void *pData, Pgno pgno, int mode) {
|
|||
break;
|
||||
}
|
||||
|
||||
if(pgno == 1 ) {
|
||||
if(pgno == 1 && !convertnosalt) {
|
||||
/* if this is a read & decrypt operation on the first page then copy the
|
||||
first 16 bytes off the page into the context's random salt buffer
|
||||
*/
|
||||
|
@ -232,6 +240,10 @@ void* sqlite3Codec(void *iCtx, void *pData, Pgno pgno, int mode) {
|
|||
codec_cipher(ctx, pgno, emode, pg_sz, pData, ctx->buffer);
|
||||
}
|
||||
|
||||
if(emode == CIPHER_DECRYPT && convertnosalt) {
|
||||
convertnosalt = 0;
|
||||
}
|
||||
|
||||
if(emode == CIPHER_ENCRYPT) {
|
||||
return ctx->buffer; /* return persistent buffer data, pData remains intact */
|
||||
} else {
|
||||
|
@ -284,7 +296,7 @@ int sqlite3CodecAttach(sqlite3* db, int nDb, const void *zKey, int nKey) {
|
|||
RAND_pseudo_bytes(ctx->salt, FILE_HEADER_SZ);
|
||||
}
|
||||
|
||||
codec_prepare_key(zKey, nKey, ctx->salt, FILE_HEADER_SZ, ctx->key, &prepared_key_sz);
|
||||
codec_prepare_key(db, zKey, nKey, ctx->salt, FILE_HEADER_SZ, ctx->key, &prepared_key_sz);
|
||||
assert(prepared_key_sz == ctx->key_sz);
|
||||
|
||||
sqlite3BtreeSetPageSize(ctx->pBt, sqlite3BtreeGetPageSize(ctx->pBt), ctx->iv_sz, 0);
|
||||
|
@ -330,6 +342,9 @@ int sqlite3FreeCodecArg(void *pCodecArg) {
|
|||
|
||||
void sqlite3_activate_see(const char* in) {
|
||||
/* do nothing, security enhancements are always active */
|
||||
if(sqlite3StrICmp(in, "convertnosalt")==0) {
|
||||
convertnosalt = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int sqlite3_key(sqlite3 *db, const void *pKey, int nKey) {
|
||||
|
@ -390,7 +405,7 @@ int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey) {
|
|||
ctx->rekey_plaintext = 1;
|
||||
}
|
||||
|
||||
codec_prepare_key(pKey, nKey, ctx->salt, FILE_HEADER_SZ, key, &prepared_key_sz);
|
||||
codec_prepare_key(db, pKey, nKey, ctx->salt, FILE_HEADER_SZ, key, &prepared_key_sz);
|
||||
assert(prepared_key_sz == key_sz);
|
||||
|
||||
ctx->rekey = key; /* set rekey to new key data - note that ctx->key is original encryption key */
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
file delete -force test.db
|
||||
file delete -force test2.db
|
||||
file delete -force test3.db
|
||||
file delete -force test4.db
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
@ -59,9 +60,36 @@ do_test codec-1.1 {
|
|||
} {}
|
||||
db close
|
||||
|
||||
# set an encryption key and create some basic data
|
||||
# set an hex key create some basic data
|
||||
# create table and insert operations should work
|
||||
do_test codec-1.2 {
|
||||
sqlite_orig db test.db
|
||||
execsql {
|
||||
PRAGMA key = "x'98483C6EB40B6C31A448C22A66DED3B5E5E8D5119CAC8327B655C8B5C4836481'";
|
||||
CREATE table t1(a,b);
|
||||
INSERT INTO t1 VALUES ('test1', 'test2');
|
||||
}
|
||||
} {}
|
||||
db close
|
||||
|
||||
# close database, open it again with the same
|
||||
# hex key. verify that the table is readable
|
||||
# and the data just inserted is visible
|
||||
do_test codec-1.3 {
|
||||
sqlite_orig db test.db
|
||||
execsql {
|
||||
PRAGMA key = "x'98483C6EB40B6C31A448C22A66DED3B5E5E8D5119CAC8327B655C8B5C4836481'";
|
||||
SELECT name FROM sqlite_master WHERE type='table';
|
||||
SELECT * from t1;
|
||||
}
|
||||
} {t1 test1 test2}
|
||||
db close
|
||||
|
||||
file delete -force test.db
|
||||
|
||||
# set an encryption key and create some basic data
|
||||
# create table and insert operations should work
|
||||
do_test codec-1.4 {
|
||||
sqlite_orig db test.db
|
||||
execsql {
|
||||
PRAGMA key = 'testkey';
|
||||
|
@ -74,7 +102,7 @@ db close
|
|||
# close database, open it again with the same
|
||||
# key. verify that the table is readable
|
||||
# and the data just inserted is visible
|
||||
do_test codec-1.3 {
|
||||
do_test codec-1.5 {
|
||||
sqlite_orig db test.db
|
||||
execsql {
|
||||
PRAGMA key = 'testkey';
|
||||
|
@ -87,7 +115,7 @@ db close
|
|||
# open the database and try to read from it without
|
||||
# providing a passphrase. verify that the
|
||||
# an error is returned from the library
|
||||
do_test codec-1.4 {
|
||||
do_test codec-1.6 {
|
||||
sqlite_orig db test.db
|
||||
catchsql {
|
||||
SELECT name FROM sqlite_master WHERE type='table';
|
||||
|
@ -98,7 +126,7 @@ db close
|
|||
# open the database and try to set an invalid
|
||||
# passphrase. verify that an error is returned
|
||||
# and that data couldn't be read
|
||||
do_test codec-1.5 {
|
||||
do_test codec-1.7 {
|
||||
sqlite_orig db test.db
|
||||
catchsql {
|
||||
PRAGMA key = 'testkey2';
|
||||
|
@ -107,8 +135,18 @@ do_test codec-1.5 {
|
|||
} {1 {file is encrypted or is not a database}}
|
||||
db close
|
||||
|
||||
# test invalid hex key fails
|
||||
do_test codec-1.8 {
|
||||
sqlite_orig db test.db
|
||||
catchsql {
|
||||
PRAGMA key = "x'98483C6EB40B6C31A448C22A66DED3B5E5E8D5119CAC8327B655C8B5C4836480'";
|
||||
SELECT name FROM sqlite_master WHERE type='table';
|
||||
}
|
||||
} {1 {file is encrypted or is not a database}}
|
||||
db close
|
||||
|
||||
# test a large number of inserts in a transaction to a memory database
|
||||
do_test codec-1.6 {
|
||||
do_test codec-1.9 {
|
||||
sqlite_orig db :memory:
|
||||
execsql {
|
||||
PRAGMA key = 'testkey3';
|
||||
|
@ -128,18 +166,8 @@ do_test codec-1.6 {
|
|||
} {25000 0}
|
||||
db close
|
||||
|
||||
# test invalid hex key fails
|
||||
do_test codec-1.7 {
|
||||
sqlite_orig db test.db
|
||||
catchsql {
|
||||
PRAGMA hexkey = '98483C6EB40B6C31A448C22A66DED3B5E5E8D5119CAC8327B655C8B5C4836480';
|
||||
SELECT name FROM sqlite_master WHERE type='table';
|
||||
}
|
||||
} {1 {file is encrypted or is not a database}}
|
||||
db close
|
||||
|
||||
# test a large number of inserts in a transaction for multiple pages
|
||||
do_test codec-1.8 {
|
||||
do_test codec-1.10 {
|
||||
sqlite_orig db test.db
|
||||
execsql {
|
||||
PRAGMA key = 'testkey';
|
||||
|
@ -158,7 +186,7 @@ do_test codec-1.8 {
|
|||
db close
|
||||
|
||||
# test initial rekey
|
||||
do_test codec-1.9 {
|
||||
do_test codec-1.11 {
|
||||
sqlite_orig db test.db
|
||||
execsql {
|
||||
PRAGMA key = 'testkey';
|
||||
|
@ -169,7 +197,7 @@ db close
|
|||
|
||||
# test that now the new key opens the database
|
||||
# now close database re-open with new key
|
||||
do_test codec-1.10 {
|
||||
do_test codec-1.12 {
|
||||
sqlite_orig db test.db
|
||||
execsql {
|
||||
PRAGMA key = 'testkeynew';
|
||||
|
@ -179,7 +207,7 @@ do_test codec-1.10 {
|
|||
db close
|
||||
|
||||
# test rekey on an unecrypted database
|
||||
do_test codec-1.11 {
|
||||
do_test codec-1.13 {
|
||||
sqlite_orig db2 test2.db
|
||||
execsql {
|
||||
BEGIN;
|
||||
|
@ -208,7 +236,7 @@ do_test codec-1.11 {
|
|||
db2 close
|
||||
|
||||
# attach an encrypted database
|
||||
do_test codec-1.12 {
|
||||
do_test codec-1.14 {
|
||||
sqlite_orig db3 test3.db
|
||||
|
||||
execsql {
|
||||
|
@ -239,7 +267,7 @@ do_test codec-1.12 {
|
|||
} {25000 15000}
|
||||
db3 close
|
||||
|
||||
do_test codec-1.13 {
|
||||
do_test codec-1.15 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
} db2
|
||||
|
@ -260,7 +288,7 @@ do_test codec-1.13 {
|
|||
db2 close
|
||||
|
||||
# test locking across multiple handles
|
||||
do_test codec-1.14 {
|
||||
do_test codec-1.16 {
|
||||
sqlite_orig db3 test3.db
|
||||
|
||||
execsql {
|
||||
|
@ -278,7 +306,7 @@ do_test codec-1.14 {
|
|||
} {1 {database is locked}}
|
||||
|
||||
# test locks are released
|
||||
do_test codec-1.15 {
|
||||
do_test codec-1.17 {
|
||||
execsql {
|
||||
COMMIT;
|
||||
} db3
|
||||
|
@ -293,7 +321,7 @@ db3 close
|
|||
db3a close
|
||||
|
||||
# alter schema
|
||||
do_test codec-1.16 {
|
||||
do_test codec-1.18 {
|
||||
sqlite_orig db3 test3.db
|
||||
execsql {
|
||||
PRAGMA key = 'testkey';
|
||||
|
@ -306,7 +334,7 @@ do_test codec-1.16 {
|
|||
} {}
|
||||
db3 close
|
||||
|
||||
do_test codec-1.17 {
|
||||
do_test codec-1.19 {
|
||||
sqlite_orig db3 test3.db
|
||||
execsql {
|
||||
PRAGMA key = 'testkey';
|
||||
|
|
Loading…
Reference in New Issue