Update README.md
[sqlcipher.git] / test / sqlcipher-integrity.test
blob639f9495d00a8743b3a93e2a290907d09f087092
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 # 1. create a database and insert a bunch of data, close the database
42 # 2. seek to the middle of the first database page and write some junk
43 # 3. Open the database and verify that the database is no longer readable
44 do_test hmac-tamper-resistence-first-page {
45   sqlite_orig db test.db
47   execsql {
48     PRAGMA key = 'testkey';
49     CREATE table t1(a,b);
50     BEGIN;
51   }
53   for {set i 1} {$i<=1000} {incr i} {
54     set r [expr {int(rand()*500000)}]
55     execsql "INSERT INTO t1 VALUES($i,'value $r');" 
56   }
58   execsql {
59     COMMIT;
60   } 
62   db close
64   # write some junk into the hmac segment, leaving
65   # the page data valid but with an invalid signature
66   hexio_write test.db 1000 000000
68   sqlite_orig db test.db
70   catchsql {
71     PRAGMA key = 'testkey';
72     SELECT count(*) FROM t1;
73   }
75 } {1 {file is not a database}}
76 db close
77 file delete -force test.db
79 # 1. create a database and insert a bunch of data, close the database
80 # 2. seek to the middle of a database page and write some junk
81 # 3. Open the database and verify that the database is still readable
82 do_test nohmac-not-tamper-resistent {
83   sqlite_orig db test.db
85   execsql {
86     PRAGMA key = 'testkey';
87     PRAGMA cipher_use_hmac = OFF;
88     PRAGMA cipher_page_size = 1024;
89     CREATE table t1(a,b);
90     BEGIN;
91   }
93   for {set i 1} {$i<=1000} {incr i} {
94     set r [expr {int(rand()*500000)}]
95     execsql "INSERT INTO t1 VALUES($i,'value $r');" 
96   }
98   execsql {
99     COMMIT;
100   } 
102   db close
104   # write some junk into the middle of the page
105   hexio_write test.db 2560 000000
107   sqlite_orig db test.db
109   execsql {
110     PRAGMA key = 'testkey';
111     PRAGMA cipher_use_hmac = OFF;
112     PRAGMA cipher_page_size = 1024;
113     SELECT count(*) FROM t1;
114   }
116 } {ok 1000}
117 db close
118 file delete -force test.db
120 # 1. create a database and insert a bunch of data, close the database
121 # 2. seek to the middle of a database page (not the first page) and write bad data
122 # 3. Open the database and verify that the database is no longer readable
123 do_test hmac-tamper-resistence {
124   sqlite_orig db test.db
126   execsql {
127     PRAGMA key = 'testkey';
128     CREATE table t1(a,b);
129     BEGIN;
130   }
132   for {set i 1} {$i<=1000} {incr i} {
133     set r [expr {int(rand()*500000)}]
134     execsql "INSERT INTO t1 VALUES($i,'value $r');"
135   }
137   execsql {
138     COMMIT;
139   }
141   db close
143   # write some junk into the hmac segment, leaving
144   # the page data valid but with an invalid signature
145   hexio_write test.db 16500 000000
147   sqlite_orig db test.db
149   catchsql {
150     PRAGMA key = 'testkey';
151     SELECT count(*) FROM t1;
152   }
154 } {1 {database disk image is malformed}}
155 db close
156 file delete -force test.db
158 # test that integrity checks work on a pristine
159 # newly created database
160 do_test integrity-check-clean-database {
161   sqlite_orig db test.db
163   execsql {
164     PRAGMA key = 'testkey';
165     CREATE table t1(a,b);
166     BEGIN;
167   }
169   for {set i 1} {$i<=10000} {incr i} {
170     execsql "INSERT INTO t1 VALUES($i,'value $i');"
171   }
173   execsql {
174     COMMIT;
175   }
177   db close
179   sqlite_orig db test.db
180   execsql {
181     PRAGMA key = 'testkey';
182     PRAGMA cipher_integrity_check;
183     PRAGMA integrity_check;
184     SELECT count(*) FROM t1;
185   }
187 } {ok ok 10000}
188 db close
189 file delete -force test.db
191 # try cipher_integrity_check on an in-memory database
192 # which should fail because the file doesn't exist
193 do_test memory-integrity-check-should-fail {
194   sqlite_orig db :memory:
195   execsql {
196     PRAGMA key = 'testkey';
197     CREATE TABLE t1(a,b);
198     INSERT INTO t1(a,b) values (1,2);
199     PRAGMA cipher_integrity_check;
200   } 
201 } {ok {database file is undefined}}
202 db close
204 # try cipher_integrity_check on a valid 1.1.8 database
205 # should fail because version 1.0 doesn't use HMAC
206 do_test version-1-integrity-check-fail-no-hmac {
207   file copy -force $sampleDir/sqlcipher-1.1.8-testkey.db test.db
208   sqlite_orig db test.db
209   execsql {
210     PRAGMA key = 'testkey';
211     PRAGMA cipher_compatibility = 1;
212     PRAGMA cipher_integrity_check;
213   } 
214 } {ok {HMAC is not enabled, unable to integrity check}}
215 db close
216 file delete -force test.db
218 # try cipher_integrity_check on a valid 2 database
219 do_test version-2-integrity-check-valid {
220   file copy -force $sampleDir/sqlcipher-2.0-le-testkey.db test.db
221   sqlite_orig db test.db
222   execsql {
223     PRAGMA key = 'testkey';
224     PRAGMA cipher_compatibility = 2;
225     PRAGMA cipher_integrity_check;
226   } 
227 } {ok}
228 db close
229 file delete -force test.db
231 # try cipher_integrity_check on a corrupted version 2 database
232 do_test version-2-integrity-check-invalid {
233   file copy -force $sampleDir/sqlcipher-2.0-le-testkey.db test.db
234   hexio_write test.db 8202 000000
235   hexio_write test.db 10250 000000
236   sqlite_orig db test.db
237   execsql {
238     PRAGMA key = 'testkey';
239     PRAGMA cipher_compatibility = 2;
240     PRAGMA cipher_integrity_check;
241   } 
242 } {ok {HMAC verification failed for page 9} {HMAC verification failed for page 11}}
243 db close
244 file delete -force test.db
246 # try cipher_integrity_check on a valid version 3 database
247 do_test version-3-integrity-check-valid {
248   file copy -force $sampleDir/sqlcipher-3.0-testkey.db test.db
249   sqlite_orig db test.db
250   execsql {
251     PRAGMA key = 'testkey';
252     PRAGMA cipher_compatibility = 3;
253     PRAGMA cipher_integrity_check;
254   } 
255 } {ok}
256 db close
257 file delete -force test.db
259 # try cipher_integrity_check on a corrupted version 3 database
260 do_test version-3-integrity-check-invalid {
261   file copy -force $sampleDir/sqlcipher-3.0-testkey.db test.db
262   hexio_write test.db 8202 000000
263   hexio_write test.db 10250 000000
264   sqlite_orig db test.db
265   execsql {
266     PRAGMA key = 'testkey';
267     PRAGMA cipher_compatibility = 3;
268     PRAGMA cipher_integrity_check;
269   } 
270 } {ok {HMAC verification failed for page 9} {HMAC verification failed for page 11}}
271 db close
272 file delete -force test.db
274 # try cipher_integrity_check on a valid version 4 database
275 do_test version-4-integrity-check-valid {
276   file copy -force $sampleDir/sqlcipher-4.0-testkey.db test.db
277   sqlite_orig db test.db
278   execsql {
279     PRAGMA key = 'testkey';
280     PRAGMA cipher_integrity_check;
281   } 
282 } {ok}
283 db close
284 file delete -force test.db
286 # try cipher_integrity_check on a corrupted version 4 database
287 do_test version-4-integrity-check-invalid {
288   file copy -force $sampleDir/sqlcipher-4.0-testkey.db test.db
289   # corrupt page data 
290   hexio_write test.db 5120 000000
291   # corrupt iv 
292   hexio_write test.db 12208 000000 
293   # corrupt the mac segment 
294   hexio_write test.db 16320 000000
295   sqlite_orig db test.db
296   execsql {
297     PRAGMA key = 'testkey';
298     PRAGMA cipher_integrity_check;
299   } 
300 } {ok {HMAC verification failed for page 2} {HMAC verification failed for page 3} {HMAC verification failed for page 4}}
301 db close
302 file delete -force test.db
304 # try cipher_integrity_check on a corrupted version 4 database
305 do_test version-4-integrity-check-invalid-last-page {
306   file copy -force $sampleDir/sqlcipher-4.0-testkey.db test.db
307   hexio_write test.db 978944 0000
308   sqlite_orig db test.db
309   execsql {
310     PRAGMA key = 'testkey';
311     PRAGMA cipher_integrity_check;
312   } 
313 } {ok {page 240 has an invalid size of 2 bytes}}
314 db close
315 file delete -force test.db
317 # verify cipher_integrity_check works on a plaintext header db
318 do_test integrity-check-plaintext-header {
319   sqlite_orig db test.db
320   set rc {}
322   execsql {
323     PRAGMA key = 'test';
324     PRAGMA cipher_plaintext_header_size = 32;
325     CREATE TABLE t1(a,b);
326     INSERT INTO t1(a,b) VALUES (1,2);
327   }
329   lappend rc [execsql {
330     PRAGMA cipher_integrity_check;
331   }]
333   lappend rc [string equal [hexio_read test.db 16 5] "1000010150"]
334   
335   hexio_write test.db 120 000000
336   hexio_write test.db 5120 000000
338   lappend rc [execsql {
339     PRAGMA cipher_integrity_check;
340   }]
341 } {{} 1 {{HMAC verification failed for page 1} {HMAC verification failed for page 2}}}
342 file delete -force test.db
344 finish_test