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
198 PRAGMA key = 'testkey';
199 PRAGMA cipher_add_random = "x'deadbaad'";
200 CREATE TABLE t2(a,b);
201 INSERT INTO t2 VALUES ('test1', 'test2');
204 lappend rc [catchsql {
205 ATTACH 'test.db' AS db;
208 lappend rc [string equal [hexio_read test.db 0 16] [hexio_read test2.db 0 16]]
210 } {{1 {file is not a database}} 0}
212 file delete -force test.db
213 file delete -force test2.db
215 # attach an empty encrypted database
216 # without specifying key, verify the database has the same
217 # salt and as the original
218 setup test.db "'testkey'"
219 do_test attach-empty-database-with-default-key {
220 sqlite_orig db test.db
224 PRAGMA key='testkey';
225 INSERT INTO t1(a,b) values (1,2);
226 ATTACH DATABASE 'test2.db' AS test;
227 CREATE TABLE test.t1(a,b);
228 INSERT INTO test.t1 SELECT * FROM t1;
229 DETACH DATABASE test;
232 sqlite_orig db2 test2.db
234 lappend rc [execsql {
235 PRAGMA key='testkey';
236 SELECT count(*) FROM t1;
238 lappend rc [string equal [hexio_read test.db 0 16] [hexio_read test2.db 0 16]]
242 file delete -force test.db
243 file delete -force test2.db
245 # attach an empty encrypted database as the first op
246 # on a keyed database and verify different
247 # salts but same keys (because derivation of the key spec
248 # has not occured yet)
249 setup test.db "'testkey'"
250 do_test attach-empty-database-with-default-key-first-op {
251 sqlite_orig db test.db
255 PRAGMA key='testkey';
256 ATTACH DATABASE 'test2.db' AS test;
257 CREATE TABLE test.t1(a,b);
258 INSERT INTO test.t1 SELECT * FROM t1;
259 DETACH DATABASE test;
262 sqlite_orig db2 test2.db
264 lappend rc [execsql {
265 PRAGMA key='testkey';
266 SELECT count(*) FROM t1;
269 lappend rc [string equal [hexio_read test.db 0 16] [hexio_read test2.db 0 16]]
273 file delete -force test.db
274 file delete -force test2.db
276 # attach an empty encrypted database
277 # on a keyed database when PRAGMA cipher_store_pass = 1
278 # and verify different salts
279 setup test.db "'testkey'"
280 do_test attach-empty-database-with-cipher-store-pass {
281 sqlite_orig db test.db
285 PRAGMA key='testkey';
286 PRAGMA cipher_store_pass = 1;
287 INSERT INTO t1(a,b) VALUES (1,2);
288 ATTACH DATABASE 'test2.db' AS test;
289 CREATE TABLE test.t1(a,b);
290 INSERT INTO test.t1 SELECT * FROM t1;
291 DETACH DATABASE test;
294 sqlite_orig db2 test2.db
296 lappend rc [execsql {
297 PRAGMA key='testkey';
298 SELECT count(*) FROM t1;
300 lappend rc [string equal [hexio_read test.db 0 16] [hexio_read test2.db 0 16]]
304 file delete -force test.db
305 file delete -force test2.db
307 # attach an encrypted database
308 # without specifying key, verify it attaches
309 # correctly when PRAGMA cipher_store_pass = 1
311 do_test attach-database-with-default-key-using-cipher-store-pass {
312 sqlite_orig db1 test.db
314 PRAGMA key = 'testkey';
315 CREATE TABLE t1(a,b);
316 INSERT INTO t1(a,b) VALUES('foo', 'bar');
320 sqlite_orig db2 test2.db
322 PRAGMA key = 'testkey';
323 CREATE TABLE t2(a,b);
324 INSERT INTO t2 VALUES ('test1', 'test2');
328 sqlite_orig db1 test.db
330 PRAGMA key = 'testkey';
331 PRAGMA cipher_store_pass = 1;
332 ATTACH DATABASE 'test2.db' as db2;
333 SELECT sqlcipher_export('db2');
338 sqlite_orig db2 test2.db
340 PRAGMA key = 'testkey';
346 file delete -force test.db
347 file delete -force test2.db
349 # attach an encrypted database
350 # where both database have the same
351 # key explicitly and verify they have different
353 setup test.db "'testkey'"
354 do_test attach-database-with-same-key {
355 sqlite_orig db2 test2.db
360 PRAGMA key = 'testkey';
361 CREATE TABLE t2(a,b);
362 INSERT INTO t2 VALUES ('test1', 'test2');
365 lappend rc [execsql {
366 SELECT count(*) FROM t2;
367 ATTACH 'test.db' AS db KEY 'testkey';
368 SELECT count(*) FROM db.t1;
371 lappend rc [string equal [hexio_read test.db 0 16] [hexio_read test2.db 0 16]]
374 file delete -force test.db
375 file delete -force test2.db
377 # attach an encrypted database
378 # where databases have different keys
379 setup test.db "'testkey'"
380 do_test attach-database-with-different-keys {
381 sqlite_orig db2 test2.db
384 PRAGMA key = 'testkey2';
385 CREATE TABLE t2(a,b);
386 INSERT INTO t2 VALUES ('test1', 'test2');
390 ATTACH 'test.db' AS db KEY 'testkey';
391 SELECT count(*) FROM db.t1;
392 SELECT count(*) FROM t2;
397 file delete -force test.db
398 file delete -force test2.db
400 # test locking across multiple handles
401 setup test.db "'testkey'"
402 do_test locking-across-multiple-handles-start {
403 sqlite_orig db test.db
406 PRAGMA key = 'testkey';
408 INSERT INTO t1 VALUES(1,2);
411 sqlite_orig dba test.db
413 PRAGMA key = 'testkey';
414 SELECT count(*) FROM t1;
417 } {1 {database is locked}}
419 do_test locking-accross-multiple-handles-finish {
425 SELECT count(*) FROM t1;
430 file delete -force test.db
433 setup test.db "'testkey'"
434 do_test alter-schema {
435 sqlite_orig db test.db
437 PRAGMA key = 'testkey';
438 ALTER TABLE t1 ADD COLUMN c;
439 INSERT INTO t1 VALUES (1,2,3);
440 INSERT INTO t1 VALUES (1,2,4);
441 CREATE TABLE t1a (a);
442 INSERT INTO t1a VALUES ('teststring');
446 sqlite_orig db test.db
448 PRAGMA key = 'testkey';
449 SELECT count(*) FROM t1 WHERE a IS NOT NULL;
450 SELECT count(*) FROM t1 WHERE c IS NOT NULL;
454 } {ok 3 2 teststring}
456 file delete -force test.db
458 # test alterations of KDF iterations and ciphers
460 setup test.db "'testkey'"
461 do_test verify-errors-for-rekey-kdf-and-cipher-changes {
462 sqlite_orig db test.db
464 PRAGMA key = 'testkey';
465 PRAGMA rekey_kdf_iter = 1000;
466 PRAGMA rekey_cipher = 'aes-256-ecb';
468 } {ok {PRAGMA rekey_kdf_iter is no longer supported.} {PRAGMA rekey_cipher is no longer supported.}}
470 file delete -force test.db
473 setup test.db "'testkey'"
474 do_test verify-errors-for-cipher-change {
475 sqlite_orig db test.db
477 PRAGMA key = 'testkey';
478 PRAGMA cipher = 'aes-256-ecb';
480 } {ok {PRAGMA cipher is no longer supported.}}
482 file delete -force test.db
485 # 1. create a database with a custom page size,
486 # 2. create table and insert operations should work
487 # 3. close database, open it again with the same
489 # 4. verify that the table is readable
490 # and the data just inserted is visible
491 do_test custom-pagesize {
492 sqlite_orig db test.db
495 PRAGMA key = 'testkey';
496 PRAGMA cipher_page_size = 8192;
497 CREATE table t1(a,b);
501 for {set i 1} {$i<=1000} {incr i} {
502 set r [expr {int(rand()*500000)}]
503 execsql "INSERT INTO t1 VALUES($i,'value $r');"
511 sqlite_orig db test.db
514 PRAGMA key = 'testkey';
515 PRAGMA cipher_page_size = 8192;
516 SELECT count(*) FROM t1;
522 # open the database with the default page size
523 ## and verfiy that it is not readable
524 do_test custom-pagesize-must-match {
525 sqlite_orig db test.db
527 PRAGMA key = 'testkey';
528 SELECT name FROM sqlite_schema WHERE type='table';
530 } {1 {file is not a database}}
532 file delete -force test.db
535 # 1. create a database with WAL journal mode
536 # 2. create table and insert operations should work
537 # 3. close database, open it again
538 # 4. verify that the table is present, readable, and that
539 # the journal mode is WAL
540 do_test journal-mode-wal {
541 sqlite_orig db test.db
544 PRAGMA key = 'testkey';
545 PRAGMA journal_mode = WAL;
546 CREATE table t1(a,b);
550 for {set i 1} {$i<=1000} {incr i} {
551 set r [expr {int(rand()*500000)}]
552 execsql "INSERT INTO t1 VALUES($i,'value $r');"
560 sqlite_orig db test.db
563 PRAGMA key = 'testkey';
564 SELECT count(*) FROM t1;
570 file delete -force test.db
572 setup test.db "'testkey'"
573 do_test multiple-key-calls-safe-1 {
574 sqlite_orig db test.db
576 PRAGMA key = 'testkey';
577 PRAGMA cache_size = 0;
578 SELECT name FROM sqlite_schema WHERE type='table';
582 do_test multiple-key-calls-safe-2 {
584 PRAGMA key = 'wrong key';
585 SELECT name FROM sqlite_schema WHERE type='table';
587 } {1 {file is not a database}}
589 do_test multiple-key-calls-safe-3 {
591 PRAGMA key = 'testkey';
592 SELECT name FROM sqlite_schema WHERE type='table';
597 file delete -force test.db
599 # 1. create a database with a custom hmac kdf iteration count,
600 # 2. create table and insert operations should work
601 # 3. close database, open it again with the same
602 # key and hmac kdf iteration count
603 # 4. verify that the table is readable
604 # and the data just inserted is visible
605 do_test custom-hmac-kdf-iter {
606 sqlite_orig db test.db
609 PRAGMA key = 'testkey';
610 PRAGMA kdf_iter = 10;
611 CREATE table t1(a,b);
615 for {set i 1} {$i<=1000} {incr i} {
616 set r [expr {int(rand()*500000)}]
617 execsql "INSERT INTO t1 VALUES($i,'value $r');"
625 sqlite_orig db test.db
628 PRAGMA key = 'testkey';
629 PRAGMA kdf_iter = 10;
630 SELECT count(*) FROM t1;
636 # open the database with the default hmac
637 # kdf iteration count
638 # to verify that it is not readable
639 do_test custom-hmac-kdf-iter-must-match {
640 sqlite_orig db test.db
642 PRAGMA key = 'testkey';
643 SELECT name FROM sqlite_schema WHERE type='table';
645 } {1 {file is not a database}}
647 file delete -force test.db
649 # open the database and turn on auto_vacuum
650 # then insert a bunch of data, delete it
651 # and verify that the file has become smaller
652 # but can still be opened with the proper
654 do_test auto-vacuum {
655 sqlite_orig db test.db
659 PRAGMA key = 'testkey';
660 PRAGMA auto_vacuum=FULL;
661 CREATE table t1(a,b);
665 for {set i 1} {$i<=10000} {incr i} {
666 set r [expr {int(rand()*500000)}]
667 execsql "INSERT INTO t1 VALUES($i,'value $r');"
670 lappend rc [execsql {
672 SELECT count(*) FROM t1;
675 # grab current size of file
676 set sz [file size test.db]
678 # delete some records, and verify
679 # autovacuum removes them
681 DELETE FROM t1 WHERE rowid > 5000;
686 # grab new file size, post
688 set sz2 [file size test.db]
690 # verify that the new size is
691 # smaller than the old size
692 if {$sz > $sz2} { lappend rc true }
694 sqlite_orig db test.db
696 lappend rc [execsql {
697 PRAGMA key = 'testkey';
698 SELECT count(*) FROM t1;
701 } {10000 true {ok 5000}}
703 file delete -force test.db
705 # test kdf_iter and other pragmas
706 # before a key is set. Verify that they
708 do_test cipher-options-before-keys {
709 sqlite_orig db test.db
712 PRAGMA kdf_iter = 1000;
713 PRAGMA cipher_page_size = 8192;
714 PRAGMA cipher_use_hmac = OFF;
715 PRAGMA key = 'testkey';
716 CREATE table t1(a,b);
717 INSERT INTO t1 VALUES(1,2);
721 sqlite_orig db test.db
724 PRAGMA key = 'testkey';
725 SELECT count(*) FROM t1;
730 file delete -force test.db
732 # verify memory security behavior
733 # initially should report OFF
734 # then enable, check that it is ON
735 # try to turn if off, but verify that it
737 do_test verify-memory-security {
738 sqlite_orig db test.db
740 PRAGMA cipher_memory_security;
741 PRAGMA cipher_memory_security = ON;
742 PRAGMA cipher_memory_security;
743 PRAGMA cipher_memory_security = OFF;
744 PRAGMA cipher_memory_security;
748 file delete -force test.db
750 # create two new database files, write to each
751 # and verify that they have different (i.e. random)
753 do_test test-random-salt {
754 sqlite_orig db test.db
755 sqlite_orig db2 test2.db
758 CREATE TABLE t1(a,b);
759 INSERT INTO t1(a,b) VALUES (1,2);
763 CREATE TABLE t1(a,b);
764 INSERT INTO t1(a,b) VALUES (1,2);
768 string equal [hexio_read test.db 0 16] [hexio_read test2.db 0 16]
770 file delete -force test.db
771 file delete -force test2.db
773 # test scenario where multiple handles are opened
774 # to a file that does not exist, where both handles
776 do_test multiple-handles-same-key-and-salt {
777 sqlite_orig db test.db
778 sqlite_orig dba test.db
781 PRAGMA key = 'testkey';
784 PRAGMA key = 'testkey';
788 CREATE TABLE t1(a,b);
789 INSERT INTO t1 VALUES(1,2);
793 SELECT count(*) FROM t1;
796 SELECT count(*) FROM t1;
802 file delete -force test.db
804 do_test test_flags_fail_encrypt {
805 sqlite_orig db :memory:
808 PRAGMA cipher_test_on = fail_encrypt;
810 PRAGMA cipher_test_off = fail_encrypt;
816 do_test test_flags_fail_decrypt {
817 sqlite_orig db :memory:
820 PRAGMA cipher_test_on = fail_decrypt;
822 PRAGMA cipher_test_off = fail_decrypt;
828 do_test test_flags_fail_migrate {
829 sqlite_orig db :memory:
832 PRAGMA cipher_test_on = fail_migrate;
834 PRAGMA cipher_test_off = fail_migrate;
840 do_test test_flags_combo {
841 sqlite_orig db :memory:
844 PRAGMA cipher_test_on = fail_encrypt;
845 PRAGMA cipher_test_on = fail_migrate;
847 PRAGMA cipher_test_off = fail_encrypt;
848 PRAGMA cipher_test_off = fail_migrate;
854 # configure URI filename support
855 # create a new encrypted database with the key via parameter
857 # open normally providing key via pragma verify
862 sqlite_orig db file:test.db?a=a&key=testkey&c=c
865 CREATE TABLE t1(a,b);
866 INSERT INTO t1 VALUES(1,2);
870 sqlite_orig db test.db
873 PRAGMA key = 'testkey';
874 SELECT count(*) FROM t1;
878 sqlite_orig db test.db
881 PRAGMA key = 'testkey';
882 SELECT count(*) FROM t1;
888 # verify wrong key fails
890 sqlite_orig db test.db
893 SELECT count(*) FROM t1;
895 } {1 {file is not a database}}
897 file delete -force test.db