I have an issue with SQLCipher db encryption and CoreData: When I use persistent store coordinator with SQLCipher, it always crash with fault one-to-many relationship after first app relaunch. So when I first time launch the app, I create NSManagedObjects with relationships, then, when I save db, and reopen the app, it crash when I try to access to these relationship. Without SQLCipher everything works fine.
Here is the code for SQLCipher persistent store initialize:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (!_persistentStoreCoordinator) {
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MyApp.sqlite"];
NSDictionary *options = @{EncryptedStorePassphraseKey: @"MyApp",
EncryptedStoreDatabaseLocation: storeURL};
NSError *error;
_persistentStoreCoordinator = [EncryptedStore makeStoreWithOptions:options managedObjectModel:[self managedObjectModel] error:&error];
if (error) {
NSLog(@"%@", error);
}
}
return _persistentStoreCoordinator;
}
Code where I create NSManagedObject:
- (id)createObjectWithClassName:(NSString *)name
{
NSManagedObject *object = [[NSClassFromString(name) alloc] initWithEntity:[NSEntityDescription entityForName:name inManagedObjectContext:self.context] insertIntoManagedObjectContext:self.context];
return object;
}
Finally I find the answer by myself.
I investigate different cases, and figured, that issue happens only in my Data Model.
Problem was that I have one property in NSManagedObject class with name "index".
Looks like SQLCipher internally use such property and there was conflicts with it. Once I rename it to another name, everything works!
With SQLCipher make sure you have a brand new SQLite database. Trying to pragma the database with a key while it already has data for some reason just tries to decrypt it.
ATTACH DATABASE 'encrypted.db' AS encrypted KEY 'secret'; -- create a new encrypted database
CREATE TABLE encrypted.t1(a,b); -- recreate the schema in the new database (you can inspect all objects using SELECT * FROM sqlite_master)
INSERT INTO encrypted.t1 SELECT * FROM t1; -- copy data from the existing tables to the new tables in the encrypted database
DETACH DATABASE encrypted;
--
//For persistentStoreCoordinator:
// Give modelName = @"MyApp.sqlite";
-(NSPersistentStoreCoordinator *)persistentStoreCoordinator:(NSString*)modelName
{
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSString *docs = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
@"PushNoticationModal.sqlite"
NSURL *storeUrl = [NSURL fileURLWithPath:[docs stringByAppendingPathComponent:modelName]];
NSError *error = nil;
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
NSError *error;
persistentStoreCoordinator = [EncryptedStore makeStoreWithOptions:options managedObjectModel:[self managedObjectModel] error:&error];
if (error) {
NSLog(@"%@", error);
}
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
NSLog(@"persistentStoreCoordinator Error: %@,%@",error,[error userInfo]);
}
return persistentStoreCoordinator;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With