Hello Team,
I already have a live app on apple app-store which is using CoreData. Now I want to encrypt my coredata using sqlcipher.
For that I am using EncryptedCoreData (https://github.com/project-imas/encrypted-core-data).
I am successfully able to implement the same with my project and it working fine for fresh installed applications but it is creating issue when I am trying to update my application over the app which is using normal coredata (without encryption).
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
else if (!storeUrl)
return nil;
NSError *error = nil;
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
NSDictionary *options = @{ EncryptedStorePassphraseKey : @"123456",
EncryptedStoreFileManagerOption : [EncryptedStoreFileManager defaultManager],
NSMigratePersistentStoresAutomaticallyOption : @YES
};
NSPersistentStore *store = [persistentStoreCoordinator_
addPersistentStoreWithType:EncryptedStoreType
configuration:nil
URL:storeUrl
options:options
error:&error];
if (!store && error)
{
[self encryptDB:[storeUrl absoluteString] url:storeUrl];
NSError *error1 = nil;
NSPersistentStore *store1 = [persistentStoreCoordinator_
addPersistentStoreWithType:EncryptedStoreType
configuration:nil
URL:storeUrl
options:options
error:&error1];
}
return persistentStoreCoordinator_;
}
//encryptDB used for encriptt the existing DB with password
- (void)encryptDB:(NSString*)path_u url:(NSURL*)url
{
sqlite3 *unencrypted_DB;
sqlite3 *encrypted_DB;
NSString *tempFile = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]
stringByAppendingPathComponent:@"encrypted.sqlite"];
NSURL *tempUrl = [NSURL fileURLWithPath:tempFile];
if (sqlite3_open([path_u UTF8String], &unencrypted_DB) == SQLITE_OK) {
NSLog(@"Database Opened");
// Attach empty encrypted database to unencrypted database
NSString *strEncryptedPath = [NSString stringWithFormat:@"ATTACH DATABASE '%@' AS encrypted KEY '123456';",tempFile];
sqlite3_exec(unencrypted_DB, [strEncryptedPath UTF8String], 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);
int version = [self queryUserVersion:unencrypted_DB];
sqlite3_close(unencrypted_DB);
NSLog (@"End database copying");
if (sqlite3_open([tempFile UTF8String], &encrypted_DB) == SQLITE_OK) {
const char* key = [@"123456" UTF8String];
sqlite3_key(encrypted_DB, key, (int)strlen(key));
[self setVersion:encrypted_DB version:(int)version];
}
sqlite3_close(encrypted_DB);
NSError *error = nil;
[[NSFileManager defaultManager] removeItemAtURL:url error:&error];
BOOL result = [[NSFileManager defaultManager] moveItemAtURL:tempUrl toURL:url error:&error];
if(!result)
NSLog(@"Error: %@", error);
}
else {
sqlite3_close(unencrypted_DB);
//NSAssert1(NO, @"Failed to open database with message '%s'.", sqlite3_errmsg(unencrypted_DB));
}
}
-(void)setVersion: (sqlite3*) db version:(int)version {
// get current database version of schema
static sqlite3_stmt *stmt_version;
if(sqlite3_prepare_v2(db, "PRAGMA user_version;", -1, &stmt_version, NULL) == SQLITE_OK) {
while(sqlite3_step(stmt_version) == SQLITE_ROW) {
db = sqlite3_bind_int( stmt_version, 1, version ); // Bind first parameter.
}
} else {
NSLog(@"%s: ERROR Preparing: , %s", __FUNCTION__, sqlite3_errmsg(db) );
}
sqlite3_finalize(stmt_version);
}
-(int)queryUserVersion: (sqlite3*) db {
// get current database version of schema
static sqlite3_stmt *stmt_version;
int databaseVersion;
if(sqlite3_prepare_v2(db, "PRAGMA user_version;", -1, &stmt_version, NULL) == SQLITE_OK) {
while(sqlite3_step(stmt_version) == SQLITE_ROW) {
databaseVersion = sqlite3_column_int(stmt_version, 0);
NSLog(@"%s: version %d", __FUNCTION__, databaseVersion);
}
NSLog(@"%s: the databaseVersion is: %d", __FUNCTION__, databaseVersion);
} else {
NSLog(@"%s: ERROR Preparing: , %s", __FUNCTION__, sqlite3_errmsg(db) );
}
sqlite3_finalize(stmt_version);
return databaseVersion;
}
Following code I am using for fetch the existing data
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"HistoryEvent" inManagedObjectContext:dbDataFile.managedObjectContext];
[request setEntity:entity];
NSMutableArray* andPredicateArray = [[NSMutableArray alloc] init];
if (guid)
{
[andPredicateArray addObject:
[NSPredicate predicateWithFormat:@"guid = %@", guid]];
}
NSPredicate* predicate = [NSCompoundPredicate andPredicateWithSubpredicates:andPredicateArray];
[request setPredicate:predicate];
[request setFetchLimit:limit];
NSMutableArray* sortDescriptors = [[NSMutableArray alloc] init];
[sortDescriptors addObject:
[[NSSortDescriptor alloc] initWithKey:@"creationDate" ascending:[isAscendingCreationDatesNum boolValue]]];
[request setSortDescriptors:sortDescriptors];
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[dbDataFile.managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (!mutableFetchResults && errorMessage && error)
{
NSLog(@"Error to fetch”); //I am not getting any error here
}
return mutableFetchResults; //Count is zero
here I am getting empty array.
I don’t know what is the wrong with this code.
Code is working fine If I installed the fresh application and creating the DB.
but when I am trying to override the existing application I am not getting any data.