bump version
[sqlcipher.git] / test / sqlcipher-rekey.test
blob267b890777ee5f9538331d2bb56a7046f2b230b8
1 # SQLCipher
2 # codec.test developed by Stephen Lombardo (Zetetic LLC)
3 # sjlombardo at zetetic dot net
4 # http://zetetic.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 # Test rekey as first operation on an empty database
42 # it should raise an error
43 do_test rekey-as-first-op-on-empty {
44   sqlite_orig db test.db
46   catchsql {
47     PRAGMA rekey = 'testkey';
48   }
50 } {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.}}
51 db close
52 file delete -force test.db
54 # test a rekey operation as the first op on an existing database
55 # then test that now the new key opens the database
56 # now close database re-open with new key
57 setup test.db "'testkey'"
58 do_test rekey-as-first-operation {
59   sqlite_orig db test.db
60   execsql {
61     PRAGMA key = 'testkey';
62     PRAGMA rekey = 'testkeynew';
63   }
64   db close
66   sqlite_orig db test.db
67   execsql {
68     PRAGMA key = 'testkeynew';
69     SELECT name FROM sqlite_schema WHERE type='table';
70   }
71 } {ok t1}
72 db close
73 file delete -force test.db
75 # create a new database, insert some data
76 # then rekey it with the same password
77 do_test rekey-same-passkey {
78   sqlite_orig db test.db
80   execsql {
81     PRAGMA key = 'test123';
82     CREATE TABLE t1(a,b);
83     BEGIN;
84   }
86   for {set i 1} {$i<=1000} {incr i} {
87     set r [expr {int(rand()*500000)}]
88     execsql "INSERT INTO t1 VALUES($i,'value $r');"
89   }
91   execsql {
92     COMMIT;
93     SELECT count(*) FROM t1;
94     PRAGMA rekey = 'test123';
95     SELECT count(*) FROM t1;
96   }
97 } {1000 ok 1000}
98 db close
99 file delete -force test.db
101 # create a new database, insert some data
102 # then rekey it. Make sure it is immediately
103 # readable. Then close it and make sure it can be
104 # read back 
105 do_test rekey-and-query-1 {
106   sqlite_orig db test.db
108   execsql {
109     PRAGMA key = 'test123';
110     CREATE TABLE t1(a,b);
111     BEGIN;
112   }
114   for {set i 1} {$i<=1000} {incr i} {
115     set r [expr {int(rand()*500000)}]
116     execsql "INSERT INTO t1 VALUES($i,'value $r');"
117   }
119   execsql {
120     COMMIT;
121     SELECT count(*) FROM t1;
122     PRAGMA rekey = 'test321';
123     SELECT count(*) FROM t1;
124   }
125 } {1000 ok 1000}
127 db close
129 do_test rekey-and-query-2 {
130   sqlite_orig db test.db
131   execsql {
132     PRAGMA key = 'test321';
133     SELECT count(*) FROM t1;
134   }
135 } {ok 1000}
136 db close
137 file delete -force test.db
139 # create a new database, insert some data
140 # delete about 50% of the data
141 # write some new data
142 # delete another 50%
143 # then rekey it. Make sure it is immediately
144 # readable. Then close it and make sure it can be
145 # read back. This test will ensure that Secure Delete
146 # is enabled and all pages are being written and are not
147 # being optimized out by sqlite3PagerDontWrite
148 do_test rekey-delete-and-query-1 {
149   sqlite_orig db test.db
151   execsql {
152     PRAGMA key = 'test123';
153     CREATE TABLE t1(a,b);
154     CREATE INDEX ta_a ON t1(a);
155     BEGIN;
156   }
158   for {set i 1} {$i<1000} {incr i} {
159     set r1 [expr {int(rand()*32767)}]
160     execsql "INSERT INTO t1 VALUES($i,$r1);"
161   }
163   execsql "DELETE FROM t1 WHERE a < 500;"
165   set r1 [expr {int(rand()*32767)}]
166   execsql "UPDATE t1 SET b = $r1 WHERE a < 750;"
168   execsql "DELETE FROM t1 WHERE a > 750;"
170   execsql {
171     COMMIT;
172     SELECT (count(*) > 0) FROM t1;
173   }
174 } {1}
175 db close
177 do_test rekey-delete-and-query-2 {
178   sqlite_orig db test.db
179   execsql {
180     PRAGMA key = 'test123';
181     PRAGMA rekey = 'test321';
182     SELECT count(*) > 1 FROM t1;
183     PRAGMA integrity_check;
184   }
185 } {ok ok 1 ok}
186 db close
188 do_test rekey-delete-and-query-3 {
189   sqlite_orig db test.db
190   execsql {
191     PRAGMA key = 'test321';
192     SELECT count(*) > 1 FROM t1;
193   }
194 } {ok 1}
195 db close
196 file delete -force test.db
199 # same as previous test, but use WAL
200 do_test rekey-delete-and-query-wal-1 {
201   sqlite_orig db test.db
203   execsql {
204     PRAGMA key = 'test123';
205     PRAGMA journal_mode = WAL;
206     CREATE TABLE t1(a,b);
207     CREATE INDEX ta_a ON t1(a);
208     BEGIN;
209   }
211   for {set i 1} {$i<1000} {incr i} {
212     set r1 [expr {int(rand()*32767)}]
213     execsql "INSERT INTO t1 VALUES($i,$r1);"
214   }
216   execsql "DELETE FROM t1 WHERE a < 500;"
218   set r1 [expr {int(rand()*32767)}]
219   execsql "UPDATE t1 SET b = $r1 WHERE a < 750;"
221   execsql "DELETE FROM t1 WHERE a > 750;"
223   execsql {
224     COMMIT;
225     SELECT (count(*) > 0) FROM t1;
226   }
227 } {1}
228 db close
230 do_test rekey-delete-and-query-wal-2 {
231   sqlite_orig db test.db
232   execsql {
233     PRAGMA key = 'test123';
234     PRAGMA journal_mode = WAL;
235     PRAGMA rekey = 'test321';
236     SELECT count(*) > 1 FROM t1;
237     PRAGMA integrity_check;
238   }
239 } {ok wal ok 1 ok}
240 db close
242 do_test rekey-delete-and-query-wal-3 {
243   sqlite_orig db test.db
244   execsql {
245     PRAGMA key = 'test321';
246     PRAGMA journal_mode = WAL;
247     SELECT count(*) > 1 FROM t1;
248   }
249 } {ok wal 1}
250 db close
251 file delete -force test.db
253 do_test rekey-database-by-name {
254     sqlite_orig db test.db
255     execsql {
256         attach database 'new.db' as new;
257         pragma new.key = 'foo';
258         create table new.t1(a,b);
259         insert into new.t1(a,b) values('foo', 'bar');
260         pragma new.rekey = 'bar';
261         detach database new;
262     }
263     db close
265     sqlite_orig db new.db
266     execsql {
267         pragma key = 'bar';
268         select * from t1;
269     }
270 } {ok foo bar}
271 db close
272 file delete -force test.db
273 file delete -force new.db
275 finish_test