Version and environment
Reproduced from SQLCipher commit 810db22f575ee7cf94ea96a3e91622b5fcece3dc on Linux amd64. Runtime: SQLite 3.53.3 / SQLCipher 4.17.0 Community.
Describe the bug
PRAGMA cipher_hmac_pgno=be directly switches the page-number byte order used for page HMACs even after the key has been used and pages have been written. SQLCipher accepts the change, allows another successful write, and closes normally. Reopening with the same correct key and default format then fails HMAC authentication on page 1.
Minimal reproduction
bash sqlcipher-014-post-key-cipher-hmac-pgno-be-corrupts-an-encrypted-dat-a505e9e3/poc/run_revalidation.sh
The trigger SQL is:
PRAGMA key='testkey';
CREATE TABLE t(v);
INSERT INTO t VALUES('before');
SELECT count(*) FROM t;
PRAGMA cipher_hmac_pgno=be;
INSERT INTO t VALUES('after');
SELECT count(*) FROM t;
Close and reopen with the same key and default settings, then query the table and run PRAGMA integrity_check. The included control performs the same writes without changing cipher_hmac_pgno.
Actual behavior/output
control_create_rc=0
control_reopen_rc=0
PRAGMA cipher_hmac_pgno is deprecated, please remove from use
be
candidate_first_rc=0
candidate_reopen_rc=1
The failed reopen emits sqlcipher_page_cipher: hmac check failed for pgno=1 and file is not a database (26).
Expected behavior
Page-HMAC byte order should remain immutable once the key is used. A late change should be rejected or treated as a no-op; it must not create a file containing pages authenticated under inconsistent format assumptions.
Impact and scope
Although the compatibility PRAGMA is deprecated, applications can still invoke it and receive successful writes that persistently corrupt the encrypted database.
Relevant source/root cause
DEFAULT_CIPHER_FLAGS selects little-endian page numbers. sqlcipher_page_hmac() uses the LE/BE flags. The PRAGMA branch at src/sqlcipher.c:2959-2976 directly clears/sets those flags without checking CIPHER_FLAG_KEY_USED, unlike other cryptographic-format setters.
Suggested regression test
After creating and reading/writing a default-format encrypted database, execute PRAGMA cipher_hmac_pgno=be. Assert rejection or no state change, then write, close, reopen with the correct key, and verify all rows plus integrity_check.
Reproduction bundle
Attached: sqlcipher-014-post-key-cipher-hmac-pgno-be-corrupts-an-encrypted-dat-a505e9e3_attachment.zip. It contains the focused PoC, validation evidence, and candidate metadata.
sqlcipher-014-post-key-cipher-hmac-pgno-be-corrupts-an-encrypted-dat-a505e9e3_attachment.zip
Version and environment
Reproduced from SQLCipher commit
810db22f575ee7cf94ea96a3e91622b5fcece3dcon Linux amd64. Runtime: SQLite 3.53.3 / SQLCipher 4.17.0 Community.Describe the bug
PRAGMA cipher_hmac_pgno=bedirectly switches the page-number byte order used for page HMACs even after the key has been used and pages have been written. SQLCipher accepts the change, allows another successful write, and closes normally. Reopening with the same correct key and default format then fails HMAC authentication on page 1.Minimal reproduction
The trigger SQL is:
Close and reopen with the same key and default settings, then query the table and run
PRAGMA integrity_check. The included control performs the same writes without changingcipher_hmac_pgno.Actual behavior/output
The failed reopen emits
sqlcipher_page_cipher: hmac check failed for pgno=1andfile is not a database (26).Expected behavior
Page-HMAC byte order should remain immutable once the key is used. A late change should be rejected or treated as a no-op; it must not create a file containing pages authenticated under inconsistent format assumptions.
Impact and scope
Although the compatibility PRAGMA is deprecated, applications can still invoke it and receive successful writes that persistently corrupt the encrypted database.
Relevant source/root cause
DEFAULT_CIPHER_FLAGSselects little-endian page numbers.sqlcipher_page_hmac()uses the LE/BE flags. The PRAGMA branch atsrc/sqlcipher.c:2959-2976directly clears/sets those flags without checkingCIPHER_FLAG_KEY_USED, unlike other cryptographic-format setters.Suggested regression test
After creating and reading/writing a default-format encrypted database, execute
PRAGMA cipher_hmac_pgno=be. Assert rejection or no state change, then write, close, reopen with the correct key, and verify all rows plusintegrity_check.Reproduction bundle
Attached:
sqlcipher-014-post-key-cipher-hmac-pgno-be-corrupts-an-encrypted-dat-a505e9e3_attachment.zip. It contains the focused PoC, validation evidence, and candidate metadata.sqlcipher-014-post-key-cipher-hmac-pgno-be-corrupts-an-encrypted-dat-a505e9e3_attachment.zip