2 # codec.test developed by Stephen Lombardo (Zetetic LLC)
3 # sjlombardo at zetetic dot net
6 # Copyright (c) 2018, ZETETIC LLC
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions are met:
9 # * Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # * Redistributions in binary form must reproduce the above copyright
12 # notice, this list of conditions and the following disclaimer in the
13 # documentation and/or other materials provided with the distribution.
14 # * Neither the name of the ZETETIC LLC nor the
15 # names of its contributors may be used to endorse or promote products
16 # derived from this software without specific prior written permission.
18 # THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
19 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 # DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
22 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 # This file implements regression tests for SQLite library. The
30 # focus of this script is testing code cipher features.
32 # NOTE: tester.tcl has overridden the definition of sqlite3 to
33 # automatically pass in a key value. Thus tests in this file
34 # should explicitly close and open db with sqlite_orig in order
35 # to bypass default key assignment.
37 set testdir [file dirname $argv0]
38 source $testdir/tester.tcl
39 source $testdir/sqlcipher.tcl
41 # The database is initially empty.
42 # set an hex key create some basic data
43 # create table and insert operations should work
44 # close database, open it again with the same
45 # hex key. verify that the table is readable
46 # and the data just inserted is visible
47 setup test.db "\"x'98483C6EB40B6C31A448C22A66DED3B5E5E8D5119CAC8327B655C8B5C4836481'\""
48 do_test will-open-with-correct-raw-key {
49 sqlite_orig db test.db
51 PRAGMA key = "x'98483C6EB40B6C31A448C22A66DED3B5E5E8D5119CAC8327B655C8B5C4836481'";
52 SELECT name FROM sqlite_schema WHERE type='table';
57 file delete -force test.db
59 # set an encryption key (non-hex) and create some basic data
60 # create table and insert operations should work
61 # close database, open it again with the same
62 # key. verify that the table is readable
63 # and the data just inserted is visible
64 setup test.db "'testkey'"
65 do_test will-open-with-correct-derived-key {
67 sqlite_orig db test.db
69 PRAGMA key = 'testkey';
70 SELECT name FROM sqlite_schema WHERE type='table';
75 file delete -force test.db
77 # set an encryption key (non-hex) and create
78 # temp tables, verify you can read from
80 setup test.db "'testkey'"
81 do_test test-temp-master {
82 sqlite_orig db test.db
84 PRAGMA key = 'testkey';
85 CREATE TEMPORARY TABLE temp_t1(a,b);
86 INSERT INTO temp_t1(a,b) VALUES ('test1', 'test2');
87 SELECT name FROM sqlite_temp_master WHERE type='table';
88 SELECT * from temp_t1;
90 } {ok temp_t1 test1 test2}
92 file delete -force test.db
94 # verify that a when a standard database is encrypted the first
95 # 16 bytes are not "SQLite format 3\0"
96 do_test test-sqlcipher-header-overwrite {
97 sqlite_orig db test.db
100 CREATE TABLE t1(a,b);
103 set header [hexio_read test.db 0 16]
104 string equal $header "53514C69746520666F726D6174203300"
106 file delete -force test.db
108 # open the database and try to read from it without
109 # providing a passphrase. verify that the
110 # an error is returned from the library
111 setup test.db "'testkey'"
112 do_test wont-open-without-key {
113 sqlite_orig db test.db
115 SELECT name FROM sqlite_schema WHERE type='table';
117 } {1 {file is not a database}}
119 file delete -force test.db
121 # open the database and try to set an invalid
122 # passphrase. verify that an error is returned
123 # and that data couldn't be read
124 setup test.db "'testkey'"
125 do_test wont-open-with-invalid-derived-key {
126 sqlite_orig db test.db
128 PRAGMA key = 'testkey2';
129 SELECT name FROM sqlite_schema WHERE type='table';
131 } {1 {file is not a database}}
133 file delete -force test.db
135 # open the database and try to set an invalid
136 # hex key. verify that an error is returned
137 # and that data couldn't be read
138 setup test.db "'testkey'"
139 do_test wont-open-with-invalid-raw-key {
140 sqlite_orig db test.db
142 PRAGMA key = "x'98483C6EB40B6C31A448C22A66DED3B5E5E8D5119CAC8327B655C8B5C4836480'";
143 SELECT name FROM sqlite_schema WHERE type='table';
145 } {1 {file is not a database}}
147 file delete -force test.db
149 # test a large number of inserts in a transaction to a memory database
150 do_test memory-database {
151 sqlite_orig db :memory:
153 PRAGMA key = 'testkey3';
155 CREATE TABLE t2(a,b);
157 for {set i 1} {$i<=25000} {incr i} {
158 set r [expr {int(rand()*500000)}]
159 execsql "INSERT INTO t2 VALUES($i,$r);"
163 SELECT count(*) FROM t2;
165 SELECT count(*) FROM t2;
170 # test a large number of inserts in a transaction for multiple pages
171 do_test multi-page-database {
172 sqlite_orig db test.db
174 PRAGMA key = 'testkey';
175 CREATE TABLE t2(a,b);
178 for {set i 1} {$i<=25000} {incr i} {
179 set r [expr {int(rand()*500000)}]
180 execsql "INSERT INTO t2 VALUES($i,$r);"
184 SELECT count(*) FROM t2;
188 file delete -force test.db
190 # attach an encrypted database
191 # without specifying key, verify it fails
192 # even if the source passwords are the same
193 # because the kdf salts are different
194 setup test.db "'testkey'"
195 do_test attach-database-with-default-key {
196 sqlite_orig db2 test2.db
200 PRAGMA key = 'testkey';
201 PRAGMA cipher_add_random = "x'deadbaad'";
202 CREATE TABLE t2(a,b);
203 INSERT INTO t2 VALUES ('test1', 'test2');
206 lappend rc [catchsql {
207 ATTACH 'test.db' AS db;
210 lappend rc [string equal [hexio_read test.db 0 16] [hexio_read test2.db 0 16]]
212 } {{1 {file is not a database}} 0}
214 file delete -force test.db
215 file delete -force test2.db
217 # attach an empty encrypted database
218 # without specifying key, verify the database has the same
219 # salt and as the original
220 setup test.db "'testkey'"
221 do_test attach-empty-database-with-default-key {
222 sqlite_orig db test.db
226 PRAGMA key='testkey';
227 INSERT INTO t1(a,b) values (1,2);
228 ATTACH DATABASE 'test2.db' AS test;
229 CREATE TABLE test.t1(a,b);
230 INSERT INTO test.t1 SELECT * FROM t1;
231 DETACH DATABASE test;
234 sqlite_orig db2 test2.db
236 lappend rc [execsql {
237 PRAGMA key='testkey';
238 SELECT count(*) FROM t1;
240 lappend rc [string equal [hexio_read test.db 0 16] [hexio_read test2.db 0 16]]
244 file delete -force test.db
245 file delete -force test2.db
247 # attach an empty encrypted database as the first operation on a keyed database. Verify
248 # that the new database has the same salt as the original.
250 # HISTORICAL NOTE: The original behavior of SQLCipher under these conditions
251 # was that the databases would have different salts but the same keys. This was because
252 # derivation of the key spec would not have occurred yet. However, upstream check-in
253 # https://sqlite.org/src/info/a02da71f3a80dd8e changed this behavior by
254 # forcing a read of the main database schema during the attach operation.
255 # This causes the main database to be opened and the key derivation logic to fire which
256 # reads the salt. Thus the current behavior of this test should now be identical
257 # to the previous attach-empty-database-with-default-key.
259 setup test.db "'testkey'"
260 do_test attach-empty-database-with-default-key-first-op {
261 sqlite_orig db test.db
265 PRAGMA key='testkey';
266 ATTACH DATABASE 'test2.db' AS test;
267 CREATE TABLE test.t1(a,b);
268 INSERT INTO test.t1 SELECT * FROM t1;
269 DETACH DATABASE test;
272 sqlite_orig db2 test2.db
274 lappend rc [execsql {
275 PRAGMA key='testkey';
276 SELECT count(*) FROM t1;
279 lappend rc [string equal [hexio_read test.db 0 16] [hexio_read test2.db 0 16]]
283 file delete -force test.db
284 file delete -force test2.db
286 # attach an empty encrypted database
287 # on a keyed database when PRAGMA cipher_store_pass = 1
288 # and verify different salts
289 setup test.db "'testkey'"
290 do_test attach-empty-database-with-cipher-store-pass {
291 sqlite_orig db test.db
295 PRAGMA key='testkey';
296 PRAGMA cipher_store_pass = 1;
297 INSERT INTO t1(a,b) VALUES (1,2);
298 ATTACH DATABASE 'test2.db' AS test;
299 CREATE TABLE test.t1(a,b);
300 INSERT INTO test.t1 SELECT * FROM t1;
301 DETACH DATABASE test;
304 sqlite_orig db2 test2.db
306 lappend rc [execsql {
307 PRAGMA key='testkey';
308 SELECT count(*) FROM t1;
310 lappend rc [string equal [hexio_read test.db 0 16] [hexio_read test2.db 0 16]]
314 file delete -force test.db
315 file delete -force test2.db
317 # attach an encrypted database
318 # without specifying key, verify it attaches
319 # correctly when PRAGMA cipher_store_pass = 1
321 do_test attach-database-with-default-key-using-cipher-store-pass {
322 sqlite_orig db1 test.db
324 PRAGMA key = 'testkey';
325 CREATE TABLE t1(a,b);
326 INSERT INTO t1(a,b) VALUES('foo', 'bar');
330 sqlite_orig db2 test2.db
332 PRAGMA key = 'testkey';
333 CREATE TABLE t2(a,b);
334 INSERT INTO t2 VALUES ('test1', 'test2');
338 sqlite_orig db1 test.db
340 PRAGMA key = 'testkey';
341 PRAGMA cipher_store_pass = 1;
342 ATTACH DATABASE 'test2.db' as db2;
343 SELECT sqlcipher_export('db2');
348 sqlite_orig db2 test2.db
350 PRAGMA key = 'testkey';
356 file delete -force test.db
357 file delete -force test2.db
359 # attach an encrypted database
360 # where both database have the same
361 # key explicitly and verify they have different
363 setup test.db "'testkey'"
364 do_test attach-database-with-same-key {
365 sqlite_orig db2 test2.db
370 PRAGMA key = 'testkey';
371 CREATE TABLE t2(a,b);
372 INSERT INTO t2 VALUES ('test1', 'test2');
375 lappend rc [execsql {
376 SELECT count(*) FROM t2;
377 ATTACH 'test.db' AS db KEY 'testkey';
378 SELECT count(*) FROM db.t1;
381 lappend rc [string equal [hexio_read test.db 0 16] [hexio_read test2.db 0 16]]
384 file delete -force test.db
385 file delete -force test2.db
387 # attach an encrypted database
388 # where databases have different keys
389 setup test.db "'testkey'"
390 do_test attach-database-with-different-keys {
391 sqlite_orig db2 test2.db
394 PRAGMA key = 'testkey2';
395 CREATE TABLE t2(a,b);
396 INSERT INTO t2 VALUES ('test1', 'test2');
400 ATTACH 'test.db' AS db KEY 'testkey';
401 SELECT count(*) FROM db.t1;
402 SELECT count(*) FROM t2;
407 file delete -force test.db
408 file delete -force test2.db
410 # test locking across multiple handles
411 setup test.db "'testkey'"
412 do_test locking-across-multiple-handles-start {
413 sqlite_orig db test.db
416 PRAGMA key = 'testkey';
418 INSERT INTO t1 VALUES(1,2);
421 sqlite_orig dba test.db
423 PRAGMA key = 'testkey';
424 SELECT count(*) FROM t1;
427 } {1 {database is locked}}
429 do_test locking-accross-multiple-handles-finish {
435 SELECT count(*) FROM t1;
440 file delete -force test.db
443 setup test.db "'testkey'"
444 do_test alter-schema {
445 sqlite_orig db test.db
447 PRAGMA key = 'testkey';
448 ALTER TABLE t1 ADD COLUMN c;
449 INSERT INTO t1 VALUES (1,2,3);
450 INSERT INTO t1 VALUES (1,2,4);
451 CREATE TABLE t1a (a);
452 INSERT INTO t1a VALUES ('teststring');
456 sqlite_orig db test.db
458 PRAGMA key = 'testkey';
459 SELECT count(*) FROM t1 WHERE a IS NOT NULL;
460 SELECT count(*) FROM t1 WHERE c IS NOT NULL;
464 } {ok 3 2 teststring}
466 file delete -force test.db
468 # test alterations of KDF iterations and ciphers
470 setup test.db "'testkey'"
471 do_test verify-errors-for-rekey-kdf-and-cipher-changes {
472 sqlite_orig db test.db
474 PRAGMA key = 'testkey';
475 PRAGMA rekey_kdf_iter = 1000;
476 PRAGMA rekey_cipher = 'aes-256-ecb';
478 } {ok {PRAGMA rekey_kdf_iter is no longer supported.} {PRAGMA rekey_cipher is no longer supported.}}
480 file delete -force test.db
483 setup test.db "'testkey'"
484 do_test verify-errors-for-cipher-change {
485 sqlite_orig db test.db
487 PRAGMA key = 'testkey';
488 PRAGMA cipher = 'aes-256-ecb';
490 } {ok {PRAGMA cipher is no longer supported.}}
492 file delete -force test.db
495 # 1. create a database with a custom page size,
496 # 2. create table and insert operations should work
497 # 3. close database, open it again with the same
499 # 4. verify that the table is readable
500 # and the data just inserted is visible
501 do_test custom-pagesize {
502 sqlite_orig db test.db
505 PRAGMA key = 'testkey';
506 PRAGMA cipher_page_size = 8192;
507 CREATE table t1(a,b);
511 for {set i 1} {$i<=1000} {incr i} {
512 set r [expr {int(rand()*500000)}]
513 execsql "INSERT INTO t1 VALUES($i,'value $r');"
521 sqlite_orig db test.db
524 PRAGMA key = 'testkey';
525 PRAGMA cipher_page_size = 8192;
526 SELECT count(*) FROM t1;
532 # open the database with the default page size
533 ## and verfiy that it is not readable
534 do_test custom-pagesize-must-match {
535 sqlite_orig db test.db
537 PRAGMA key = 'testkey';
538 SELECT name FROM sqlite_schema WHERE type='table';
540 } {1 {file is not a database}}
542 file delete -force test.db
545 # 1. create a database with WAL journal mode
546 # 2. create table and insert operations should work
547 # 3. close database, open it again
548 # 4. verify that the table is present, readable, and that
549 # the journal mode is WAL
550 do_test journal-mode-wal {
551 sqlite_orig db test.db
554 PRAGMA key = 'testkey';
555 PRAGMA journal_mode = WAL;
556 CREATE table t1(a,b);
560 for {set i 1} {$i<=1000} {incr i} {
561 set r [expr {int(rand()*500000)}]
562 execsql "INSERT INTO t1 VALUES($i,'value $r');"
570 sqlite_orig db test.db
573 PRAGMA key = 'testkey';
574 SELECT count(*) FROM t1;
580 file delete -force test.db
582 # open a database and try to use an invalid
583 # passphrase. verify that an error is returned
584 # and that data couldn't be read. without closing the databsae
585 # set the correct key and verify it is working.
586 setup test.db "'testkey'"
587 do_test multiple-key-calls-safe-wrong-key-first {
588 sqlite_orig db test.db
591 lappend rc [catchsql {
592 PRAGMA key = 'testkey2';
593 SELECT count(*) FROM sqlite_schema;
596 lappend rc [execsql {
597 PRAGMA key = 'testkey';
598 SELECT count(*) FROM sqlite_schema;
600 } {{1 {file is not a database}} {ok 1}}
602 file delete -force test.db
604 # open a databse and use the valid key. Then
605 # use pragma key to try to set an invalid key
606 # without closing the database. It should not do anything
608 setup test.db "'testkey'"
609 do_test multiple-key-calls-safe {
610 sqlite_orig db test.db
612 PRAGMA key = 'testkey';
613 PRAGMA cache_size = 0;
614 SELECT name FROM sqlite_schema WHERE type='table';
615 PRAGMA key = 'wrong key';
616 SELECT name FROM sqlite_schema WHERE type='table';
617 PRAGMA key = 'testkey';
618 SELECT name FROM sqlite_schema WHERE type='table';
620 } {ok t1 ok t1 ok t1}
623 file delete -force test.db
625 # 1. create a database with a custom hmac kdf iteration count,
626 # 2. create table and insert operations should work
627 # 3. close database, open it again with the same
628 # key and hmac kdf iteration count
629 # 4. verify that the table is readable
630 # and the data just inserted is visible
631 do_test custom-hmac-kdf-iter {
632 sqlite_orig db test.db
635 PRAGMA key = 'testkey';
636 PRAGMA kdf_iter = 10;
637 CREATE table t1(a,b);
641 for {set i 1} {$i<=1000} {incr i} {
642 set r [expr {int(rand()*500000)}]
643 execsql "INSERT INTO t1 VALUES($i,'value $r');"
651 sqlite_orig db test.db
654 PRAGMA key = 'testkey';
655 PRAGMA kdf_iter = 10;
656 SELECT count(*) FROM t1;
662 # open the database with the default hmac
663 # kdf iteration count
664 # to verify that it is not readable
665 do_test custom-hmac-kdf-iter-must-match {
666 sqlite_orig db test.db
668 PRAGMA key = 'testkey';
669 SELECT name FROM sqlite_schema WHERE type='table';
671 } {1 {file is not a database}}
673 file delete -force test.db
675 # open the database and turn on auto_vacuum
676 # then insert a bunch of data, delete it
677 # and verify that the file has become smaller
678 # but can still be opened with the proper
680 do_test auto-vacuum {
681 sqlite_orig db test.db
685 PRAGMA key = 'testkey';
686 PRAGMA auto_vacuum=FULL;
687 CREATE table t1(a,b);
691 for {set i 1} {$i<=10000} {incr i} {
692 set r [expr {int(rand()*500000)}]
693 execsql "INSERT INTO t1 VALUES($i,'value $r');"
696 lappend rc [execsql {
698 SELECT count(*) FROM t1;
701 # grab current size of file
702 set sz [file size test.db]
704 # delete some records, and verify
705 # autovacuum removes them
707 DELETE FROM t1 WHERE rowid > 5000;
712 # grab new file size, post
714 set sz2 [file size test.db]
716 # verify that the new size is
717 # smaller than the old size
718 if {$sz > $sz2} { lappend rc true }
720 sqlite_orig db test.db
722 lappend rc [execsql {
723 PRAGMA key = 'testkey';
724 SELECT count(*) FROM t1;
727 } {10000 true {ok 5000}}
729 file delete -force test.db
731 # test kdf_iter and other pragmas
732 # before a key is set. Verify that they
734 do_test cipher-options-before-keys {
735 sqlite_orig db test.db
738 PRAGMA kdf_iter = 1000;
739 PRAGMA cipher_page_size = 8192;
740 PRAGMA cipher_use_hmac = OFF;
741 PRAGMA key = 'testkey';
742 CREATE table t1(a,b);
743 INSERT INTO t1 VALUES(1,2);
747 sqlite_orig db test.db
750 PRAGMA key = 'testkey';
751 SELECT count(*) FROM t1;
756 file delete -force test.db
758 # verify memory security behavior
759 # initially should report OFF
760 # then enable, check that it is ON
761 # try to turn if off, but verify that it
763 do_test verify-memory-security {
764 sqlite_orig db test.db
766 PRAGMA cipher_memory_security;
767 PRAGMA cipher_memory_security = ON;
768 PRAGMA cipher_memory_security;
769 PRAGMA cipher_memory_security = OFF;
770 PRAGMA cipher_memory_security;
774 file delete -force test.db
776 # create two new database files, write to each
777 # and verify that they have different (i.e. random)
779 do_test test-random-salt {
780 sqlite_orig db test.db
781 sqlite_orig db2 test2.db
784 CREATE TABLE t1(a,b);
785 INSERT INTO t1(a,b) VALUES (1,2);
789 CREATE TABLE t1(a,b);
790 INSERT INTO t1(a,b) VALUES (1,2);
794 string equal [hexio_read test.db 0 16] [hexio_read test2.db 0 16]
796 file delete -force test.db
797 file delete -force test2.db
799 # test scenario where multiple handles are opened
800 # to a file that does not exist, where both handles
802 do_test multiple-handles-same-key-and-salt {
803 sqlite_orig db test.db
804 sqlite_orig dba test.db
807 PRAGMA key = 'testkey';
810 PRAGMA key = 'testkey';
814 CREATE TABLE t1(a,b);
815 INSERT INTO t1 VALUES(1,2);
819 SELECT count(*) FROM t1;
822 SELECT count(*) FROM t1;
828 file delete -force test.db
830 do_test test_flags_fail_encrypt {
831 sqlite_orig db :memory:
834 PRAGMA cipher_test_on = fail_encrypt;
836 PRAGMA cipher_test_off = fail_encrypt;
842 do_test test_flags_fail_decrypt {
843 sqlite_orig db :memory:
846 PRAGMA cipher_test_on = fail_decrypt;
848 PRAGMA cipher_test_off = fail_decrypt;
854 do_test test_flags_fail_migrate {
855 sqlite_orig db :memory:
858 PRAGMA cipher_test_on = fail_migrate;
860 PRAGMA cipher_test_off = fail_migrate;
866 do_test test_flags_combo {
867 sqlite_orig db :memory:
870 PRAGMA cipher_test_on = fail_encrypt;
871 PRAGMA cipher_test_on = fail_migrate;
873 PRAGMA cipher_test_off = fail_encrypt;
874 PRAGMA cipher_test_off = fail_migrate;
881 # it should raise an error
883 sqlite_orig db test.db
889 } {1 {An error occurred with PRAGMA key or rekey. PRAGMA key requires a key of one or more characters. PRAGMA rekey can only be run on an existing encrypted database. Use sqlcipher_export() and ATTACH to convert encrypted/plaintext databases.}}
891 file delete -force test.db
893 # configure URI filename support
894 # create a new encrypted database with the key via parameter
896 # open normally providing key via pragma verify
901 sqlite_orig db file:test.db?a=a&key=testkey&c=c
904 CREATE TABLE t1(a,b);
905 INSERT INTO t1 VALUES(1,2);
909 sqlite_orig db test.db
912 PRAGMA key = 'testkey';
913 SELECT count(*) FROM t1;
917 sqlite_orig db test.db
920 PRAGMA key = 'testkey';
921 SELECT count(*) FROM t1;
927 # verify wrong key fails
929 sqlite_orig db test.db
932 SELECT count(*) FROM t1;
934 } {1 {file is not a database}}
936 file delete -force test.db