Data Protection on iOS Apps

04 April, 2018

Data Protection on iOS Apps

  Data protection secures user data using built-in encryption hardware. Every file stored on an iOS device has one of the four data protection types, which determine when the file can be read from and written to. These protection types can be set either with an entitlement or programmatically. These are:
  • NSFileProtectionComplete:
    The file is only accessible while the device is unlocked. When the device is locked your app will receive a UIApplicationProtectedDataWillBecomeUnavailable notification, and will lose access to protected files 10 seconds later. Use this if possible, but not if you need to access the file while running in the background.
  • NSFileProtectionCompleteUnlessOpen:
    While the device is locked, files can still be created and already open files can be accessed. Use this for completing a task in the background that requires you to save new data or update a data.
  • NSFileProtectionCompleteUntilFirstUserAuthentication:
    The file can be accessed any time after the user enters their passcode once after the device has booted, even when the device is locked. Use this if you need to read the file while running in the background.
  • NSFileProtectionNone:
    The file can always be accessed. The system needs to use this in some places but your app probably doesn’t.
If you try to access a file when it is protected, the operation will fail with either NSFileReadNoPermissionError (code 257) or NSFileWriteNoPermissionError.

Setting a Default Protection Level

CompleteUntilFirstUserAuthentication has been default from iOS 7.
The default protection level for files created in your app or extension’s container is determined by the entitlement, which is shown as ‘Data Protection’ in Xcode. You need to set this for the app and all extensions. There are two caveats to bear in mind.
  • This entitlement needs to be set before the app is installed.
  • Since the entitlement only applies to your app or extension’s container, you need to set the protection level for a shared container programmatically.
Setting the entitlement Xcode project settings -> Capabilities -> turn on Data Protection. This will add a data protection entitlement to your app’s entitlements file (creating it if it does not exist) with the entitlement’s value set to NSFileProtectionComplete. It will also enable data protection on your App ID in the Certificates, Identifiers & Profiles section of the Apple developer website.
You need to follow the steps for NSFileProtectionComplete,then change the protection level in both the entitlements file and on your App ID in the Certificates, Identifiers & Profiles section of the Apple developer website. These two values must be manually kept in sync otherwise you’ll see an error when building about invalid entitlements.The place to navigate to on the website is: Identifiers > App IDs > (the app ID) > Edit > Data Protection > Sharing and Permissions. This can be set to one of the three protection levels (but not NSFileProtectionNone).The key expected in the entitlements file is NSFileProtectionCompleteUnlessOpen.Then update provisioning profile.
You can’t make this the default because there is no option for this in the Certificates, Identifiers & Profiles section of the Apple developer website.

Setting a Protection Level Programmatically

If your app is already installed on users’ devices without the entitlement set and you want something other than NSFileProtectionCompleteUntilFirstUserAuthentication, you’ll need to set the protection type programmatically, both to protect new files and upgrade existing ones. Note that you don’t need to set the entitlement to use these APIs. Setting a Protection Level for a Particular File there are several APIs that accept a protection type as an option. If you’re writing a new file from Data/NSData, use try data.write(to: fileURL, options: .completeFileProtection) For an existing file you can use either NSFileManager/FileManager or NSURL: try FileManager.default.setAttributes([.protectionKey: FileProtectionType.complete], ofItemAtPath: fileURL.path) // or // cast as NSURL because the fileProtection property of URLResourceValues is read-only try (fileURL as NSURL).setResourceValue(URLFileProtection.complete, forKey: .fileProtectionKey) With Core Data you can pass the protection type when adding the persistent store: try persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: [NSPersistentStoreFileProtectionKey: FileProtectionType.complete]) Setting a Protection Level for New Files in a Directory, you can use the FileManager/NSFileManager or NSURL API as above with a directory URL instead of a file URL, or pass the protection attribute when creating the directory try FileManager.default.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: [.protectionKey: FileProtectionType.complete] You can then create files in the directory as normal.

Changing the Protection Level for All Existing Files in a Directory

When you set the protection level of a directory, the protection level of existing files in that directory does not change. You’ll need to set the protection level for every file in the directory. This can be done with FileManager.DirectoryEnumerator/NSDirectoryEnumerator: guard let directoryEnumerator = FileManager.default.enumerator(at: directoryURL, includingPropertiesForKeys: [], options: [], errorHandler: { url, error -> Bool in print(error) return true }) else { print("Could not create directory enumerator at \(directoryURL.path)") return } // NSEnumerator is not generic in Swift so we have to deal with Any. for urlAsAny in directoryEnumerator { do { try (urlAsAny as! NSURL).setResourceValue(URLFileProtection.complete, forKey: .fileProtectionKey) } catch { print(error) } }
Note: 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. A protected file is accessible only when a device is unlocked.

So What's Next ?

Our pricing starts from as low as $5K

Why wait when now is the right time to build your app and chase your dream?


Guaranteed response from our experts within 1 hour.
Okay to contact me