在Xcode中,我试图让FMDB使用SQLCipher来加密数据库。在我的项目中,我已经有一个SQLCipher的编译版本,我已经证明它正在通过sqlite3调用。我有一个单元测试创建数据库和1表然后插入一行。一切都可以使用FMDB,但数据库仍未加密。
-(id)initWithDatabaseFilename:(NSString*)filename{
NSString *databasePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]
stringByAppendingPathComponent: filename];
self.databasePath = databasePath;
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:databasePath]) {
database = [FMDatabase databaseWithPath:databasePath];
[database setLogsErrors:YES];
[database setTraceExecution:NO];
BOOL keyCheck = [database setKey:@"B!GSecret"];
NSLog(@"Database is encrypted: %d",keyCheck);
NSLog(@"database created");
} else {
NSLog(@"Didnt need to create database");
}
[self createTable];
return self;
}
-(void)createTable{
BOOL tableExists = [self.database tableExists:kTASKTableName];
if(!tableExists){
[database open];
[database executeUpdate:@"CREATE TABLE TEST(TEST_PK integer primary key autoincrement, TITLE text, OTHERTITLE text, TESTVAL text, COMPLETED integer, CREATION_DATE double)"];
[database close];
}
}
-(BOOL) addTasks:(NSArray*) tasks{
BOOL insertSuccess = NO;
if([self.databasePath isEqualToString:@""]){
NSLog(@"Database has not yet been initialized");
}
[database open];
for(TESTOBJ *to in tasks){
[database executeUpdate:@"insert into TEST(TITLE, OTHERTITLE, TESTVAL) VALUES (?,?,?)",
to.title,to.otherTitle,to.testVal,nil];
}
[database close];
return insertSuccess;
}
答案 0 :(得分:3)
通过添加
对问题进行排序[database setKey:@"B!GSecret"];
在每个数据库打开语句之后。
答案 1 :(得分:2)
由于这是谷歌通常会带人的地方,如果有人在加密现有的未加密数据库时遇到问题,经过痛苦的研究后,我能够弄清楚如何做到这一点并创建了一个教程:
http://www.guilmo.com/fmdb-with-sqlcipher-tutorial/
但最重要的部分是,打开现有数据库并附加新的加密数据库。然后在FMDB连接中设置密钥。
SQLCipher - 加密数据库
// Import sqlite3.h in your AppDelegate
#import <sqlite3.h>
// Set the new encrypted database path to be in the Documents Folder
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir = [documentPaths objectAtIndex:0];
NSString *ecDB = [documentDir stringByAppendingPathComponent:@"encrypted.sqlite"];
// SQL Query. NOTE THAT DATABASE IS THE FULL PATH NOT ONLY THE NAME
const char* sqlQ = [[NSString stringWithFormat:@"ATTACH DATABASE '%@' AS encrypted KEY 'secretKey';",ecDB] UTF8String];
sqlite3 *unencrypted_DB;
if (sqlite3_open([self.databasePath UTF8String], &unencrypted_DB) == SQLITE_OK) {
// Attach empty encrypted database to unencrypted database
sqlite3_exec(unencrypted_DB, sqlQ, NULL, NULL, NULL);
// export database
sqlite3_exec(unencrypted_DB, "SELECT sqlcipher_export('encrypted');", NULL, NULL, NULL);
// Detach encrypted database
sqlite3_exec(unencrypted_DB, "DETACH DATABASE encrypted;", NULL, NULL, NULL);
sqlite3_close(unencrypted_DB);
}
else {
sqlite3_close(unencrypted_DB);
NSAssert1(NO, @"Failed to open database with message '%s'.", sqlite3_errmsg(unencrypted_DB));
}
self.databasePath = [documentDir stringByAppendingPathComponent:@"encrypted.sqlite"];
请注意,我们在SQL Query,DATABASE和KEY中设置了2个参数。 DATABASE应该是要创建的加密数据库的完整路径,在本例中为字符串ecDB,KEY参数是用于加密数据库的密钥,因此请选择强大的
现在在你的FMDB功能上,每次打开数据库后都要调用 [db setKey:@“strongKey”] 。
// FMDatabase Example
FMDatabase *db = [FMDatabase databaseWithPath:[self getDatabasePath]];
[db open];
[db setKey:@"secretKey"];
// FMDatabaseQueue Exmple
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:[self getDatabasePath]];
[queue inDatabase:^(FMDatabase *db) {
[db setKey:@"secretKey"];
...
}];
如果您有任何疑问,请与我联系!
答案 2 :(得分:0)
除了来自@gmogames 的出色回答之外,请参阅下面的 Swift 示例,该示例展示了如何从头开始创建加密的 SQLCipher 数据库,而无需转换现有的未加密数据库。
诀窍是使用适当的 sqlite3_open(或 sqlite3_open_v2)命令创建文件,使用 sqlite3_key 设置密钥并填充关闭数据库之前(例如添加一个表就足够了)。如果在关闭数据库之前没有创建表或内容,则文件将为空(大小为 0)且未加密。
然后您可以使用 FMDB 打开新加密的数据库并使用 customerDB.setKey(secretKey) 设置密钥。
一个常见的错误是尝试使用 FMDB 从头开始创建加密数据库,并使用 customerDB.setKey(secretKey) 设置其密钥。此类程序适用于打开现有的加密 SQLCipher 数据库,但不适用于创建数据库。 SQLCipher加密数据库只能使用如下sqlite3命令创建,然后用FMDB打开。
var rc: Int32
var db: OpaquePointer? = nil
var databasePath: String = "" // Initialize to your database path
var secretKey: String = "Thisisasecretkey"
rc = sqlite3_open_v2((databasePath as NSString).utf8String, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_FULLMUTEX, nil)
if (rc != SQLITE_OK) {
let errmsg = String(cString: sqlite3_errmsg(db))
NSLog("Error opening database: \(errmsg)")
return
}
rc = sqlite3_key(db, secretKey, Int32(secretKey.utf8.count))
if (rc != SQLITE_OK) {
let errmsg = String(cString: sqlite3_errmsg(db))
NSLog("Error setting key: \(errmsg)")
}
// create a table to populate database and ensure it is saved in encrypted form
let sql = "CREATE TABLE IF NOT EXISTS TEST_TABLE (ID INTEGER PRIMARY KEY AUTOINCREMENT, INFO_TEXT TEXT default '');"
if (sqlite3_exec(db, sql, nil, nil, nil) != SQLITE_OK) {
print("error")
}
sqlite3_close(db)
print("encrypted db created")
// Now, we open the newly created encrypted database
customerDB = FMDatabase(path: databasePath)
if customerDB.open() {
// We set secret key
customerDB.setKey(secretKey)
// We perform needed operations on the database using FMDB requests
// ...
}