Skip to content

Commit f1ea44e

Browse files
committed
pragma allows le, be, or native pgno ordering plus tests
1 parent 7f2b44c commit f1ea44e

6 files changed

Lines changed: 73 additions & 15 deletions

File tree

sqlcipher-2.0-be-testkey.db

2 KB
Binary file not shown.

src/crypto.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,19 @@ int codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLeft, const c
129129
rc = codec_set_btree_to_codec_pagesize(db, pDb, ctx);
130130
if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc);
131131
}
132+
}else
133+
if( sqlite3StrICmp(zLeft,"cipher_hmac_pgno")==0 ){
134+
// clear both pgno endian flags
135+
if(sqlite3StrICmp(zRight, "le") == 0) {
136+
sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_BE_PGNO);
137+
sqlcipher_codec_ctx_set_flag(ctx, CIPHER_FLAG_LE_PGNO);
138+
} else if(sqlite3StrICmp(zRight, "be") == 0) {
139+
sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_LE_PGNO);
140+
sqlcipher_codec_ctx_set_flag(ctx, CIPHER_FLAG_BE_PGNO);
141+
} else if(sqlite3StrICmp(zRight, "native") == 0) {
142+
sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_LE_PGNO);
143+
sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_BE_PGNO);
144+
}
132145
}else {
133146
return 0;
134147
}

src/crypto.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
/* possible flags for cipher_ctx->flags */
6060
#define CIPHER_FLAG_HMAC 0x01
6161
#define CIPHER_FLAG_LE_PGNO 0x02
62+
#define CIPHER_FLAG_BE_PGNO 0x04
6263

6364
#ifndef DEFAULT_CIPHER_FLAGS
6465
#define DEFAULT_CIPHER_FLAGS CIPHER_FLAG_HMAC | CIPHER_FLAG_LE_PGNO

src/crypto_impl.c

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,7 @@ void sqlcipher_codec_ctx_free(codec_ctx **iCtx) {
497497
sqlcipher_free(ctx, sizeof(codec_ctx));
498498
}
499499

500+
/** convert a 32bit unsigned integer to little endian byte ordering */
500501
static inline void sqlcipher_put4byte_le(unsigned char *p, u32 v) {
501502
p[0] = (u8)v;
502503
p[1] = (u8)(v>>8);
@@ -505,29 +506,31 @@ static inline void sqlcipher_put4byte_le(unsigned char *p, u32 v) {
505506
}
506507

507508
int sqlcipher_page_hmac(cipher_ctx *ctx, Pgno pgno, unsigned char *in, int in_sz, unsigned char *out) {
508-
unsigned char pgno_le[4];
509-
/* convert page number to consistent representation before calculating MAC for
509+
unsigned char pgno_raw[sizeof(pgno)];
510+
/* we may convert page number to consistent representation before calculating MAC for
510511
compatibility across big-endian and little-endian platforms.
511512
512513
Note: The public release of sqlcipher 2.0.0 to 2.0.6 had a bug where the bytes of pgno
513-
were used directly in the MAC. So, we convert to little endian instead of big endian, to
514-
preserve backwards compatibility on the most popular platform */
515-
sqlcipher_put4byte_le(pgno_le, pgno);
514+
were used directly in the MAC. SQLCipher convert's to little endian by default to preserve
515+
backwards compatibility on the most popular platforms, but can optionally be configured
516+
to use either big endian or native byte ordering via pragma. */
517+
518+
if(ctx->flags & CIPHER_FLAG_LE_PGNO) { /* compute hmac using little endian pgno*/
519+
sqlcipher_put4byte_le(pgno_raw, pgno);
520+
} else if(ctx->flags & CIPHER_FLAG_BE_PGNO) { /* compute hmac using big endian pgno */
521+
sqlite3Put4byte(pgno_raw, pgno); /* sqlite3Put4byte converts 32bit uint to big endian */
522+
} else { /* use native byte ordering */
523+
memcpy(pgno_raw, &pgno, sizeof(pgno));
524+
}
516525

517526
HMAC_CTX_init(&ctx->hctx);
518-
519527
HMAC_Init_ex(&ctx->hctx, ctx->hmac_key, ctx->key_sz, EVP_sha1(), NULL);
520528

521529
/* include the encrypted page data, initialization vector, and page number in HMAC. This will
522530
prevent both tampering with the ciphertext, manipulation of the IV, or resequencing otherwise
523531
valid pages out of order in a database */
524532
HMAC_Update(&ctx->hctx, in, in_sz);
525-
526-
if(ctx->flags & CIPHER_FLAG_LE_PGNO) /* default compute hmac using little endian */
527-
HMAC_Update(&ctx->hctx, (const unsigned char*) pgno_le, sizeof(pgno_le));
528-
else /* legacy setting - compute using native byte ordering */
529-
HMAC_Update(&ctx->hctx, (const unsigned char*) &pgno, sizeof(pgno));
530-
533+
HMAC_Update(&ctx->hctx, (const unsigned char*) pgno_raw, sizeof(pgno));
531534
HMAC_Final(&ctx->hctx, out, NULL);
532535
HMAC_CTX_cleanup(&ctx->hctx);
533536
return SQLITE_OK;

test/crypto.test

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1556,9 +1556,10 @@ do_test multipage-schema-autovacuum-shortread-wal {
15561556
db close
15571557
file delete -force test.db
15581558

1559-
# open a 2.0 database verify it can be opened
1560-
do_test open-2.0-database {
1561-
sqlite_orig db sqlcipher-2.0-testkey.db
1559+
# open a 2.0 database with little endian hmac page numbers (default)
1560+
# verify it can be opened
1561+
do_test open-2.0-le-database {
1562+
sqlite_orig db sqlcipher-2.0-le-testkey.db
15621563
execsql {
15631564
PRAGMA key = 'testkey';
15641565
SELECT count(*) FROM t1;
@@ -1567,4 +1568,44 @@ do_test open-2.0-database {
15671568
} {4 1 1 one one 1 2 one two}
15681569
db close
15691570

1571+
# open a 2.0 database with big-endian hmac page numbers
1572+
# verify it can be opened
1573+
do_test open-2.0-be-database {
1574+
sqlite_orig db sqlcipher-2.0-be-testkey.db
1575+
execsql {
1576+
PRAGMA key = 'testkey';
1577+
PRAGMA cipher_hmac_pgno = be;
1578+
SELECT count(*) FROM t1;
1579+
SELECT * FROM t1;
1580+
}
1581+
} {4 1 1 one one 1 2 one two}
1582+
db close
1583+
1584+
# open a 2.0 database with big-endian hmac page numbers
1585+
# attach a new database with little endian page numbers (default)
1586+
# copy schema between the two, and verify the latter
1587+
# can be opened
1588+
do_test be-to-le-migration {
1589+
sqlite_orig db sqlcipher-2.0-be-testkey.db
1590+
1591+
execsql {
1592+
PRAGMA key = 'testkey';
1593+
PRAGMA cipher_hmac_pgno = be;
1594+
ATTACH DATABASE 'test.db' AS db2 KEY 'testkey';
1595+
CREATE TABLE db2.t1(a,b);
1596+
INSERT INTO db2.t1 SELECT * FROM main.t1;
1597+
DETACH DATABASE db2;
1598+
}
1599+
db close
1600+
1601+
sqlite_orig db test.db
1602+
execsql {
1603+
PRAGMA key = 'testkey';
1604+
SELECT count(*) FROM t1;
1605+
SELECT * FROM t1;
1606+
}
1607+
} {4 1 1 one one 1 2 one two}
1608+
db close
1609+
file delete -force test.db
1610+
15701611
finish_test

0 commit comments

Comments
 (0)