Version and environment
Reproduced on SQLCipher commit 810db22f575ee7cf94ea96a3e91622b5fcece3dc, Linux amd64, with a fresh runtime reporting SQLite 3.53.3 / SQLCipher 4.17.0 Community.
Describe the bug
Unlike neighboring format setters, sqlcipher_codec_ctx_set_plaintext_header_size() does not reject changes after the key has been derived and used. Changing cipher_plaintext_header_size from 0 to 16 after initial reads/writes changes page-1 crypto offsets mid-connection. Further writes and integrity_check report success, but the committed database cannot be reopened with the correct key.
Minimal reproduction
bash sqlcipher-013-post-key-cipher-plaintext-header-size-corrupts-an-encr-cff04674/poc/run_revalidation.sh
The trigger sequence is:
PRAGMA key='testkey';
CREATE TABLE t1(v);
INSERT INTO t1 VALUES('before');
SELECT count(*) FROM t1;
PRAGMA cipher_plaintext_header_size=16;
INSERT INTO t1 VALUES('after');
SELECT count(*) FROM t1;
PRAGMA integrity_check;
Close the database, reopen the same file with PRAGMA key='testkey', then run SELECT count(*) FROM t1; PRAGMA integrity_check;. The supplied control sets a fixed salt and plaintext-header size before any page use and successfully reopens.
Actual behavior/output
before_count|1
16
after_count|2
ok
first_connection_exit=0
reopen_with_correct_key_exit=1
Reopen stderr includes sqlcipher_page_cipher: hmac check failed for pgno=1 and file is not a database (26). The pre-key control creates and reopens successfully.
Expected behavior
After a key has been used, a setting that changes page-1 header/salt/encryption layout should be rejected or ignored before any state changes. A successful write must not leave the file unreadable with the correct key.
Impact and scope
An accepted PRAGMA can persistently corrupt an otherwise valid encrypted database. The first connection provides misleading success, so the damage may be discovered only after close/reopen.
Relevant source/root cause
Sibling setters around src/sqlcipher.c:1396, :1418, and :1450 check CIPHER_FLAG_KEY_USED. The plaintext-header setter at :1439-1442 lacks that guard. The PRAGMA branch at :3006-3012 also ignores the setter result. Page-1 read/write code around :3442-3450 and :3484-3493 uses the mutable header size as its offset.
Suggested regression test
Create and read/write an encrypted database, then set cipher_plaintext_header_size=16. Assert that the setting is rejected or unchanged, and verify after close/reopen that all rows remain readable and both integrity checks pass.
Reproduction bundle
Attached: sqlcipher-013-post-key-cipher-plaintext-header-size-corrupts-an-encr-cff04674_attachment.zip. It contains the focused PoC, validation evidence, and candidate metadata.
sqlcipher-013-post-key-cipher-plaintext-header-size-corrupts-an-encr-cff04674_attachment.zip
Version and environment
Reproduced on SQLCipher commit
810db22f575ee7cf94ea96a3e91622b5fcece3dc, Linux amd64, with a fresh runtime reporting SQLite 3.53.3 / SQLCipher 4.17.0 Community.Describe the bug
Unlike neighboring format setters,
sqlcipher_codec_ctx_set_plaintext_header_size()does not reject changes after the key has been derived and used. Changingcipher_plaintext_header_sizefrom 0 to 16 after initial reads/writes changes page-1 crypto offsets mid-connection. Further writes andintegrity_checkreport success, but the committed database cannot be reopened with the correct key.Minimal reproduction
The trigger sequence is:
Close the database, reopen the same file with
PRAGMA key='testkey', then runSELECT count(*) FROM t1; PRAGMA integrity_check;. The supplied control sets a fixed salt and plaintext-header size before any page use and successfully reopens.Actual behavior/output
Reopen stderr includes
sqlcipher_page_cipher: hmac check failed for pgno=1andfile is not a database (26). The pre-key control creates and reopens successfully.Expected behavior
After a key has been used, a setting that changes page-1 header/salt/encryption layout should be rejected or ignored before any state changes. A successful write must not leave the file unreadable with the correct key.
Impact and scope
An accepted PRAGMA can persistently corrupt an otherwise valid encrypted database. The first connection provides misleading success, so the damage may be discovered only after close/reopen.
Relevant source/root cause
Sibling setters around
src/sqlcipher.c:1396,:1418, and:1450checkCIPHER_FLAG_KEY_USED. The plaintext-header setter at:1439-1442lacks that guard. The PRAGMA branch at:3006-3012also ignores the setter result. Page-1 read/write code around:3442-3450and:3484-3493uses the mutable header size as its offset.Suggested regression test
Create and read/write an encrypted database, then set
cipher_plaintext_header_size=16. Assert that the setting is rejected or unchanged, and verify after close/reopen that all rows remain readable and both integrity checks pass.Reproduction bundle
Attached:
sqlcipher-013-post-key-cipher-plaintext-header-size-corrupts-an-encr-cff04674_attachment.zip. It contains the focused PoC, validation evidence, and candidate metadata.sqlcipher-013-post-key-cipher-plaintext-header-size-corrupts-an-encr-cff04674_attachment.zip