mirror of
https://github.com/status-im/sqlcipher.git
synced 2025-02-23 01:08:09 +00:00
PRAGMA cipher_store_pass allows the passphrase to remain in memory which will allow an ATTACH statement to succeed without providing the key value during ATTACH when both databases use the same passphrase, but have different salt values. Previously, in order to ATTACH with this scneario, calling ATTACH required providing the key value inline.
2261 lines
52 KiB
Plaintext
2261 lines
52 KiB
Plaintext
# SQLCipher
|
|
# codec.test developed by Stephen Lombardo (Zetetic LLC)
|
|
# sjlombardo at zetetic dot net
|
|
# http://zetetic.net
|
|
#
|
|
# Copyright (c) 2009, ZETETIC LLC
|
|
# 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
|
|
set old_pending_byte [sqlite3_test_control_pending_byte 0x40000000]
|
|
|
|
# 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
|
|
}
|
|
|
|
proc setup {file key} {
|
|
sqlite_orig db $file
|
|
execsql "PRAGMA key=$key;"
|
|
execsql {
|
|
CREATE table t1(a,b);
|
|
INSERT INTO t1 VALUES ('test1', 'test2');
|
|
} db
|
|
db close
|
|
}
|
|
|
|
proc get_cipher_provider {} {
|
|
sqlite_orig db test.db
|
|
return [execsql {
|
|
PRAGMA key = 'test';
|
|
PRAGMA cipher_provider;
|
|
}];
|
|
}
|
|
|
|
proc if_built_with_openssl {name cmd expected} {
|
|
if {[get_cipher_provider] == "openssl"} {
|
|
do_test $name $cmd $expected
|
|
}
|
|
}
|
|
|
|
proc if_built_with_libtomcrypt {name cmd expected} {
|
|
if {[get_cipher_provider] == "libtomcrypt"} {
|
|
do_test $name $cmd $expected
|
|
}
|
|
}
|
|
|
|
proc if_built_with_commoncrypto {name cmd expected} {
|
|
if {[get_cipher_provider] == "commoncrypto"} {
|
|
do_test $name $cmd $expected
|
|
}
|
|
}
|
|
|
|
proc cmpFilesChunked {file1 file2 {chunksize 16384}} {
|
|
set f1 [open $file1]; fconfigure $f1 -translation binary
|
|
set f2 [open $file2]; fconfigure $f2 -translation binary
|
|
while {1} {
|
|
set d1 [read $f1 $chunksize]
|
|
set d2 [read $f2 $chunksize]
|
|
set diff [string compare $d1 $d2]
|
|
if {$diff != 0 || [eof $f1] || [eof $f2]} {
|
|
close $f1; close $f2
|
|
return $diff
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
# The database is initially empty.
|
|
# set an hex key create some basic data
|
|
# create table and insert operations should work
|
|
# close database, open it again with the same
|
|
# hex key. verify that the table is readable
|
|
# and the data just inserted is visible
|
|
setup test.db "\"x'98483C6EB40B6C31A448C22A66DED3B5E5E8D5119CAC8327B655C8B5C4836481'\""
|
|
do_test will-open-with-correct-raw-key {
|
|
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 (non-hex) and create some basic data
|
|
# create table and insert operations should work
|
|
# close database, open it again with the same
|
|
# key. verify that the table is readable
|
|
# and the data just inserted is visible
|
|
setup test.db "'testkey'"
|
|
do_test will-open-with-correct-derived-key {
|
|
|
|
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
|
|
file delete -force test.db
|
|
|
|
# open the database and try to read from it without
|
|
# providing a passphrase. verify that the
|
|
# an error is returned from the library
|
|
setup test.db "'testkey'"
|
|
do_test wont-open-without-key {
|
|
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
|
|
file delete -force test.db
|
|
|
|
# open the database and try to set an invalid
|
|
# passphrase. verify that an error is returned
|
|
# and that data couldn't be read
|
|
setup test.db "'testkey'"
|
|
do_test wont-open-with-invalid-derived-key {
|
|
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
|
|
file delete -force test.db
|
|
|
|
# open the database and try to set an invalid
|
|
# hex key. verify that an error is returned
|
|
# and that data couldn't be read
|
|
setup test.db "'testkey'"
|
|
do_test wont-open-with-invalid-raw-key {
|
|
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
|
|
file delete -force test.db
|
|
|
|
# test a large number of inserts in a transaction to a memory database
|
|
do_test memory-database {
|
|
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 multi-page-database {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
CREATE TABLE t2(a,b);
|
|
BEGIN;
|
|
}
|
|
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
|
|
file delete -force test.db
|
|
|
|
# test a rekey operation as the first op on a database
|
|
# then test that now the new key opens the database
|
|
# now close database re-open with new key
|
|
setup test.db "'testkey'"
|
|
do_test rekey-as-first-operation {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA rekey = 'testkeynew';
|
|
}
|
|
db close
|
|
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkeynew';
|
|
SELECT name FROM sqlite_master WHERE type='table';
|
|
}
|
|
} {t1}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# create a new database, insert some data
|
|
# then rekey it with the same password
|
|
do_test rekey-same-passkey {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'test123';
|
|
CREATE TABLE t1(a,b);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<=1000} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t1 VALUES($i,'value $r');"
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
SELECT count(*) FROM t1;
|
|
PRAGMA rekey = 'test123';
|
|
SELECT count(*) FROM t1;
|
|
}
|
|
} {1000 1000}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# create a new database, insert some data
|
|
# then rekey it. Make sure it is immediately
|
|
# readable. Then close it and make sure it can be
|
|
# read back
|
|
do_test rekey-and-query-1 {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'test123';
|
|
CREATE TABLE t1(a,b);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<=1000} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t1 VALUES($i,'value $r');"
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
SELECT count(*) FROM t1;
|
|
PRAGMA rekey = 'test321';
|
|
SELECT count(*) FROM t1;
|
|
}
|
|
} {1000 1000}
|
|
|
|
db close
|
|
|
|
do_test rekey-and-query-2 {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'test321';
|
|
SELECT count(*) FROM t1;
|
|
}
|
|
} {1000}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# create a new database, insert some data
|
|
# delete about 50% of the data
|
|
# write some new data
|
|
# delete another 50%
|
|
# then rekey it. Make sure it is immediately
|
|
# readable. Then close it and make sure it can be
|
|
# read back. This test will ensure that Secure Delete
|
|
# is enabled and all pages are being written and are not
|
|
# being optimized out by sqlite3PagerDontWrite
|
|
do_test rekey-delete-and-query-1 {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'test123';
|
|
CREATE TABLE t1(a,b);
|
|
CREATE INDEX ta_a ON t1(a);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<1000} {incr i} {
|
|
set r [expr {int(rand()*32767)}]
|
|
set r1 [expr {int(rand()*32767)}]
|
|
execsql "INSERT INTO t1 VALUES($r,$r1);"
|
|
}
|
|
set r [expr {int(rand()*32767)}]
|
|
set r1 [expr {int(rand()*32767)}]
|
|
execsql "UPDATE t1 SET b = $r WHERE a < $r1;"
|
|
|
|
set r [expr {int(rand()*32767)}]
|
|
|
|
execsql "DELETE FROM t1 WHERE a < $r;"
|
|
|
|
execsql {
|
|
COMMIT;
|
|
SELECT (count(*) > 0) FROM t1;
|
|
}
|
|
} {1}
|
|
db close
|
|
|
|
do_test rekey-delete-and-query-2 {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'test123';
|
|
PRAGMA rekey = 'test321';
|
|
SELECT count(*) > 1 FROM t1;
|
|
PRAGMA integrity_check;
|
|
}
|
|
} {1 ok}
|
|
db close
|
|
|
|
do_test rekey-delete-and-query-3 {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'test321';
|
|
SELECT count(*) > 1 FROM t1;
|
|
}
|
|
} {1}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
|
|
# same as previous test, but use WAL
|
|
do_test rekey-delete-and-query-wal-1 {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'test123';
|
|
PRAGMA journal_mode = WAL;
|
|
CREATE TABLE t1(a,b);
|
|
CREATE INDEX ta_a ON t1(a);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<1000} {incr i} {
|
|
set r [expr {int(rand()*32767)}]
|
|
set r1 [expr {int(rand()*32767)}]
|
|
execsql "INSERT INTO t1 VALUES($r,$r1);"
|
|
}
|
|
set r [expr {int(rand()*32767)}]
|
|
set r1 [expr {int(rand()*32767)}]
|
|
execsql "UPDATE t1 SET b = $r WHERE a < $r1;"
|
|
|
|
set r [expr {int(rand()*32767)}]
|
|
|
|
execsql "DELETE FROM t1 WHERE a < $r;"
|
|
|
|
execsql {
|
|
COMMIT;
|
|
SELECT (count(*) > 0) FROM t1;
|
|
}
|
|
} {1}
|
|
db close
|
|
|
|
do_test rekey-delete-and-query-wal-2 {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'test123';
|
|
PRAGMA journal_mode = WAL;
|
|
PRAGMA rekey = 'test321';
|
|
SELECT count(*) > 1 FROM t1;
|
|
PRAGMA integrity_check;
|
|
}
|
|
} {wal 1 ok}
|
|
db close
|
|
|
|
do_test rekey-delete-and-query-wal-3 {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'test321';
|
|
PRAGMA journal_mode = WAL;
|
|
SELECT count(*) > 1 FROM t1;
|
|
}
|
|
} {wal 1}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# attach an encrypted database
|
|
# without specifying key, verify it fails
|
|
# even if the source passwords are the same
|
|
# because the kdf salts are different
|
|
setup test.db "'testkey'"
|
|
do_test attach-database-with-default-key {
|
|
sqlite_orig db2 test2.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA cipher_add_random = "x'deadbaad'";
|
|
CREATE TABLE t2(a,b);
|
|
INSERT INTO t2 VALUES ('test1', 'test2');
|
|
} db2
|
|
|
|
catchsql {
|
|
ATTACH 'test.db' AS db;
|
|
} db2
|
|
|
|
} {1 {file is encrypted or is not a database}}
|
|
db2 close
|
|
file delete -force test.db
|
|
file delete -force test2.db
|
|
|
|
# attach an encrypted database
|
|
# without specifying key, verify it attaches
|
|
# correctly when PRAGMA cipher_store_pass = 1
|
|
# is set.
|
|
do_test attach-database-with-default-key-using-cipher-store-pass {
|
|
|
|
sqlite_orig db1 test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
CREATE TABLE t1(a,b);
|
|
INSERT INTO t1(a,b) VALUES('foo', 'bar');
|
|
} db1
|
|
db1 close
|
|
|
|
sqlite_orig db2 test2.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
CREATE TABLE t2(a,b);
|
|
INSERT INTO t2 VALUES ('test1', 'test2');
|
|
} db2
|
|
db2 close
|
|
|
|
sqlite_orig db1 test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA cipher_store_pass = 1;
|
|
ATTACH DATABASE 'test2.db' as db2;
|
|
SELECT sqlcipher_export('db2');
|
|
DETACH DATABASE db2;
|
|
} db1
|
|
db1 close
|
|
|
|
sqlite_orig db2 test2.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT * FROM t1;
|
|
} db2
|
|
|
|
} {foo bar}
|
|
db2 close
|
|
file delete -force test.db
|
|
file delete -force test2.db
|
|
|
|
# attach an encrypted database
|
|
# where both database have the same
|
|
# key explicitly
|
|
setup test.db "'testkey'"
|
|
do_test attach-database-with-same-key {
|
|
sqlite_orig db2 test2.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
CREATE TABLE t2(a,b);
|
|
INSERT INTO t2 VALUES ('test1', 'test2');
|
|
} db2
|
|
|
|
execsql {
|
|
SELECT count(*) FROM t2;
|
|
ATTACH 'test.db' AS db KEY 'testkey';
|
|
SELECT count(*) FROM db.t1;
|
|
} db2
|
|
|
|
} {1 1}
|
|
db2 close
|
|
file delete -force test.db
|
|
file delete -force test2.db
|
|
|
|
# attach an encrypted database
|
|
# where databases have different keys
|
|
setup test.db "'testkey'"
|
|
do_test attach-database-with-different-keys {
|
|
sqlite_orig db2 test2.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey2';
|
|
CREATE TABLE t2(a,b);
|
|
INSERT INTO t2 VALUES ('test1', 'test2');
|
|
} db2
|
|
|
|
execsql {
|
|
ATTACH 'test.db' AS db KEY 'testkey';
|
|
SELECT count(*) FROM db.t1;
|
|
SELECT count(*) FROM t2;
|
|
} db2
|
|
|
|
} {1 1}
|
|
db2 close
|
|
file delete -force test.db
|
|
file delete -force test2.db
|
|
|
|
# test locking across multiple handles
|
|
setup test.db "'testkey'"
|
|
do_test locking-across-multiple-handles-start {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
BEGIN EXCLUSIVE;
|
|
INSERT INTO t1 VALUES(1,2);
|
|
}
|
|
|
|
sqlite_orig dba test.db
|
|
catchsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT count(*) FROM t1;
|
|
} dba
|
|
|
|
} {1 {database is locked}}
|
|
|
|
do_test locking-accross-multiple-handles-finish {
|
|
execsql {
|
|
COMMIT;
|
|
}
|
|
|
|
execsql {
|
|
SELECT count(*) FROM t1;
|
|
} dba
|
|
} {2}
|
|
db close
|
|
dba close
|
|
file delete -force test.db
|
|
|
|
# alter schema
|
|
setup test.db "'testkey'"
|
|
do_test alter-schema {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
ALTER TABLE t1 ADD COLUMN c;
|
|
INSERT INTO t1 VALUES (1,2,3);
|
|
INSERT INTO t1 VALUES (1,2,4);
|
|
CREATE TABLE t1a (a);
|
|
INSERT INTO t1a VALUES ('teststring');
|
|
}
|
|
db close
|
|
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT count(*) FROM t1 WHERE a IS NOT NULL;
|
|
SELECT count(*) FROM t1 WHERE c IS NOT NULL;
|
|
SELECT * FROM t1a;
|
|
}
|
|
|
|
} {3 2 teststring}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# test alterations of KDF iterations and ciphers
|
|
# rekey then add
|
|
setup test.db "'testkey'"
|
|
do_test non-standard-kdf-and-ciphers {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA rekey_kdf_iter = 1000;
|
|
PRAGMA rekey_cipher = 'aes-256-cfb';
|
|
PRAGMA rekey = 'testkey2';
|
|
INSERT INTO t1 VALUES (1,2);
|
|
}
|
|
db close
|
|
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey2';
|
|
PRAGMA kdf_iter = 1000;
|
|
PRAGMA cipher = 'aes-256-cfb';
|
|
SELECT count(*) FROM t1;
|
|
}
|
|
|
|
} {2}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# test alterations of CIPHER from CBC Mode requiring
|
|
# IV to ECB mode that does not
|
|
setup test.db "'testkey'"
|
|
do_test rekey-from-cbc-to-ecb-no-iv {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<=1000} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t1 VALUES($i,$r);"
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
PRAGMA rekey_kdf_iter = 1000;
|
|
PRAGMA rekey_cipher = 'aes-128-ecb';
|
|
PRAGMA rekey = 'testkey';
|
|
}
|
|
db close
|
|
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA kdf_iter = 1000;
|
|
PRAGMA cipher = 'aes-128-ecb';
|
|
SELECT count(*) FROM t1;
|
|
}
|
|
|
|
} {1001}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# test alterations of CIPHER from ECB Mode (no IV) to CBC Mode
|
|
do_test rekey-from-ecb-to-cbc-with-iv {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA cipher = 'aes-256-ecb';
|
|
CREATE table t1(a,b);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<=1000} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t1 VALUES($i,$r);"
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
PRAGMA rekey_cipher = 'aes-256-cbc';
|
|
PRAGMA rekey = 'testkey';
|
|
}
|
|
db close
|
|
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT count(*) FROM t1;
|
|
}
|
|
|
|
} {1000}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# create an unencrypted database, attach a new encrypted volume
|
|
# copy data between, verify the encypted database is good afterwards
|
|
do_test unencrypted-attach {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
CREATE TABLE t1(a,b);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<=1000} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t1 VALUES($i,$r);"
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
ATTACH DATABASE 'test2.db' AS db2 KEY 'testkey';
|
|
CREATE TABLE db2.t1(a,b);
|
|
INSERT INTO db2.t1 SELECT * FROM t1;
|
|
DETACH DATABASE db2;
|
|
}
|
|
|
|
sqlite_orig db2 test2.db
|
|
execsql {
|
|
PRAGMA key='testkey';
|
|
SELECT count(*) FROM t1;
|
|
} db2
|
|
} {1000}
|
|
db2 close
|
|
file delete -force test.db
|
|
file delete -force test2.db
|
|
|
|
# create an unencrypted database, attach a new encrypted volume
|
|
# using a raw key copy data between, verify the encypted
|
|
# database is good afterwards
|
|
do_test unencrypted-attach-raw-key {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
CREATE TABLE t1(a,b);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<=1000} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t1 VALUES($i,$r);"
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
ATTACH DATABASE 'test2.db' AS db2 KEY "x'10483C6EB40B6C31A448C22A66DED3B5E5E8D5119CAC8327B655C8B5C4836481'";
|
|
CREATE TABLE db2.t1(a,b);
|
|
INSERT INTO db2.t1 SELECT * FROM t1;
|
|
DETACH DATABASE db2;
|
|
}
|
|
|
|
sqlite_orig db2 test2.db
|
|
execsql {
|
|
PRAGMA key="x'10483C6EB40B6C31A448C22A66DED3B5E5E8D5119CAC8327B655C8B5C4836481'";
|
|
SELECT count(*) FROM t1;
|
|
} db2
|
|
} {1000}
|
|
db2 close
|
|
file delete -force test.db
|
|
file delete -force test2.db
|
|
|
|
# create an encrypted database, attach an default-key encrypted volume
|
|
# copy data between, verify the second database
|
|
do_test encrypted-attach-default-key {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key='testkey';
|
|
CREATE TABLE t1(a,b);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<=1000} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t1 VALUES($i,$r);"
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
ATTACH DATABASE 'test2.db' AS test;
|
|
CREATE TABLE test.t1(a,b);
|
|
INSERT INTO test.t1 SELECT * FROM t1;
|
|
DETACH DATABASE test;
|
|
}
|
|
|
|
sqlite_orig db2 test2.db
|
|
|
|
execsql {
|
|
PRAGMA key='testkey';
|
|
SELECT count(*) FROM t1;
|
|
} db2
|
|
} {1000}
|
|
db close
|
|
db2 close
|
|
file delete -force test.db
|
|
file delete -force test2.db
|
|
|
|
# create an encrypted database, attach an unencrypted volume
|
|
# copy data between, verify the unencypted database is good afterwards
|
|
do_test encrypted-attach-unencrypted {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
CREATE TABLE t1(a,b);
|
|
}
|
|
|
|
sqlite_orig db2 test2.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
CREATE TABLE t1(a,b);
|
|
BEGIN;
|
|
} db2
|
|
|
|
for {set i 1} {$i<=1000} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t1 VALUES($i,$r);" db2
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
ATTACH DATABASE 'test.db' AS test KEY '';
|
|
INSERT INTO test.t1 SELECT * FROM t1;
|
|
DETACH DATABASE test;
|
|
} db2
|
|
|
|
execsql {
|
|
SELECT count(*) FROM t1;
|
|
}
|
|
} {1000}
|
|
db close
|
|
db2 close
|
|
file delete -force test.db
|
|
file delete -force test2.db
|
|
|
|
# create an unencrypted database, attach an unencrypted volume
|
|
# copy data between, verify the unencypted database is good afterwards
|
|
do_test unencrypted-attach-unencrypted {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
CREATE TABLE t1(a,b);
|
|
}
|
|
|
|
sqlite_orig db2 test2.db
|
|
execsql {
|
|
CREATE TABLE t1(a,b);
|
|
BEGIN;
|
|
} db2
|
|
|
|
for {set i 1} {$i<=1000} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t1 VALUES($i,$r);" db2
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
ATTACH DATABASE 'test.db' AS test;
|
|
INSERT INTO test.t1 SELECT * FROM t1;
|
|
DETACH DATABASE test;
|
|
} db2
|
|
|
|
execsql {
|
|
SELECT count(*) FROM t1;
|
|
}
|
|
} {1000}
|
|
db close
|
|
db2 close
|
|
file delete -force test.db
|
|
file delete -force test2.db
|
|
|
|
# 1. create a database with a custom page size,
|
|
# 2. create table and insert operations should work
|
|
# 3. close database, open it again with the same
|
|
# key and page size
|
|
# 4. verify that the table is readable
|
|
# and the data just inserted is visible
|
|
do_test custom-pagesize {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA cipher_page_size = 4096;
|
|
CREATE table t1(a,b);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<=1000} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t1 VALUES($i,'value $r');"
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
}
|
|
|
|
db close
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA cipher_page_size = 4096;
|
|
SELECT count(*) FROM t1;
|
|
}
|
|
|
|
} {1000}
|
|
db close
|
|
|
|
# open the database with the default page size
|
|
## and verfiy that it is not readable
|
|
do_test custom-pagesize-must-match {
|
|
sqlite_orig db test.db
|
|
catchsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT name FROM sqlite_master WHERE type='table';
|
|
}
|
|
} {1 {file is encrypted or is not a database}}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# 1. create a database and insert a bunch of data, close the database
|
|
# 2. seek to the middle of a database page and write some junk
|
|
# 3. Open the database and verify that the database is no longer readable
|
|
do_test hmac-tamper-resistence {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
CREATE table t1(a,b);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<=1000} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t1 VALUES($i,'value $r');"
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
}
|
|
|
|
db close
|
|
|
|
# write some junk into the hmac segment, leaving
|
|
# the page data valid but with an invalid signature
|
|
hexio_write test.db 1000 0000
|
|
|
|
sqlite_orig db test.db
|
|
|
|
catchsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT count(*) FROM t1;
|
|
}
|
|
|
|
} {1 {file is encrypted or is not a database}}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# 1. create a database and insert a bunch of data, close the database
|
|
# 2. seek to the middle of a database page and write some junk
|
|
# 3. Open the database and verify that the database is still readable
|
|
do_test nohmac-not-tamper-resistent {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA cipher_use_hmac = OFF;
|
|
PRAGMA cipher_page_size = 1024;
|
|
CREATE table t1(a,b);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<=1000} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t1 VALUES($i,'value $r');"
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
}
|
|
|
|
db close
|
|
|
|
# write some junk into the middle of the page
|
|
hexio_write test.db 2560 00
|
|
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA cipher_use_hmac = OFF;
|
|
PRAGMA cipher_page_size = 1024;
|
|
SELECT count(*) FROM t1;
|
|
}
|
|
|
|
} {1000}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# open a 1.1.8 database using the new code, HMAC disabled
|
|
do_test open-1.1.8-database {
|
|
file copy -force sqlcipher-1.1.8-testkey.db test.db
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA cipher_use_hmac = off;
|
|
PRAGMA kdf_iter = 4000;
|
|
SELECT count(*) FROM t1;
|
|
SELECT distinct * FROM t1;
|
|
}
|
|
} {75709 1 1 one one 1 2 one two 1 2}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# open a 1.1.8 database without hmac, then copy the data
|
|
do_test attach-and-copy-1.1.8 {
|
|
sqlite_orig db sqlcipher-1.1.8-testkey.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA cipher_use_hmac = OFF;
|
|
PRAGMA kdf_iter = 4000;
|
|
ATTACH DATABASE 'test.db' AS db2 KEY 'testkey-hmac';
|
|
CREATE TABLE db2.t1(a,b);
|
|
INSERT INTO db2.t1 SELECT * FROM main.t1;
|
|
DETACH DATABASE db2;
|
|
}
|
|
db close
|
|
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey-hmac';
|
|
SELECT count(*) FROM t1;
|
|
SELECT distinct * FROM t1;
|
|
}
|
|
} {75709 1 1 one one 1 2 one two 1 2}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# open a standard database, then attach a new
|
|
# database with completely different options.
|
|
# copy data between them, and verify that the
|
|
# new database can be opened with the proper data
|
|
do_test attached-database-pragmas {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
CREATE TABLE t1(a,b);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<=1000} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t1 VALUES($i,'value $r');"
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
ATTACH DATABASE 'test2.db' AS db2 KEY 'testkey2';
|
|
PRAGMA db2.cipher_page_size = 4096;
|
|
PRAGMA db2.cipher = 'aes-128-cbc';
|
|
PRAGMA db2.kdf_iter = 1000;
|
|
PRAGMA db2.cipher_use_hmac = OFF;
|
|
CREATE TABLE db2.t1(a,b);
|
|
INSERT INTO db2.t1 SELECT * FROM main.t1;
|
|
DETACH DATABASE db2;
|
|
}
|
|
db close
|
|
|
|
sqlite_orig db test2.db
|
|
execsql {
|
|
PRAGMA key = 'testkey2';
|
|
PRAGMA cipher_page_size = 4096;
|
|
PRAGMA cipher = 'aes-128-cbc';
|
|
PRAGMA kdf_iter = 1000;
|
|
PRAGMA cipher_use_hmac = OFF;
|
|
SELECT count(*) FROM t1;
|
|
}
|
|
} {1000}
|
|
db close
|
|
file delete -force test.db
|
|
file delete -force test2.db
|
|
|
|
# use the sqlcipher_export function
|
|
# on a non-existent database. Verify
|
|
# the error gets through.
|
|
do_test export-error {
|
|
sqlite_orig db test.db
|
|
|
|
catchsql {
|
|
PRAGMA key = 'testkey';
|
|
CREATE TABLE t1(a,b);
|
|
SELECT sqlcipher_export('nodb');
|
|
}
|
|
} {1 {unknown database nodb}}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# use the sqlcipher_export function
|
|
# to copy a complicated database.
|
|
# tests autoincrement fields,
|
|
# indexes, views, and triggers,
|
|
# tables and virtual tables
|
|
do_test export-database {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b, c);
|
|
CREATE UNIQUE INDEX b_idx ON t1(b);
|
|
CREATE INDEX c_idx ON t1(c);
|
|
|
|
CREATE TABLE t2(b,c);
|
|
CREATE TRIGGER t2_after_insert AFTER INSERT ON t2
|
|
BEGIN
|
|
INSERT INTO t1(b,c) VALUES (new.b, new.c);
|
|
END;
|
|
|
|
CREATE VIEW v1 AS
|
|
SELECT c FROM t1;
|
|
|
|
CREATE VIRTUAL TABLE fts USING fts3(a,b);
|
|
|
|
BEGIN;
|
|
-- start with one known value
|
|
INSERT INTO t2 VALUES(1000000,'value 1000000');
|
|
}
|
|
|
|
for {set i 1} {$i<=999} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t2 VALUES($i,'value $r');"
|
|
}
|
|
|
|
execsql {
|
|
INSERT INTO fts SELECT b,c FROM t1;
|
|
COMMIT;
|
|
|
|
ATTACH DATABASE 'test2.db' AS db2 KEY 'testkey2';
|
|
PRAGMA db2.cipher_page_size = 4096;
|
|
|
|
SELECT sqlcipher_export('db2');
|
|
|
|
DETACH DATABASE db2;
|
|
}
|
|
db close
|
|
|
|
sqlite_orig db test2.db
|
|
execsql {
|
|
PRAGMA key = 'testkey2';
|
|
PRAGMA cipher_page_size = 4096;
|
|
SELECT count(*) FROM t1;
|
|
SELECT count(*) FROM v1;
|
|
SELECT count(*) FROM sqlite_sequence;
|
|
SELECT seq FROM sqlite_sequence WHERE name = 't1';
|
|
INSERT INTO t2 VALUES(10001, 'value 938383');
|
|
SELECT count(*) FROM t1; -- verify the trigger worked
|
|
SELECT seq FROM sqlite_sequence WHERE name = 't1'; -- verify that autoincrement worked
|
|
SELECT a FROM fts WHERE b MATCH '1000000';
|
|
}
|
|
} {1000 1000 1 1000 1001 1001 1000000}
|
|
db close
|
|
file delete -force test.db
|
|
file delete -force test2.db
|
|
|
|
# 1. create a database with WAL journal mode
|
|
# 2. create table and insert operations should work
|
|
# 3. close database, open it again
|
|
# 4. verify that the table is present, readable, and that
|
|
# the journal mode is WAL
|
|
do_test journal-mode-wal {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA journal_mode = WAL;
|
|
CREATE table t1(a,b);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<=1000} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t1 VALUES($i,'value $r');"
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
}
|
|
|
|
db close
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT count(*) FROM t1;
|
|
PRAGMA journal_mode;
|
|
}
|
|
|
|
} {1000 wal}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# Test rekey as first operation on an empty database. should be a no-op
|
|
do_test rekey-as-first-op {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA rekey = 'testkey';
|
|
CREATE table t1(a,b);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<=100} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t1 VALUES($i,'value $r');"
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
}
|
|
|
|
db close
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA rekey = 'testkey';
|
|
SELECT count(*) FROM t1;
|
|
}
|
|
|
|
} {100}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# Test rekey as first operation follwed by key
|
|
do_test rekey-then-key-as-first-ops {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA rekey = '1234';
|
|
PRAGMA key = 'testkey';
|
|
CREATE table t1(a,b);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<=100} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t1 VALUES($i,'value $r');"
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
}
|
|
|
|
db close
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA rekey = '4321';
|
|
PRAGMA key = 'testkey';
|
|
SELECT count(*) FROM t1;
|
|
}
|
|
|
|
} {100}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
setup test.db "'testkey'"
|
|
do_test multiple-key-calls-safe-1 {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA cache_size = 0;
|
|
SELECT name FROM sqlite_master WHERE type='table';
|
|
}
|
|
} {t1}
|
|
|
|
do_test multiple-key-calls-safe-2 {
|
|
catchsql {
|
|
PRAGMA key = 'wrong key';
|
|
SELECT name FROM sqlite_master WHERE type='table';
|
|
}
|
|
} {1 {file is encrypted or is not a database}}
|
|
|
|
do_test multiple-key-calls-safe-3 {
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT name FROM sqlite_master WHERE type='table';
|
|
}
|
|
} {t1}
|
|
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# 1. create a database with a custom hmac kdf iteration count,
|
|
# 2. create table and insert operations should work
|
|
# 3. close database, open it again with the same
|
|
# key and hmac kdf iteration count
|
|
# 4. verify that the table is readable
|
|
# and the data just inserted is visible
|
|
do_test custom-hmac-kdf-iter {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA fast_kdf_iter = 10;
|
|
CREATE table t1(a,b);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<=1000} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t1 VALUES($i,'value $r');"
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
}
|
|
|
|
db close
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA fast_kdf_iter = 10;
|
|
SELECT count(*) FROM t1;
|
|
}
|
|
|
|
} {1000}
|
|
db close
|
|
|
|
# open the database with the default hmac
|
|
# kdf iteration count
|
|
# to verify that it is not readable
|
|
do_test custom-hmac-kdf-iter-must-match {
|
|
sqlite_orig db test.db
|
|
catchsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT name FROM sqlite_master WHERE type='table';
|
|
}
|
|
} {1 {file is encrypted or is not a database}}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# open the database and turn on auto_vacuum
|
|
# then insert a bunch of data, delete it
|
|
# and verify that the file has become smaller
|
|
# but can still be opened with the proper
|
|
# key
|
|
do_test auto-vacuum {
|
|
sqlite_orig db test.db
|
|
set rc {}
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA auto_vacuum=FULL;
|
|
CREATE table t1(a,b);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<=10000} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t1 VALUES($i,'value $r');"
|
|
}
|
|
|
|
lappend rc [execsql {
|
|
COMMIT;
|
|
SELECT count(*) FROM t1;
|
|
}]
|
|
|
|
# grab current size of file
|
|
set sz [file size test.db]
|
|
|
|
# delete some records, and verify
|
|
# autovacuum removes them
|
|
execsql {
|
|
DELETE FROM t1 WHERE rowid > 5000;
|
|
}
|
|
|
|
db close
|
|
|
|
# grab new file size, post
|
|
# autovacuum
|
|
set sz2 [file size test.db]
|
|
|
|
# verify that the new size is
|
|
# smaller than the old size
|
|
if {$sz > $sz2} { lappend rc true }
|
|
|
|
sqlite_orig db test.db
|
|
|
|
lappend rc [execsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT count(*) FROM t1;
|
|
}]
|
|
|
|
} {10000 true 5000}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# open the database then insert a bunch of data.
|
|
# then delete it and run a manual vacuum
|
|
# verify that the file has become smaller
|
|
# but can still be opened with the proper
|
|
# key
|
|
do_test vacuum {
|
|
sqlite_orig db test.db
|
|
set rc {}
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
CREATE table t1(a,b);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<=10000} {incr i} {
|
|
set r [expr {int(rand()*500000)}]
|
|
execsql "INSERT INTO t1 VALUES($i,'value $r');"
|
|
}
|
|
|
|
lappend rc [execsql {
|
|
COMMIT;
|
|
SELECT count(*) FROM t1;
|
|
}]
|
|
|
|
# grab current size of file
|
|
set sz [file size test.db]
|
|
|
|
execsql {
|
|
DELETE FROM t1 WHERE rowid > 5000;
|
|
VACUUM;
|
|
}
|
|
db close
|
|
|
|
# grab new file size, post
|
|
# autovacuum
|
|
set sz2 [file size test.db]
|
|
|
|
# verify that the new size is
|
|
# smaller than the old size
|
|
if {$sz > $sz2} { lappend rc true }
|
|
|
|
sqlite_orig db test.db
|
|
lappend rc [execsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT count(*) FROM t1;
|
|
}]
|
|
|
|
} {10000 true 5000}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# test kdf_iter and other pragmas
|
|
# before a key is set. Verify that they
|
|
# are no-ops
|
|
do_test cipher-options-before-keys {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA kdf_iter = 1000;
|
|
PRAGMA cipher_page_size = 4096;
|
|
PRAGMA cipher = 'aes-128-cbc';
|
|
PRAGMA cipher_use_hmac = OFF;
|
|
PRAGMA key = 'testkey';
|
|
CREATE table t1(a,b);
|
|
INSERT INTO t1 VALUES(1,2);
|
|
}
|
|
db close
|
|
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT count(*) FROM t1;
|
|
}
|
|
|
|
} {1}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# open a 1.1.8 database (no HMAC, 4K iter), then
|
|
# try to open another 1.1.8 database. The
|
|
# attached database should have the same hmac
|
|
# setting as the original
|
|
do_test default-hmac-kdf-attach {
|
|
file copy -force sqlcipher-1.1.8-testkey.db test.db
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA cipher_default_use_hmac = OFF;
|
|
PRAGMA cipher_default_kdf_iter = 4000;
|
|
PRAGMA key = 'testkey';
|
|
SELECT count(*) FROM t1;
|
|
ATTACH 'sqlcipher-1.1.8-testkey.db' AS db2 KEY 'testkey';
|
|
SELECT count(*) from db2.t1;
|
|
PRAGMA cipher_default_use_hmac = ON;
|
|
PRAGMA cipher_default_kdf_iter = 64000;
|
|
}
|
|
} {75709 75709}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# open a 2.0 database (with HMAC), then
|
|
# try to a 1.1.8 database. this should
|
|
# fail because the hmac setting for the
|
|
# attached database is not compatible
|
|
do_test attach-1.1.8-database-from-2.0-fails {
|
|
sqlite_orig db test.db
|
|
catchsql {
|
|
PRAGMA key = 'testkey';
|
|
CREATE table t1(a,b);
|
|
ATTACH 'sqlcipher-1.1.8-testkey.db' AS db2 KEY 'testkey';
|
|
}
|
|
} {1 {file is encrypted or is not a database}}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# open a 2.0 database (with HMAC, 4k iter), then
|
|
# set the default hmac setting to OFF.
|
|
# try to a 1.1.8 database. this should
|
|
# succeed now that hmac is off by default
|
|
# before the attach
|
|
do_test change-default-hmac-kdf-attach {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
CREATE table t1(a,b);
|
|
INSERT INTO t1(a,b) VALUES (1,2);
|
|
}
|
|
db close
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT count(*) FROM t1;
|
|
PRAGMA cipher_default_use_hmac = OFF;
|
|
PRAGMA cipher_default_kdf_iter = 4000;
|
|
ATTACH 'sqlcipher-1.1.8-testkey.db' AS db2 KEY 'testkey';
|
|
SELECT count(*) from db2.t1;
|
|
PRAGMA cipher_default_use_hmac = ON;
|
|
PRAGMA cipher_default_kdf_iter = 64000;
|
|
}
|
|
} {1 75709}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# verify the pragma cipher_version
|
|
# returns the currently configured
|
|
# sqlcipher version
|
|
do_test verify-pragma-cipher-version {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA cipher_version;
|
|
}
|
|
} {3.0.1}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# create a new database, insert some data
|
|
# and delete some data with
|
|
# auto_vacuum on
|
|
do_test auto-vacuum-full {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'test123';
|
|
PRAGMA auto_vacuum = FULL;
|
|
CREATE TABLE t1(a,b);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<10000} {incr i} {
|
|
set r [expr {int(rand()*32767)}]
|
|
set r1 [expr {int(rand()*32767)}]
|
|
execsql "INSERT INTO t1 VALUES($r,$r1);"
|
|
}
|
|
set r [expr {int(rand()*32767)}]
|
|
execsql "DELETE FROM t1 WHERE a < $r;"
|
|
|
|
execsql {
|
|
COMMIT;
|
|
PRAGMA integrity_check;
|
|
PRAGMA freelist_count;
|
|
SELECT (count(*) > 0) FROM t1;
|
|
}
|
|
} {ok 0 1}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# create a new database, insert some data
|
|
# and delete some data with
|
|
# auto_vacuum incremental
|
|
do_test auto-vacuum-incremental {
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'test123';
|
|
PRAGMA auto_vacuum = INCREMENTAL;
|
|
CREATE TABLE t1(a,b);
|
|
BEGIN;
|
|
}
|
|
|
|
for {set i 1} {$i<10000} {incr i} {
|
|
set r [expr {int(rand()*32767)}]
|
|
set r1 [expr {int(rand()*32767)}]
|
|
execsql "INSERT INTO t1 VALUES($r,$r1);"
|
|
}
|
|
set r [expr {int(rand()*32767)}]
|
|
execsql "DELETE FROM t1 WHERE a < $r;"
|
|
|
|
execsql {
|
|
COMMIT;
|
|
PRAGMA incremental_vacuum;
|
|
PRAGMA freelist_count;
|
|
PRAGMA integrity_check;
|
|
SELECT (count(*) > 0) FROM t1;
|
|
}
|
|
} {0 ok 1}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
|
|
# create a database with many hundred tables such that the schema
|
|
# will overflow the first several pages of the database. verify the schema
|
|
# is intact on open.
|
|
do_test multipage-schema {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
BEGIN EXCLUSIVE;
|
|
} db
|
|
|
|
for {set i 1} {$i<=300} {incr i} {
|
|
execsql "CREATE TABLE tab$i (a TEXT, b TEXT, c TEXT, d TEXT, e TEXT, f TEXT, g TEXT, h TEXT, i TEXT, j TEXT, k, TEXT, l, m TEXT, n TEXT, o TEXT, p TEXT);" db
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
} db
|
|
|
|
db close
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT count(*) FROM sqlite_master where type = 'table';
|
|
} db
|
|
|
|
} {300}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# create a database with many hundred tables such that the schema
|
|
# will overflow the first several pages of the database. this time, enable
|
|
# autovacuum on the database, which will cause sqlite to do some "short reads"
|
|
# after the end of the main database file. verify that there are no HMAC errors
|
|
# resulting from the short reads, and that the schema is intact when
|
|
# the database is reopened
|
|
do_test multipage-schema-autovacuum-shortread {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA auto_vacuum = FULL;
|
|
BEGIN EXCLUSIVE;
|
|
} db
|
|
|
|
for {set i 1} {$i<=300} {incr i} {
|
|
execsql "CREATE TABLE tab$i (a TEXT, b TEXT, c TEXT, d TEXT, e TEXT, f TEXT, g TEXT, h TEXT, i TEXT, j TEXT, k, TEXT, l, m TEXT, n TEXT, o TEXT, p TEXT);" db
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
} db
|
|
|
|
db close
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT count(*) FROM sqlite_master where type = 'table';
|
|
} db
|
|
|
|
} {300}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# same as multi-page-schema-autovacuum-shortread, except
|
|
# using write ahead log mode
|
|
do_test multipage-schema-autovacuum-shortread-wal {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA auto_vacuum = FULL;
|
|
PRAGMA journal_mode = WAL;
|
|
BEGIN EXCLUSIVE;
|
|
} db
|
|
|
|
for {set i 1} {$i<=300} {incr i} {
|
|
execsql "CREATE TABLE tab$i (a TEXT, b TEXT, c TEXT, d TEXT, e TEXT, f TEXT, g TEXT, h TEXT, i TEXT, j TEXT, k, TEXT, l, m TEXT, n TEXT, o TEXT, p TEXT);" db
|
|
}
|
|
|
|
execsql {
|
|
COMMIT;
|
|
} db
|
|
|
|
db close
|
|
sqlite_orig db test.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT count(*) FROM sqlite_master where type = 'table';
|
|
} db
|
|
} {300}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# open a 3.0 database with little endian hmac page numbers (default)
|
|
# verify it can be opened
|
|
do_test open-3.0-le-database {
|
|
sqlite_orig db sqlcipher-3.0-testkey.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT count(*) FROM t1;
|
|
SELECT distinct * FROM t1;
|
|
}
|
|
} {78536 1 1 one one 1 2 one two}
|
|
db close
|
|
|
|
# open a 2.0 database with little endian hmac page numbers (default)
|
|
# verify it can be opened
|
|
do_test open-2.0-le-database {
|
|
sqlite_orig db sqlcipher-2.0-le-testkey.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA kdf_iter = 4000;
|
|
SELECT count(*) FROM t1;
|
|
SELECT distinct * FROM t1;
|
|
}
|
|
} {78536 1 1 one one 1 2 one two}
|
|
db close
|
|
|
|
# open a 2.0 database with big-endian hmac page numbers
|
|
# verify it can be opened
|
|
do_test open-2.0-be-database {
|
|
sqlite_orig db sqlcipher-2.0-be-testkey.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA cipher_hmac_pgno = be;
|
|
PRAGMA kdf_iter = 4000;
|
|
SELECT count(*) FROM t1;
|
|
SELECT distinct * FROM t1;
|
|
}
|
|
} {78536 1 1 one one 1 2 one two}
|
|
db close
|
|
|
|
# open a 2.0 database with big-endian hmac page numbers
|
|
# attach a new database with little endian page numbers (default)
|
|
# copy schema between the two, and verify the latter
|
|
# can be opened
|
|
do_test be-to-le-migration {
|
|
sqlite_orig db sqlcipher-2.0-be-testkey.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA cipher_hmac_pgno = be;
|
|
PRAGMA kdf_iter = 4000;
|
|
ATTACH DATABASE 'test.db' AS db2 KEY 'testkey';
|
|
CREATE TABLE db2.t1(a,b);
|
|
INSERT INTO db2.t1 SELECT * FROM main.t1;
|
|
DETACH DATABASE db2;
|
|
}
|
|
db close
|
|
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT count(*) FROM t1;
|
|
SELECT distinct * FROM t1;
|
|
}
|
|
} {78536 1 1 one one 1 2 one two}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# verify the pragma cipher_use_hmac
|
|
# is set to true be default
|
|
do_test verify-pragma-cipher-use-hmac-default {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'test';
|
|
PRAGMA cipher_use_hmac;
|
|
}
|
|
} {1}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# verify the pragma cipher_use_hmac
|
|
# reports the flag turned off
|
|
do_test verify-pragma-cipher-use-hmac-off {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'test';
|
|
PRAGMA cipher_use_hmac = off;
|
|
PRAGMA cipher_use_hmac;
|
|
}
|
|
} {0}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# verify the pragma default_cipher_use_hmac
|
|
# is set to true by default
|
|
do_test verify-pragma-cipher-default-use-hmac-default {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA cipher_default_use_hmac;
|
|
}
|
|
} {1}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# verify the pragma default_cipher_use_hmac
|
|
# reports the flag turned off
|
|
do_test verify-pragma-cipher-default-use-hmac-off {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA cipher_default_use_hmac = off;
|
|
PRAGMA cipher_default_use_hmac;
|
|
-- Be sure to turn cipher_default_use_hmac
|
|
-- back on or it will break later tests
|
|
-- (it's a global flag)
|
|
PRAGMA cipher_default_use_hmac = ON;
|
|
}
|
|
} {0}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# verify the pragma default_cipher_kdf_iter
|
|
# is set to 64000 by default
|
|
do_test verify-pragma-cipher-default-kdf-iter-default {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA cipher_default_kdf_iter;
|
|
}
|
|
} {64000}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
|
|
# verify the pragma default_cipher_kdf_ter
|
|
# reports changes
|
|
do_test verify-pragma-cipher-default-use-hmac-off {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA cipher_default_kdf_iter = 1000;
|
|
PRAGMA cipher_default_kdf_iter;
|
|
PRAGMA cipher_default_kdf_iter = 64000;
|
|
}
|
|
} {1000}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# verify the pragma kdf_iter
|
|
# reports the default value
|
|
do_test verify-pragma-kdf-iter-reports-default {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'test';
|
|
PRAGMA kdf_iter;
|
|
}
|
|
} {64000}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# verify the pragma kdf_iter
|
|
# reports value changed
|
|
do_test verify-pragma-kdf-iter-reports-value-changed {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'test';
|
|
PRAGMA kdf_iter = 8000;
|
|
PRAGMA kdf_iter;
|
|
}
|
|
} {8000}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# verify the pragma fast_kdf_iter
|
|
# reports the default value
|
|
do_test verify-pragma-fast-kdf-iter-reports-default {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'test';
|
|
PRAGMA fast_kdf_iter;
|
|
}
|
|
} {2}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# verify the pragma fast_kdf_iter
|
|
# reports value changed
|
|
do_test verify-pragma-kdf-iter-reports-value-changed {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'test';
|
|
PRAGMA fast_kdf_iter = 4000;
|
|
PRAGMA fast_kdf_iter;
|
|
}
|
|
} {4000}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# verify the pragma cipher_page_size
|
|
# reports default value
|
|
do_test verify-pragma-cipher-page-size-default {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'test';
|
|
PRAGMA cipher_page_size;
|
|
}
|
|
} {1024}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# verify the pragma cipher_page_size
|
|
# reports change in value
|
|
do_test verify-pragma-cipher-page-size-changed {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'test';
|
|
PRAGMA cipher_page_size = 4096;
|
|
PRAGMA cipher_page_size;
|
|
}
|
|
} {4096}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# verify the pragma cipher
|
|
# reports the default value
|
|
if_built_with_openssl verify-pragma-cipher-default {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'test';
|
|
PRAGMA cipher;
|
|
}
|
|
} {AES-256-CBC}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# verify the pragma cipher
|
|
# reports a change in value
|
|
if_built_with_openssl verify-pragma-cipher-changed {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'test';
|
|
PRAGMA cipher = 'AES-256-ECB';
|
|
PRAGMA cipher;
|
|
}
|
|
} {AES-256-ECB}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# verify the pragma cipher_hmac_salt_mask reports default
|
|
do_test verify-pragma-hmac-salt-mask-reports-default {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'test';
|
|
PRAGMA cipher_hmac_salt_mask;
|
|
}
|
|
} {3a}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# verify the pragma cipher_hmac_salt_mask reports
|
|
# reports value changed
|
|
do_test verify-pragma-hmac-salt-mask-reports-value-changed {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'test';
|
|
PRAGMA cipher_hmac_salt_mask = "x'11'";
|
|
PRAGMA cipher_hmac_salt_mask;
|
|
}
|
|
} {11}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# verify the pragma cipher_hmac_pgno reports default
|
|
do_test verify-pragma-hmac-pgno-reports-default {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'test';
|
|
PRAGMA cipher_hmac_pgno;
|
|
}
|
|
} {le}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# verify the pragma cipher_hmac_pgno
|
|
# reports value changed
|
|
do_test verify-pragma-hmac-pgno-reports-value-changed {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'test';
|
|
PRAGMA cipher_hmac_pgno = be;
|
|
PRAGMA cipher_hmac_pgno;
|
|
PRAGMA cipher_hmac_pgno = native;
|
|
PRAGMA cipher_hmac_pgno;
|
|
PRAGMA cipher_hmac_pgno = le;
|
|
PRAGMA cipher_hmac_pgno;
|
|
}
|
|
} {be native le}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
# open a 2.0 beta database with 4000 round hmac kdf and 0x00
|
|
# hmac salt mask
|
|
# verify it can be opened
|
|
do_test open-2.0-beta-database {
|
|
sqlite_orig db sqlcipher-2.0-beta-testkey.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA kdf_iter = 4000;
|
|
PRAGMA fast_kdf_iter = 4000;
|
|
PRAGMA cipher_hmac_salt_mask = "x'00'";
|
|
SELECT count(*) FROM t1;
|
|
SELECT distinct * FROM t1;
|
|
}
|
|
} {38768 test-0-0 test-0-1 test-1-0 test-1-1}
|
|
db close
|
|
|
|
# open a 2.0 beta database
|
|
# attach a new standard database
|
|
# copy schema between the two, and verify the latter
|
|
# can be opened
|
|
do_test 2.0-beta-to-2.0-migration {
|
|
sqlite_orig db sqlcipher-2.0-beta-testkey.db
|
|
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA cipher_hmac_salt_mask = "x'00'";
|
|
PRAGMA kdf_iter = 4000;
|
|
PRAGMA fast_kdf_iter = 4000;
|
|
SELECT count(*) FROM sqlite_master;
|
|
|
|
PRAGMA cipher_hmac_salt_mask = "x'3a'";
|
|
ATTACH DATABASE 'test.db' AS db2 KEY 'testkey';
|
|
|
|
CREATE TABLE db2.t1(a,b);
|
|
INSERT INTO db2.t1 SELECT * FROM main.t1;
|
|
DETACH DATABASE db2;
|
|
}
|
|
db close
|
|
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT distinct * FROM t1;
|
|
}
|
|
} {test-0-0 test-0-1 test-1-0 test-1-1}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
if_built_with_libtomcrypt verify-default-cipher {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key='test';
|
|
PRAGMA cipher;
|
|
}
|
|
} {rijndael}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
if_built_with_commoncrypto verify-default-cipher {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key='test';
|
|
PRAGMA cipher;
|
|
}
|
|
} {aes-256-cbc}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
do_test migrate-1.1.8-database-to-3x-format {
|
|
file copy -force sqlcipher-1.1.8-testkey.db test.db
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA cipher_migrate;
|
|
}
|
|
db close
|
|
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT count(*) FROM sqlite_master;
|
|
}
|
|
} {1}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
do_test migrate-2-0-le-database-to-3x-format {
|
|
file copy -force sqlcipher-2.0-le-testkey.db test.db
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
PRAGMA cipher_migrate;
|
|
}
|
|
db close
|
|
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = 'testkey';
|
|
SELECT count(*) FROM sqlite_master;
|
|
}
|
|
} {1}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
do_test key-database-by-name {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
attach database 'new.db' as new;
|
|
pragma new.key = 'foo';
|
|
create table new.t1(a,b);
|
|
insert into new.t1(a,b) values('foo', 'bar');
|
|
detach database new;
|
|
}
|
|
db close
|
|
|
|
sqlite_orig db new.db
|
|
execsql {
|
|
pragma key = 'foo';
|
|
select * from t1;
|
|
}
|
|
} {foo bar}
|
|
db close
|
|
file delete -force test.db
|
|
file delete -force new.db
|
|
|
|
do_test key-multiple-databases-with-different-keys-using-pragma {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
pragma key = 'foobar';
|
|
create table t1(a,b);
|
|
insert into t1(a,b) values('baz','qux');
|
|
attach database 'new.db' as new;
|
|
pragma new.key = 'foo';
|
|
create table new.t1(a,b);
|
|
insert into new.t1(a,b) values('foo', 'bar');
|
|
detach database new;
|
|
}
|
|
db close
|
|
|
|
sqlite_orig db new.db
|
|
execsql {
|
|
pragma key = 'foo';
|
|
attach database 'test.db' as test key 'foobar';
|
|
select * from t1;
|
|
select * from test.t1;
|
|
}
|
|
} {foo bar baz qux}
|
|
db close
|
|
file delete -force test.db
|
|
file delete -force new.db
|
|
|
|
do_test rekey-database-by-name {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
attach database 'new.db' as new;
|
|
pragma new.key = 'foo';
|
|
create table new.t1(a,b);
|
|
insert into new.t1(a,b) values('foo', 'bar');
|
|
pragma new.rekey = 'bar';
|
|
detach database new;
|
|
}
|
|
db close
|
|
|
|
sqlite_orig db new.db
|
|
execsql {
|
|
pragma key = 'bar';
|
|
select * from t1;
|
|
}
|
|
} {foo bar}
|
|
db close
|
|
file delete -force test.db
|
|
file delete -force new.db
|
|
|
|
# Requires SQLCipher to be built with -DSQLCIPHER_TEST
|
|
if_built_with_libtomcrypt verify-random-data-alters-file-content {
|
|
file delete -force test.db
|
|
file delete -force test2.db
|
|
file delete -force test3.db
|
|
set rc {}
|
|
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key="x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'";
|
|
create table t1(a,b);
|
|
}
|
|
db close
|
|
sqlite_orig db test2.db
|
|
execsql {
|
|
PRAGMA key="x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'";
|
|
create table t1(a,b);
|
|
}
|
|
db close
|
|
sqlite_orig db test3.db
|
|
execsql {
|
|
PRAGMA key="x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'";
|
|
PRAGMA cipher_add_random = "x'deadbaad'";
|
|
create table t1(a,b);
|
|
}
|
|
db close
|
|
lappend rc [cmpFilesChunked test.db test2.db]
|
|
lappend rc [cmpFilesChunked test2.db test3.db]
|
|
} {0 1}
|
|
file delete -force test.db
|
|
file delete -force test2.db
|
|
file delete -force test3.db
|
|
|
|
do_test can-migrate-with-keys-longer-than-64-characters {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = "012345678901234567890123456789012345678901234567890123456789012345";
|
|
PRAGMA kdf_iter = 4000;
|
|
PRAGMA user_version = 5;
|
|
}
|
|
db close
|
|
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = "012345678901234567890123456789012345678901234567890123456789012345";
|
|
PRAGMA cipher_migrate;
|
|
}
|
|
db close
|
|
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = "012345678901234567890123456789012345678901234567890123456789012345";
|
|
PRAGMA user_version;
|
|
}
|
|
} {5}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
do_test can-migrate-with-raw-hex-key {
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'";
|
|
PRAGMA kdf_iter = 4000;
|
|
PRAGMA cipher_use_hmac = off;
|
|
PRAGMA user_version = 5;
|
|
}
|
|
db close
|
|
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'";
|
|
PRAGMA cipher_migrate;
|
|
}
|
|
|
|
sqlite_orig db test.db
|
|
execsql {
|
|
PRAGMA key = "x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'";
|
|
PRAGMA user_version;
|
|
}
|
|
|
|
} {5}
|
|
db close
|
|
file delete -force test.db
|
|
|
|
sqlite3_test_control_pending_byte $old_pending_byte
|
|
finish_test
|