# SQLite Cipher # codec.test developed by Stephen Lombardo (Zetetic LLC) # sjlombardo at zetetic dot net # http://zetetic.net # # Copyright (c) 2008, ZETETIC LLC # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the ZETETIC LLC nor the # names of its contributors may be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # This file implements regression tests for SQLite library. The # focus of this script is testing code cipher features. # # NOTE: tester.tcl has overridden the definition of sqlite3 to # automatically pass in a key value. Thus tests in this file # should explicitly close and open db with sqlite_orig in order # to bypass default key assignment. file delete -force test.db file delete -force test2.db file delete -force test3.db file delete -force test4.db set testdir [file dirname $argv0] source $testdir/tester.tcl # If the library is not compiled with has_codec support then # skip all tests in this file. if {![sqlite_orig -has-codec]} { finish_test return } # The database is initially empty. do_test codec-1.1 { sqlite_orig db test.db execsql { SELECT name FROM sqlite_master WHERE type='table'; } } {} db close # set an hex key create some basic data # create table and insert operations should work do_test codec-1.2 { sqlite_orig db test.db execsql { PRAGMA key = "x'98483C6EB40B6C31A448C22A66DED3B5E5E8D5119CAC8327B655C8B5C4836481'"; CREATE table t1(a,b); INSERT INTO t1 VALUES ('test1', 'test2'); } } {} db close # close database, open it again with the same # hex key. verify that the table is readable # and the data just inserted is visible do_test codec-1.3 { sqlite_orig db test.db execsql { PRAGMA key = "x'98483C6EB40B6C31A448C22A66DED3B5E5E8D5119CAC8327B655C8B5C4836481'"; SELECT name FROM sqlite_master WHERE type='table'; SELECT * from t1; } } {t1 test1 test2} db close file delete -force test.db # set an encryption key and create some basic data # create table and insert operations should work do_test codec-1.4 { sqlite_orig db test.db execsql { PRAGMA key = 'testkey'; CREATE table t1(a,b); INSERT INTO t1 VALUES ('test1', 'test2'); } } {} db close # close database, open it again with the same # key. verify that the table is readable # and the data just inserted is visible do_test codec-1.5 { sqlite_orig db test.db execsql { PRAGMA key = 'testkey'; SELECT name FROM sqlite_master WHERE type='table'; SELECT * from t1; } } {t1 test1 test2} db close # open the database and try to read from it without # providing a passphrase. verify that the # an error is returned from the library do_test codec-1.6 { sqlite_orig db test.db catchsql { SELECT name FROM sqlite_master WHERE type='table'; } } {1 {file is encrypted or is not a database}} db close # open the database and try to set an invalid # passphrase. verify that an error is returned # and that data couldn't be read do_test codec-1.7 { sqlite_orig db test.db catchsql { PRAGMA key = 'testkey2'; SELECT name FROM sqlite_master WHERE type='table'; } } {1 {file is encrypted or is not a database}} db close # test invalid hex key fails do_test codec-1.8 { sqlite_orig db test.db catchsql { PRAGMA key = "x'98483C6EB40B6C31A448C22A66DED3B5E5E8D5119CAC8327B655C8B5C4836480'"; SELECT name FROM sqlite_master WHERE type='table'; } } {1 {file is encrypted or is not a database}} db close # test a large number of inserts in a transaction to a memory database do_test codec-1.9 { sqlite_orig db :memory: execsql { PRAGMA key = 'testkey3'; BEGIN; CREATE TABLE t2(a,b); } for {set i 1} {$i<=25000} {incr i} { set r [expr {int(rand()*500000)}] execsql "INSERT INTO t2 VALUES($i,$r);" } execsql { COMMIT; SELECT count(*) FROM t2; DELETE FROM t2; SELECT count(*) FROM t2; } } {25000 0} db close # test a large number of inserts in a transaction for multiple pages do_test codec-1.10 { sqlite_orig db test.db execsql { PRAGMA key = 'testkey'; BEGIN; CREATE TABLE t2(a,b); } for {set i 1} {$i<=25000} {incr i} { set r [expr {int(rand()*500000)}] execsql "INSERT INTO t2 VALUES($i,$r);" } execsql { COMMIT; SELECT count(*) FROM t2; } } {25000} db close # test initial rekey do_test codec-1.11 { sqlite_orig db test.db execsql { PRAGMA key = 'testkey'; PRAGMA rekey = 'testkeynew'; } } {} db close # test that now the new key opens the database # now close database re-open with new key do_test codec-1.12 { sqlite_orig db test.db execsql { PRAGMA key = 'testkeynew'; SELECT count(*) FROM t2; } } {25000} db close # test rekey on an unecrypted database do_test codec-1.13 { sqlite_orig db2 test2.db execsql { BEGIN; CREATE TABLE t2(a,b); } db2 for {set i 1} {$i<=25000} {incr i} { set r [expr {int(rand()*500000)}] execsql "INSERT INTO t2 VALUES($i,$r);" db2 } execsql { COMMIT; PRAGMA rekey = 'testkey'; } db2 db2 close sqlite_orig db2 test2.db execsql { PRAGMA key = 'testkey'; SELECT count(*) FROM t2; } db2 } {25000} db2 close # attach an encrypted database do_test codec-1.14 { sqlite_orig db3 test3.db execsql { BEGIN; PRAGMA key = 'testkey'; CREATE TABLE t3(a,b); } db3 for {set i 1} {$i<=15000} {incr i} { set r [expr {int(rand()*500000)}] execsql "INSERT INTO t3 VALUES($i,$r);" db3 } execsql { COMMIT; } db3 sqlite_orig db2 test2.db execsql { PRAGMA key = 'testkey'; SELECT count(*) FROM t2; ATTACH 'test3.db' AS db3; SELECT count(*) FROM db3.t3; } db2 } {25000 15000} db3 close do_test codec-1.15 { execsql { BEGIN; } db2 for {set i 1} {$i<=10000} {incr i} { set r [expr {int(rand()*500000)}] execsql "INSERT INTO t2 VALUES($i,$r);" db2 execsql "INSERT INTO db3.t3 VALUES($i,$r);" db2 } execsql { COMMIT; SELECT count(*) FROM t2; SELECT count(*) FROM db3.t3; DETACH db3; } db2 } {35000 25000} db2 close # test locking across multiple handles do_test codec-1.16 { sqlite_orig db3 test3.db execsql { PRAGMA key = 'testkey'; BEGIN EXCLUSIVE; INSERT INTO t3 VALUES(1,2); } db3 sqlite_orig db3a test3.db catchsql { PRAGMA key = 'testkey'; SELECT count(*) FROM t3; } db3a } {1 {database is locked}} # test locks are released do_test codec-1.17 { execsql { COMMIT; } db3 catchsql { SELECT count(*) FROM t3; } db3a } {0 25001} db3 close db3a close # alter schema do_test codec-1.18 { sqlite_orig db3 test3.db execsql { PRAGMA key = 'testkey'; ALTER TABLE t3 ADD COLUMN c; INSERT INTO t3 VALUES (1,2,3); INSERT INTO t3 VALUES (1,2,4); CREATE TABLE t3a (a); INSERT INTO t3a VALUES ('teststring'); } db3 } {} db3 close do_test codec-1.19 { sqlite_orig db3 test3.db execsql { PRAGMA key = 'testkey'; SELECT count(*) FROM t3 WHERE a IS NOT NULL; SELECT count(*) FROM t3 WHERE c IS NOT NULL; SELECT * FROM t3a; } db3 } {25003 2 teststring} db3 close finish_test