Nick Harris

Core Data and Enterprise iPhone Applications – Protecting Your Data

Introduction

NewsGator’s primary software offering is a product called Social Sites which basically adds social networking aspects to Microsoft SharePoint. My role in this product is to create the iOS device apps that interact with the server. My app is pulling in a lot of data that an enterprise customer considers *very* sensitive so data protection is the first thing many CIOs ask about when considering Social Sites. This post is to layout both how iOS protects data on the device so our prospective clients have a better idea about how it works, along with some additional steps developers can take to further protect their data.

Much of what I’ll discuss was covered in Session 209 at WWDC, but since that information is under NDA, I’ll stick to information that’s available in the public domain (including this post about iPhone 3GS and this post about iOS4). But if you have access to the WWDC videos, Session 209 is a great resource.

Data Encryption Starting with iPhone 3GS

Social Sites uses Core Data with a SQLite store type for storage and persistence. When the app first runs, it creates a Social_Sites.sqlite database file in its sand boxed documents directory on the device file system.

With the 3GS, any data written to the filesystem is encrypted using hardware encryption. By simply creating the Social_Sites.sqlite file on the file system, the data stored in it is already encrypted. This encryption also allows for the Social Sites data to be instantaneously unavailable when you use Remote Wipe. I say unavailable because the remote wipe doesn’t actually overwrite the encrypted data on the filesystem, but instead overwrites the hardware key used to encrypt/decrypt it. But still, the important thing is that the data on disk is encrypted.

This type of data encryption is also used on the current iPads.

Data Encryption on iOS 4

The way hardware encryption works on iOS4 has been greatly improved. I can’t find any public document from Apple that explains the improvements in detail, but their iOS 4: Understanding data protection support page gives a hint with “Data protection enhances the built-in hardware encryption by protecting the hardware encryption keys with your passcode.” I’ll just say that hardware data encryption on the 3GS and iPad use a single hardware encryption key. The WWDC session goes into great detail about the under the hood improvements. The main takeaway for a CIO though is that the Social Sites sqlite datafile on iOS4 has stronger encryption than it did in the past.

Further Protection – NSFileProtectionComplete

In iOS4, Apple introduced data protection. It gives you the ability to encrypt the hardware keys used to encrypt your files and to erase those keys when the system is locked – leaving your file unreadable until the phone is unlocked and the keys are regenerated.

This level of protection is not built in by default though. The user has to enable it (or an IT department can enable it and force users to have it on) and your code must set an attribute on your Core Data sqlite store as well.

Steps for the user to enable data protection are outlined on the iOS 4: Understanding data protection support page. You need to have the passcode turned on since this is what the system will use to generate the encryption for the keys.

As a developer, you need to set the NSFileProtection level of your sqlite store to NSFileProtectionComplete (by default it will be NSFileProtectionNone). You can do this right after you instantiate your persistent store coordinator:

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    if (persistentStoreCoordinator != nil) {
        return persistentStoreCoordinator;
    }

    NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"Social_Sites.sqlite"];
    NSURL *storeUrl = [NSURL fileURLWithPath:storePath ];

    NSError *error = nil;
    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error]) {
        // Handle error
    }

    if(RSRunningOnOS4OrBetter())
    {
        NSDictionary *fileAttributes = [NSDictionary dictionaryWithObject:NSFileProtectionComplete forKey:NSFileProtectionKey];
        if (![[NSFileManager defaultManager] setAttributes:fileAttributes ofItemAtPath:storePath error:&error]) {
            // Handle error
        }
    }

    return persistentStoreCoordinator;
}

BOOL RSRunningOnOS4OrBetter(void) {
    static BOOL didCheckIfOnOS4 = NO;
    static BOOL runningOnOS4OrBetter = NO;

    if (!didCheckIfOnOS4) {
        NSString *systemVersion = [UIDevice currentDevice].systemVersion;
        NSInteger majorSystemVersion = 3;

        if (systemVersion != nil && [systemVersion length] > 0) { //Can't imagine it would be empty, but.
            NSString *firstCharacter = [systemVersion substringToIndex:1];
            majorSystemVersion = [firstCharacter integerValue];			
        }

        runningOnOS4OrBetter = (majorSystemVersion >= 4);
        didCheckIfOnOS4 = YES;
    }
    return runningOnOS4OrBetter;
}

Considerations

If your application needs your Core Data store in any background processing, then you cannot use data protection. Any attempt to access files that are NSFileProtectionComplete will cause an exception.

There are application delegates applicationProtectedDataWillBecomeUnavailable and applicationProtectedDataDidBecomeAvailable as well as notifications UIApplicationProtectedDataWillBecomeUnavailable and UIApplicationProtectedDataWillBecomeAvailable that you can use to determine what state your protected data is in.

You could then in theory keep unprotected data in memory in your background processing then write it into your Core Data store when protected data becomes available again.

You can find more information in the iPhone Application Programming Guide.

Conclusions

My answer to any CIO asking would be to ensure any device using Social Sites be a 3GS, an iPad or an iPhone 4. I would also encourage enforcing passcode and data protection for any device running iOS4. These steps ensure that the SQLite data store for Social Sites is hardware encrypted with remote wipe capabilities and further protected with iOS4 and data protection.

UPDATE:
Here’s the link to the iPhone Configuration Utility 3.0 which can be used to “create, maintain, encrypt, and install configuration profiles, track and install provisioning profiles and authorized applications, and capture device information including console logs.”

Written by Nick Harris

July 14, 2010 at 8:23 pm

Posted in Code, Core Data

Tagged with ,

30 Responses

Subscribe to comments with RSS.

  1. Assuming systemVersion is in the form x.y, why not use [[systemVersion componentsSeparatedByString:@”.”] objectAtIndex:0] to grab the first component/major version? Granted, it’s probably a while until version 10 rolls around and breaks this, but you never know.

    It’s a shame so little information about this is publicly available.

    Jesper

    July 14, 2010 at 9:44 pm

  2. Actually, I’ll do that one better. Since NSString’s doubleValue method uses non-localized parsing, you could use that to extract an x.y format much easier.

    Jesper

    July 14, 2010 at 9:46 pm

    • You could get a string like 3.1.2 though. But your suggestion about componentsSeperatedByString is a better implementation.

      Nick Harris

      July 14, 2010 at 9:54 pm

      • It’s safer to assume that the function will be long gone before iOS 10.0 than it is to assume that the separator will always be a . character.

        Are we sure it’s not localized? Are we sure there won’t be a bug or a change where the separator is a , character instead? I’ve certainly seen x,y,z (like in Apple’s system profiler).

        Brent Simmons

        July 15, 2010 at 4:09 am

      • Hey guys, take a look my post on runtime version checking http://forr.st/~mOO

        Michael Waterfall

        July 15, 2010 at 6:39 am

      • Oh, and also thanks for the great article, I didn’t know about this new feature! Haven’t had a chance to wade through the hours of WWDC videos just yet! Cheers!

        Michael Waterfall

        July 15, 2010 at 6:41 am

  3. Why don’t just check whether NSFileProtectionComplete is available at runtime rather than guessing its availability based on system version?


    if (& NSFileProtectionComplete)

    Andreas Amann

    July 15, 2010 at 4:15 pm

  4. I glanced at the code. Please nothing bit. Approprtiate {left no contentions}

    Kevin Baynes

    September 15, 2010 at 2:45 pm

  5. Did they actually fix the horribly broken implementation from iOS 3? It seems like since you can know actually encrypt the hardware keys with your passcode maybe iPhone encryption could become somewhat useful. I’ll wait until some security professionals comment on it, though. In the meantime DO NOT use encryption on the iPhone pre-iOS 4. It’s as bad as no encryption at all.

    Mike

    September 23, 2010 at 8:09 pm

  6. Hi,

    thank you for this nice article.
    But why don’t you use:

    #ifdef __IPHONE_4_0
    // code goes here
    #endif

    instead of:
    BOOL RSRunningOnOS4OrBetter(void) {…}

    ?

    regards
    René

    Rene Pardon

    January 3, 2011 at 9:32 am

    • René, the RSRunningOnOS4OrBetter method is a runtime check, whereas #ifdef __IPHONE_4_0 is resolved at compile time. This runtime check will enable the same executable to run on various versions of iOS and have different functionality in each of them.

      Michael

      January 3, 2011 at 11:30 am

  7. I tested this in my application and then proceeded to download the sqlite database using organizer and found that none of the data was encrypted. When I downloaded the data was it decrypted? How can I see the data encrypted on the device just to sooth my soul?

    Chris

    March 10, 2011 at 1:21 am

    • The data doesn’t actually get encrypted anymore than usual (all files on disc are encrypted). Instead there are keys that allow the OS access to that data. Since you did the backup you presumably had to enter your PIN. That gave the OS the keys it needed to get to the file.

      Nick Harris

      June 14, 2011 at 7:08 pm

  8. If you already have an iPhone app in the App Store that uses Core Data with a database, will there be a need to include some type of migration-like code if we set NSFileProtection to NSFileProtectionComplete in an app update? Will the users’ existing database cause a crash with the updated app?

    iDevice

    June 12, 2011 at 2:39 am

    • I don’t believe so. The data isn’t actually encrypted anymore than it normally is. But there’s an extra layer of security where the OS creates keys to access that data based on your PIN. So moving to this configuration in a new build will put that new security layer in while leaving all the data intact.

      Nick Harris

      June 14, 2011 at 7:10 pm

      • After some experiments – if I connect my iPad to computer, start ITunes a backup everything, the “protected” files end in my filesystem without encryption even if my iPad is locked the whole time.

        Ondrej Hanslik

        September 2, 2011 at 6:52 pm

  9. No one is ever going to say anything about the message *EVERYONE* sees when they try to submit their apps:

    > Does it contain encryption? File legal papaers for exporting.

    Does this “built-in Apple encryption” apply????

    Donna

    June 20, 2011 at 3:27 pm

  10. will the protected file stay encrypted if the user has not specified a passcode on the device?

    vinay sharma

    February 10, 2012 at 6:10 pm

  11. It is important to have a sensible idea for the application and employ a reliable coder for that development portion. An individual will be done with this specific, it is simple to offer the app upon …iPhone App

  12. I have followed the steps as outlined in this post and even with the device passcode locked, I am still able to access my .sqllite file using a tool called iExplorer……Am I missing something?

    John OS

    December 7, 2012 at 10:55 am

    • So can I. There appears to be no protection at all for the database file. Does anyone have a solution to this?

      Marian

      March 11, 2014 at 2:00 pm

      • Are you inspecting the database on the actual device or in the simulator? If you are inspecting the database in the simulator, last I knew the simulator does not encrypt.

        Paul

        March 11, 2014 at 11:33 pm

      • I’m inspecting the database on the device. I used iExplorer to inspect the file system of my app, locate the database file and export it to a folder on my desktop. I was able to open the database using Firefox SQLite Manager and read the contents. There was no encryption.

        Marian

        March 14, 2014 at 12:00 pm

  13. thanks

    incataloguevn

    March 21, 2013 at 9:02 am

    • Hey im getting this error , could you help me out

      Error Domain=NSCocoaErrorDomain Code=260 “The operation couldn’t be completed. (Cocoa error 260.)” UserInfo=0x56ee00 {NSFilePath=file://localhost/var/mobile/Applications/11CB4293-000B-4D62-A25C-797AD2C7356C/Documents/MQIRApp.sqlite, NSUnderlyingError=0x56ed80 “The operation couldn’t be completed. No such file or directory”}

      Dhiraj Kumar

      May 6, 2013 at 11:17 pm

  14. Hi im getting an error while excuting your line of code , could you tell me why

    Error Domain=NSCocoaErrorDomain Code=260 “The operation couldn’t be completed. (Cocoa error 260.)” UserInfo=0x56ee00 {NSFilePath=file://localhost/var/mobile/Applications/11CB4293-000B-4D62-A25C-797AD2C7356C/Documents/MQIRApp.sqlite, NSUnderlyingError=0x56ed80 “The operation couldn’t be completed. No such file or directory”}

    Dhiraj Kumar

    May 6, 2013 at 11:16 pm

  15. I’m developing an iOS 6 app with core data and an SQLite DB. I added the NSFileProtectionComplete attribute in my persistentStoreCoordinator similar to above, but I receive an exception (“The operation couldn’t be completed. No such file or directory”). I assume that’s because the DB isn’t being created until the first save. That would not explain why it would work above but not in my code. How can the DB be forced to be created, so that this attribute can be applied? Otherwise, when can this setting actually be applied if not here, do I need to detect when the first is first created in the save code? That seems laborious. Here’s a code snippet:

    – (NSPersistentStoreCoordinator *) persistentStoreCoordinator
    {
    if (_persistentStoreCoordinator != nil)
    {
    return _persistentStoreCoordinator;
    }

    NSURL * storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent : @”WML.sqlite”];

    NSError * error = nil;

    NSDictionary * options = [NSDictionary dictionaryWithObjectsAndKeys : [NSNumber numberWithBool: YES],
    NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool: YES], NSInferMappingModelAutomaticallyOption, nil];

    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel : [self managedObjectModel]];

    if (![_persistentStoreCoordinator addPersistentStoreWithType : NSSQLiteStoreType configuration : nil URL : storeURL options : options error : &error])
    {
    abort();
    }

    NSDictionary * fileAttributes = [NSDictionary dictionaryWithObject : NSFileProtectionComplete forKey : NSFileProtectionKey];

    if (![[NSFileManager defaultManager] setAttributes : fileAttributes ofItemAtPath : [storeURL absoluteString] error : &error])
    {
    abort();
    }

    return _persistentStoreCoordinator;
    }

    Charlie C.

    June 18, 2013 at 12:36 am

  16. Setting NSFileProtectionComplete for NSFileProtectionKey after addPersistentStoreWithType:configuration:URL:options:error: has no effect, i.e., the default setting (NSFileProtectionCompleteUntilFirstUserAuthentication) is applied, which is less secure.

    The correct approach is to set NSFileProtectionComplete for NSPersistentStoreFileProtectionKey (note that this key is specific to the persistent store) in a dictionary passed for the options parameter…

    http://stackoverflow.com/questions/5165391/iphone-sqlite-encryption-data/24315838#24315838

  17. For any future readers, this information isn’t 100% correct. See: http://www.hopelessgeek.com/2014/10/10/core-data-and-data-protection/

    Oz

    March 16, 2015 at 11:30 pm


Comments are closed.