【问题标题】:FMDB & SQLCipher not encryptingFMDB & SQLCipher 未加密
【发布时间】:2013-01-16 23:20:59
【问题描述】:

在 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;

}

【问题讨论】:

    标签: ios fmdb sqlcipher


    【解决方案1】:

    通过添加对问题进​​行排序

    [database setKey:@"B!GSecret"];
    

    在每个数据库打开语句之后。

    【讨论】:

      【解决方案2】:

      由于这是 google 通常带人去的地方,如果有人在加密已经存在的未加密数据库时遇到问题,经过痛苦的研究,我能够弄清楚如何去做,并创建了一个教程:

      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 中设置了 2 个参数,DATABASE 和 KEY。 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"];
          ...
      }];
      

      如果您有任何问题,请告诉我!

      【讨论】:

      • 请在此处包含教程的相关部分。仅包含链接的答案通常是不可接受的,因为链接往往会消失。
      • @gmogames guilmo.com/fmdb-with-sqlcipher-tutorial 你的链接坏了,如果它被移动到任何其他存储库,你能告诉我们吗
      • @DheerajJami 我正在更改服务器,DNS 应该很快就会传播并且链接将恢复工作。
      • @gmogames 谢谢!
      • @gmogames 你能告诉我它仅用于数据库密码保护还是表格的每个数据都像base63或二进制一样加密格式?
      【解决方案3】:

      除了来自@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
          // ...
      }
      

      【讨论】:

        猜你喜欢
        • 2017-01-30
        • 2015-11-09
        • 1970-01-01
        • 2016-11-09
        • 2013-08-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多