4

I'm using FMDB to work with sqlite and I'd prefer to avoid a dependency on SQLCipher. How can I simply leverage the DataProtection capability built into iOS? Is this possible - the only requirement is to protect the data in the event of the phone being stolen.

If the phone is unlocked with a PIN, it's fine that the user could access the DB - it's their data.

ConfusedNoob
  • 9,826
  • 14
  • 64
  • 85

2 Answers2

5

Look for the line where you do databaseWithPath: (or initWithPath:), then add:

FMDatabase *db = [FMDatabase databaseWithPath:path];

NSDictionary *attributes = @{NSFileProtectionKey: NSFileProtectionCompleteUnlessOpen};
NSError *error;
BOOL success = [[NSFileManager defaultManager] setAttributes:attributes
                                                ofItemAtPath:path
                                                       error:&error];
if (!success) {
    NSLog(@"File protection failed: %@", error);
}

The possible Values for the NSFileProtectionKey key are:

  • NSFileProtectionNone: The file has no special protections associated with it. It can be read from or written to at any time.
  • NSFileProtectionComplete: The file is stored in an encrypted format on disk and cannot be read from or written to while the device is locked or booting.
  • NSFileProtectionCompleteUnlessOpen: The file is stored in an encrypted format on disk. Files can be created while the device is locked, but once closed, cannot be opened again until the device is unlocked. If the file is opened when unlocked, you may continue to access the file normally, even if the user locks the device. There is a small performance penalty when the file is created and opened, though not when being written to or read from. This can be mitigated by changing the file protection to NSFileProtectionComplete when the device is unlocked.
  • NSFileProtectionCompleteUntilFirstUserAuthentication: The file is stored in an encrypted format on disk and cannot be accessed until after the device has booted. After the user unlocks the device for the first time, your app can access the file and continue to access it even if the user subsequently locks the device.

The right type of protection may depend on the version of iOS (the last two are not available on iOS 4) and whether you use your database when the device is locked.

eik
  • 2,104
  • 12
  • 15
  • Does this mean the file is NOT encrypted if the user has not specified a device PIN then? – Oli Feb 08 '14 at 23:55
3

By far the easiest way is to turn on Data Protection for the entire app. Go to App IDs, click "Edit" and set "Sharing and Permissions" to "Complete Protection."

enter image description here

Update Xcode with your new app id information, and from there on, it'll be handled for your app automatically.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Thanks, is it possible to use Data Protection for the specific sqlite file? – ConfusedNoob Aug 24 '13 at 18:04
  • Yes, using `[NSFileManager setAttibutes:]` with `NSFileProtectionKey : NSFileProtectionComplete`. See page 18 of this preso: https://github.com/rnapier/practical-security/blob/master/Practical%20Security.pdf. – Rob Napier Aug 24 '13 at 19:24
  • @RobNapier if I use your approach and turn on Data Protection for the entire app, do I need to set `NSFileProtectionKey : NSFileProtectionComplete` on the sqlite database file? And will background access with background context in Core Data work? – mrd May 08 '15 at 15:53
  • @mradlmaier If you turn on app-wide data protect, then you do not have to also set the protection key (unless it's been set to something else). You will be able to access the file in the background, but not when the device is locked. If you need to do so, you'll need to use "Protected Unless Open" for either that file or app-wide. – Rob Napier May 08 '15 at 16:10
  • So I had to enable Data Protection in the App ID, AND ADDITIONALLY use "Protected Unless Open" on my Core Data file and background access will be enabled, and Core Data encrypted? How can I know if the device is locked? – mrd May 08 '15 at 16:14
  • Again, not "background access" but "access to files that were open when the device was locked." Device locking is orthogonal to background. You'll be notified of data protection changes via the notifications `UIApplicationProtectedDataDidBecomeAvailable` and `UIApplicationProtectedDataWillBecomeUnavailable`. – Rob Napier May 08 '15 at 16:21
  • @RobNapier oic. So device locking refers to the sqlite database becoming unavailable and background access refers to access from different threads, which would be possible? – mrd May 08 '15 at 19:57
  • All "Complete" files will be encrypted when the device locks (i.e. the user must reenter their PIN). "background" "different threads" "other processes" or anything else that isn't "the device locks" is not relevant to data protection. All "Protected Unless Open" files will be encrypted if they are not currently open at the time that the device locks. Otherwise they will remain unencrypted. – Rob Napier May 08 '15 at 20:10
  • @RobNapier Will iOS Data Protection set in the provisioning profile work with synchronisation with iCloud? – mrd May 11 '15 at 10:12
  • It looks like you have several questions that other SO users will be interested in. You should ask them as questions so future readers can find them. – Rob Napier May 11 '15 at 12:05
  • @RobNapier posted that question here: http://stackoverflow.com/questions/30171001/will-ios-data-protection-set-in-the-provisioning-profile-work-with-synchronisati – mrd May 11 '15 at 14:55
  • @RobNapier - For NSFileProtectionComplete, you are saying all the "complete" files will be encrypted, does it mean that the if the .sqlite file is not "complete" that will also not get encrypted? I have this setup and the app level Data Protection using the new provisioning profile, still can't get the encryption to work. I have posted my question here, I'd really appreciate it if you could take a look : http://stackoverflow.com/questions/39151959/nsfileprotectioncomplete-doesnt-encrypt-the-core-data-file – EmbCoder Aug 27 '16 at 12:57