implementation of PRAGMA cipher_integrity_check and associated tests
This commit is contained in:
parent
de558b049f
commit
488d81e8da
|
@ -1,6 +1,9 @@
|
|||
# SQLCipher Change Log
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [unreleased] - (TBD - [unreleased])
|
||||
- Adds PRAGMA cipher_integrity_check to perform external verification of page HMACs
|
||||
|
||||
## [4.1.0] - (March 2019 - [4.1.0 changes])
|
||||
- Defer reading salt from header until key derivation is triggered
|
||||
- Clarify usage of sqlite3_rekey for plaintext databases in header
|
||||
|
|
|
@ -629,6 +629,11 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef
|
|||
pragma = sqlite3_mprintf("PRAGMA cipher_default_kdf_algorithm = %s;", SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL);
|
||||
}
|
||||
codec_vdbe_return_string(pParse, "pragma", pragma, P4_DYNAMIC);
|
||||
}else
|
||||
if( sqlite3StrICmp(zLeft,"cipher_integrity_check")==0 ){
|
||||
if(ctx) {
|
||||
sqlcipher_codec_ctx_integrity_check(ctx, pParse, "cipher_integrity_check");
|
||||
}
|
||||
}else {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -289,6 +289,8 @@ int sqlcipher_get_mem_security(void);
|
|||
|
||||
int sqlcipher_find_db_index(sqlite3 *db, const char *zDb);
|
||||
|
||||
int sqlcipher_codec_ctx_integrity_check(codec_ctx *, Parse *, char *);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
/* END SQLCIPHER */
|
||||
|
|
|
@ -1254,6 +1254,87 @@ cleanup:
|
|||
return rc;
|
||||
}
|
||||
|
||||
int sqlcipher_codec_ctx_integrity_check(codec_ctx *ctx, Parse *pParse, char *column) {
|
||||
Pgno page = 1;
|
||||
int i, trans_rc, rc = 0;
|
||||
char *result;
|
||||
unsigned char *hmac_out = NULL;
|
||||
sqlite3_file *fd = sqlite3PagerFile(ctx->pBt->pBt->pPager);
|
||||
i64 file_sz;
|
||||
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, column, SQLITE_STATIC);
|
||||
|
||||
if(fd == NULL || fd->pMethods == 0) {
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, "database file is undefined", P4_TRANSIENT);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if(!(ctx->flags & CIPHER_FLAG_HMAC)) {
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, "HMAC is not enabled, unable to integrity check", P4_TRANSIENT);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if((rc = sqlcipher_codec_key_derive(ctx)) != SQLITE_OK) {
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, "unable to derive keys", P4_TRANSIENT);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* establish an exclusive lock on the database */
|
||||
if((trans_rc = sqlite3BtreeBeginTrans(ctx->pBt, 2, 0)) != SQLITE_OK) {
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, "unable to lock database", P4_TRANSIENT);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
sqlite3OsFileSize(fd, &file_sz);
|
||||
hmac_out = sqlcipher_malloc(ctx->hmac_sz);
|
||||
|
||||
for(page = 1; page <= file_sz / ctx->page_sz; page++) {
|
||||
int offset = (page - 1) * ctx->page_sz;
|
||||
int payload_sz = ctx->page_sz - ctx->reserve_sz + ctx->iv_sz;
|
||||
int read_sz = ctx->page_sz;
|
||||
|
||||
if(page==1) {
|
||||
int page1_offset = ctx->plaintext_header_sz ? ctx->plaintext_header_sz : FILE_HEADER_SZ;
|
||||
read_sz = read_sz - page1_offset;
|
||||
payload_sz = payload_sz - page1_offset;
|
||||
offset += page1_offset;
|
||||
}
|
||||
|
||||
sqlcipher_memset(ctx->buffer, 0, ctx->page_sz);
|
||||
sqlcipher_memset(hmac_out, 0, ctx->hmac_sz);
|
||||
if(sqlite3OsRead(fd, ctx->buffer, read_sz, offset) != SQLITE_OK) {
|
||||
result = sqlite3_mprintf("error reading %d bytes from file page %d at offset %d\n", read_sz, page, offset);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, result, P4_DYNAMIC);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
||||
} else if(sqlcipher_page_hmac(ctx, ctx->read_ctx, page, ctx->buffer, payload_sz, hmac_out) != SQLITE_OK) {
|
||||
result = sqlite3_mprintf("HMAC operation failed for page %d", page);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, result, P4_DYNAMIC);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
||||
} else if(sqlcipher_memcmp(ctx->buffer + payload_sz, hmac_out, ctx->hmac_sz) != 0) {
|
||||
result = sqlite3_mprintf("HMAC verification failed for page %d", page);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, result, P4_DYNAMIC);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if(file_sz % ctx->page_sz != 0) {
|
||||
result = sqlite3_mprintf("page %d has an invalid size of %d bytes", page, file_sz - ((file_sz / ctx->page_sz) * ctx->page_sz));
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, result, P4_DYNAMIC);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if(trans_rc == SQLITE_OK) sqlite3BtreeRollback(ctx->pBt, SQLITE_OK, 0);
|
||||
if(hmac_out != NULL) sqlcipher_free(hmac_out, ctx->hmac_sz);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) {
|
||||
int i, pass_sz, keyspec_sz, nRes, user_version, rc, oflags;
|
||||
Db *pDb = 0;
|
||||
|
|
|
@ -531,84 +531,6 @@ do_test custom-pagesize-must-match {
|
|||
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 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
|
||||
|
||||
# 1. create a database with WAL journal mode
|
||||
# 2. create table and insert operations should work
|
||||
|
|
|
@ -0,0 +1,332 @@
|
|||
# SQLCipher
|
||||
# codec.test developed by Stephen Lombardo (Zetetic LLC)
|
||||
# sjlombardo at zetetic dot net
|
||||
# http://zetetic.net
|
||||
#
|
||||
# Copyright (c) 2018, 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.
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/sqlcipher.tcl
|
||||
|
||||
# 1. create a database and insert a bunch of data, close the database
|
||||
# 2. seek to the middle of the first database page and write some junk
|
||||
# 3. Open the database and verify that the database is no longer readable
|
||||
do_test hmac-tamper-resistence-first-page {
|
||||
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 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
|
||||
|
||||
# 1. create a database and insert a bunch of data, close the database
|
||||
# 2. seek to the middle of a database page (not the first page) and write bad data
|
||||
# 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 16500 0000
|
||||
|
||||
sqlite_orig db test.db
|
||||
|
||||
catchsql {
|
||||
PRAGMA key = 'testkey';
|
||||
SELECT count(*) FROM t1;
|
||||
}
|
||||
|
||||
} {1 {database disk image is malformed}}
|
||||
db close
|
||||
file delete -force test.db
|
||||
|
||||
# try cipher_integrity_check on an in-memory database
|
||||
# which should fail because the file doesn't exist
|
||||
do_test memory-integrity-check-should-fail {
|
||||
sqlite_orig db :memory:
|
||||
execsql {
|
||||
PRAGMA key = 'testkey';
|
||||
CREATE TABLE t1(a,b);
|
||||
INSERT INTO t1(a,b) values (1,2);
|
||||
PRAGMA cipher_integrity_check;
|
||||
}
|
||||
} {{database file is undefined}}
|
||||
db close
|
||||
|
||||
# try cipher_integrity_check on a valid 1.1.8 database
|
||||
# should fail because version 1.0 doesn't use HMAC
|
||||
do_test version-1-integrity-check-fail-no-hmac {
|
||||
file copy -force $sampleDir/sqlcipher-1.1.8-testkey.db test.db
|
||||
sqlite_orig db test.db
|
||||
execsql {
|
||||
PRAGMA key = 'testkey';
|
||||
PRAGMA cipher_compatibility = 1;
|
||||
PRAGMA cipher_integrity_check;
|
||||
}
|
||||
} {{HMAC is not enabled, unable to integrity check}}
|
||||
db close
|
||||
file delete -force test.db
|
||||
|
||||
# try cipher_integrity_check on a valid 2 database
|
||||
do_test version-2-integrity-check-valid {
|
||||
file copy -force $sampleDir/sqlcipher-2.0-le-testkey.db test.db
|
||||
sqlite_orig db test.db
|
||||
execsql {
|
||||
PRAGMA key = 'testkey';
|
||||
PRAGMA cipher_compatibility = 2;
|
||||
PRAGMA cipher_integrity_check;
|
||||
}
|
||||
} {}
|
||||
db close
|
||||
file delete -force test.db
|
||||
|
||||
# try cipher_integrity_check on a corrupted version 2 database
|
||||
do_test version-2-integrity-check-invalid {
|
||||
file copy -force $sampleDir/sqlcipher-2.0-le-testkey.db test.db
|
||||
hexio_write test.db 8202 00
|
||||
hexio_write test.db 10250 00
|
||||
sqlite_orig db test.db
|
||||
execsql {
|
||||
PRAGMA key = 'testkey';
|
||||
PRAGMA cipher_compatibility = 2;
|
||||
PRAGMA cipher_integrity_check;
|
||||
}
|
||||
} {{HMAC verification failed for page 9} {HMAC verification failed for page 11}}
|
||||
db close
|
||||
file delete -force test.db
|
||||
|
||||
# try cipher_integrity_check on a valid version 3 database
|
||||
do_test version-3-integrity-check-valid {
|
||||
file copy -force $sampleDir/sqlcipher-3.0-testkey.db test.db
|
||||
sqlite_orig db test.db
|
||||
execsql {
|
||||
PRAGMA key = 'testkey';
|
||||
PRAGMA cipher_compatibility = 3;
|
||||
PRAGMA cipher_integrity_check;
|
||||
}
|
||||
} {}
|
||||
db close
|
||||
file delete -force test.db
|
||||
|
||||
# try cipher_integrity_check on a corrupted version 3 database
|
||||
do_test version-3-integrity-check-invalid {
|
||||
file copy -force $sampleDir/sqlcipher-3.0-testkey.db test.db
|
||||
hexio_write test.db 8202 00
|
||||
hexio_write test.db 10250 00
|
||||
sqlite_orig db test.db
|
||||
execsql {
|
||||
PRAGMA key = 'testkey';
|
||||
PRAGMA cipher_compatibility = 3;
|
||||
PRAGMA cipher_integrity_check;
|
||||
}
|
||||
} {{HMAC verification failed for page 9} {HMAC verification failed for page 11}}
|
||||
db close
|
||||
file delete -force test.db
|
||||
|
||||
# try cipher_integrity_check on a valid version 4 database
|
||||
do_test version-4-integrity-check-valid {
|
||||
file copy -force $sampleDir/sqlcipher-4.0-testkey.db test.db
|
||||
sqlite_orig db test.db
|
||||
execsql {
|
||||
PRAGMA key = 'testkey';
|
||||
PRAGMA cipher_integrity_check;
|
||||
}
|
||||
} {}
|
||||
db close
|
||||
file delete -force test.db
|
||||
|
||||
# try cipher_integrity_check on a corrupted version 4 database
|
||||
do_test version-4-integrity-check-invalid {
|
||||
file copy -force $sampleDir/sqlcipher-4.0-testkey.db test.db
|
||||
# corrupt page data
|
||||
hexio_write test.db 5120 00
|
||||
# corrupt iv
|
||||
hexio_write test.db 12208 00
|
||||
# corrupt the mac segment
|
||||
hexio_write test.db 16320 00
|
||||
sqlite_orig db test.db
|
||||
execsql {
|
||||
PRAGMA key = 'testkey';
|
||||
PRAGMA cipher_integrity_check;
|
||||
}
|
||||
} {{HMAC verification failed for page 2} {HMAC verification failed for page 3} {HMAC verification failed for page 4}}
|
||||
db close
|
||||
file delete -force test.db
|
||||
|
||||
# try cipher_integrity_check on a corrupted version 4 database
|
||||
do_test version-4-integrity-check-invalid-last-page {
|
||||
file copy -force $sampleDir/sqlcipher-4.0-testkey.db test.db
|
||||
hexio_write test.db 978944 0000
|
||||
sqlite_orig db test.db
|
||||
execsql {
|
||||
PRAGMA key = 'testkey';
|
||||
PRAGMA cipher_integrity_check;
|
||||
}
|
||||
} {{page 240 has an invalid size of 2 bytes}}
|
||||
db close
|
||||
file delete -force test.db
|
||||
|
||||
# verify cipher_integrity_check works on a plaintext header db
|
||||
do_test integrity-check-plaintext-header {
|
||||
sqlite_orig db test.db
|
||||
set rc {}
|
||||
|
||||
execsql {
|
||||
PRAGMA key = 'test';
|
||||
PRAGMA cipher_plaintext_header_size = 32;
|
||||
CREATE TABLE t1(a,b);
|
||||
INSERT INTO t1(a,b) VALUES (1,2);
|
||||
}
|
||||
|
||||
lappend rc [execsql {
|
||||
PRAGMA cipher_integrity_check;
|
||||
}]
|
||||
|
||||
lappend rc [string equal [hexio_read test.db 16 5] "1000010150"]
|
||||
|
||||
hexio_write test.db 120 00
|
||||
hexio_write test.db 5120 00
|
||||
|
||||
lappend rc [execsql {
|
||||
PRAGMA cipher_integrity_check;
|
||||
}]
|
||||
} {{} 1 {{HMAC verification failed for page 1} {HMAC verification failed for page 2}}}
|
||||
file delete -force test.db
|
||||
|
||||
# verify database locking for cipher_integrity_check
|
||||
do_test integrity-check-locking {
|
||||
sqlite_orig db test.db
|
||||
sqlite_orig db2 test.db
|
||||
|
||||
execsql {
|
||||
PRAGMA key = 'test';
|
||||
CREATE TABLE t1(a,b);
|
||||
BEGIN EXCLUSIVE;
|
||||
INSERT INTO t1(a,b) VALUES (1,2);
|
||||
}
|
||||
|
||||
execsql {
|
||||
PRAGMA key = 'test';
|
||||
PRAGMA cipher_integrity_check;
|
||||
} db2
|
||||
} {{unable to lock database}}
|
||||
sqlite_orig db test.db
|
||||
sqlite_orig db2 test.db
|
||||
file delete -force test.db
|
||||
|
||||
finish_test
|
|
@ -48,5 +48,6 @@ slave_test_file $testdir/sqlcipher-rekey.test
|
|||
slave_test_file $testdir/sqlcipher-plaintext-header.test
|
||||
slave_test_file $testdir/sqlcipher-rekey.test
|
||||
slave_test_file $testdir/sqlcipher-pragmas.test
|
||||
slave_test_file $testdir/sqlcipher-integrity.test
|
||||
|
||||
finish_test
|
||||
|
|
Loading…
Reference in New Issue