I'm using Airdrop to transfer application internal data between two phones. Because Airdrop was intended for file sharing, it could occur that user choose "save the file" to save the data file in Files app by accident. Since my app is a financial planning app, I'm considering to encrypt the file transferred by Airdrop to keep user's data secure. The encryption only applies to the temp file transferred by Airdrop. Once the app on the receiver phone receivers it, it decrypts the file immediately.
I'm referring to this thread to determine how I should answer the export compliance question if I encrypt the temp file. And I noticed these two exemption items:
(iii) your app uses, accesses, implements or incorporates encryption with key lengths not exceeding 56 bits symmetric, 512 bits asymmetric and/or 112 bit elliptic curve
(iv) your app is a mass market product with key lengths not exceeding 64 bits symmetric, or if no symmetric algorithms, not exceeding 768 bits asymmetric and/or 128 bits elliptic curve.
I don't quite understand the difference between the conditions in the two items (what is a mass market product?). But I don't think either helps, because the ciphers provided by iOS Cryptokit contains only AES and ChaChaPoly - the former takes a minimum key size of 128 bits and the latter takes 256 bits key size.
Since there are a lot of apps using Airdrop to transfer application internal data (I can tell that from the discussions on SO), I wonder how other people deal with this? Is this considered an exemption case?
BTW, I considered other options, but none is satisfying:
Don't encrypt the data. Obscure it instead (for example, using something like Caesar cipher). But that feels very unprofessional.
Don't use Airdrop. Implement my own data transfer mechanism. For example, start a tiny web server on sender side and the receiver side get the data through HTTPS, which from my understanding is an exemption case. I don't choose this approach because a) Airdrop provides a much better user experience than this approach, b) I'll need to use Bonjour to discover service, which requires local network permission. I'd like to avoid that if possible.
The answer depends on what cipher you use to encrypt the data.
Apple summarises your requirements in a couple of documents.
First, in the CryptoKit documentation
Typically, the use of encryption that’s built into the operating system—for example, when your app makes HTTPS connections using URLSession—is exempt from export documentation upload requirements, whereas the use of proprietary encryption is not. To determine whether your use of encryption is considered exempt, see Determine your export compliance requirements.
This leads you to this document which has a table, that I have shown in part:
Assuming that you use AES from Apple's Crypto Kit framework, the second clause would apply. You don't need to provide any documentation to Apple but you should submit a self classification report to the us government.
The exemptions you listed in your question do not apply since you wouldn't use a symmetric cipher with a key length of 64 or 56 bits.
I'm still in the very early stages of a game, and I am saving information using a KeyChain wrapper class someone made. I wanted to ask for some advice early on, since I have time to change my approach.
My game has the potential to persist a fair amount of data about the player and what they've done, such as:
how much gold the player has
what items they've acquired (you can get about 50 items)
what skills, spells, and abilities they've chosen for their character
what experience level they are, max health, stats, etc
The reason I decided to store this in KeyChain was that I was told it's encrypted and much more difficult to tamper with. I felt there were other solutions such as the ones below, but I wrote some potential reasons why that might not be good:
Make everything web-based, and stored in a database somewhere on my server - I want my game to be playable offline
Use a local database (FMDB, let's say) - I could use a tool to edit the values directly, and give myself more health, etc.
Use Core Data - Never used this before, not sure if this is the same ease of tampering as #3?
GameCenter - Never used this before, so not sure what the lift is
NSPreferences - Preferences are more easily tampered with (i've used a tool to change the values pretty quickly)
So I am not sure if i'm completely wrong above, but let's say there is some degree of truth there and KeyChain is a good approach. The problem is now what if I want to then somehow allow the player to pick up a new device and pick up where they left off? How on earth would I serialize all that data I'm saving in keychain? I don't mind creating a giant JSON document of the values, and sending it along somewhere (where? to GameCenter?)
Any advice / pointers in the right direction would be good, especially now since i'm in the early stages and can make changes to step back.
Thanks so much everyone appreciate your time!
A few thoughts based on lessons learned (usually, "the hard way") that may (or may not) be helpful. :)
I see three requirements in your post: offline play (requiring local storage), data security (which is a massive topic in and of itself) and synchronization.
Playable offline:
Thus you need some sort of local storage. Keychain, Core Data, SQL, NSPreferences are all options. I don't know the limitations of the Keychain, so not really sure how suitable it is for continuous read/write of large chunks of data.
Data security:
They keychain protects your secrets when you're not logged in, and partitions them between apps. https://developer.apple.com/library/content/documentation/Security/Conceptual/keychainServConcepts/02concepts/concepts.html and http://evgenii.com/blog/sharing-keychain-in-ios/ give more details. That should prevent other tools from modifying other app's content on non-jailbroken devices.
Core Data, SQL, et al will be inside your app's container, which makes it harder for other tools to access on non-jailbroken devices. There's a good description here: https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html
NSPreferences doesn't offer any security that I'm aware of. Plus, if they jailbreak the device, they basically have root access on a linux machine and can probably do anything they want.
In today's security world, the mantra is generally, "assume breach." As in, assume if they want in bad enough, they're going to find a way in. Thus you need to think about other layers of defense: partitioning your secrets so compromised secrets have limited value, encryption at rest and encryption in transit. Obfuscating the data before you write it/transmit is therefore another layer of defense (although they may still edit it and you'll have to handle potential garbage values).
You can chase security pretty far down the rabbit hole; you'll have to decide where the cost outweighs the benefit, and/or what risks you intend to defend against.
Synchronization across devices:
Thus you need a syncing solution. the iCloud Keychain syncs between devices, so if the keychain meets your storage needs, this probably will meet your sync needs, too. Again, I'm not sure if there are size or frequency-of-update constraints. I haven't used this, but this SO answer gives more info: https://stackoverflow.com/a/32606371/1641444. Based on Apple's docs (https://support.apple.com/en-us/HT204085) it looks like the user does have to enable syncing for this to work.
Otherwise, Apple provides GameCenter and CloudKit. Or you could explore 3rd party options. I've used GameCenter and CloudKit to sync data across devices. CloudKit wins over GameCenter, IMO, no contest.
With GameCenter, you gain multiplayer matchmaking and channels to share data between users. But, you have to adhere specifically to its structure which is IMO both extremely frustrating to work with and limited in functionality. Check the GameCenter and GKTurnBasedMatch tags here on SO for a taste of the problems.
CloudKit is a lower-level solution. It allows you to store a wide variety of data objects in iCloud and "subscribe" to change notifications. All data is contained within a container for the app, and has a "private" (user-specific) section and a public (shared by all users of the app) section. After watching the introductory WWDC videos on CloudKit, I was successfully sync'ing user settings between devices AND different users on different devices in no time. However, if you want some of the multiplayer features of GameCenter, you'll have to build the data model/subscriptions yourself. Since you support offline play, you'd need to save your data to a local storage solution and periodically upload it to iCloud for sync.
Conclusion (aka TL;DR)
So, my opinion is: none of the tools individually meet all three of your requirements, and you'll end up rolling your own solution for at least 1 req, regardless of which option you go for. In my multiplayer game, I'm trusting in Apple's filesystem (containers) to provide sufficient data security, I'm using a local storage option within the app's container, and I'm periodically writing NSData objects to cloudKit for synchronization across devices. I hit my frustration limit with GameCenter and pulled it from my app.
Star for a good question!!
I'm doing something similar with this. Right now, I'm using UserDefaults for primary storage. When I need to transfer data, I can save it to iCloudKit, or I could export it as a plist or json to use with AlamoFire, email, etc.
As for actually storing the data, I saw you mentioned CoreData.. that is kind of overkill! Look at NSCoder and NSKeyedArchiver.
Personally, I make my own save/load functions that manipulate dictionaries, then toss them into a UserDefaults key.
An example hierarchy of how I store dicts in UserDefaults (there are many ways to go about this)
Key:
Items->Equipment->Weapons->WeaponName
Value:
{ dictionary of data like AP, Cost, etc }
This to me is easier than using NSCoder, and certainly easier than CoreData!! The goal is to turn everything into a dictionary, which you can then easily put into UserDefaults, which allows you to easily create plists or save to the cloud.
With the above key system, you basically just do for loops to find what you need, parsing out each section.. so a function to display all equipment, you just load the entire UserDefaults.standard.dictionaryRepresentation, then search for keys that only have 'Items->Equipment' and so on.
Hope this helps!
I have some functions from my game I could share if you need more tips.
UPDATE:
If you are making this an online game, I would focus on learning the essentials of persistence and cloud usage first, then port it to a more secure platform that uses encryption.
Your best bet will be to create your own servers and transfer data that way. That will give you exactly what you want, when you want it, and with the security that you want.
If you want to use GameCenter, I would use GC as an in-between layer of something custom you created, so that way you can filter out the cheaters' scores / have more flexibility.
I have an sqlite table and some audio in my iOS application that I have put a lot of work and effort into, but looking through iFile or any other browser based application I can easily find these files and do whatever I want with them. If I can do this then someone else and more malicious than myself would be able to do the same.
How can I obfuscate my files while keeping them usable?
What you need to do depends on who you are protecting them from.
Using NSData "Data Protection" will protect the file only wheb the iDevice is locked—at best but is a step up.
Another method is to encrypt them with a key which you save in the keychain. on an iPhone 6s can encrypt 1Mb in 6ms, an iPhone 4s in 30 ms (using Common Crypto), so there is really no noticible speed degradation. A good candidate for this is a 3rd party library: RNCryptor, it handes many details needed to do this right. The attacker will have to be more than a cyrious user, this may meet your needs.
You need to define the attacker you are protecting against ranging from a curious kid to a well funded government.
Depending on how hard you want to make it, just hash all filenames so people can't see them. if thats too easy encrypt them ... I have an answer here on SO that details how to do this
I am developing an App which will download some images from a server and save it on user's device. But what I am really concerned about is that these images should not be easily accessible by other apps or THE USER.
One approach could be that my App encrypts the images and saves them in the documents directory and decrypts them when required, but I think that it would make loading the images into UIImageView considerably slow.
There are many games which don't include large resources into their App-bundle to keep the App-size small and download the heavy resources later.
Where exactly do they save those resources?
And how do they secure them from being copied very easily from the directory where they are stored?
Probably because of trying to secure the files from the user the best option is to encrypt them with AES and saving them in the user area, Documents or Library directory or subdirectory thereof.
You are better off using Common Crypto. If RNCryptor suits you needs use it, it uses Common Crypto under the hood. Otherwise there is plenty of sample code for encrypting using Common Crypto here on SO.
Key the key should be random bytes as is the iv, save the key in the Keychain. Use AES in CBC mode with PKCS7 padding.
If you really want good security hire a cryptographic domain expert, the overall security is not trivial to get right. Don't forget the server and at a minimum use two factor authentication to it.
The decryption time should not be a problem, much faster that coming from a server.
We are developing a game where all the game logic is executed locally (no server back-end) and would like to make it difficult to tamper with game data (such as user credits, game settings and so on).
Now, it's even possible on non-jailbroken devices to access the filesystem and change game data - so, for example if user inventory stats are stored in a plist file, it's very easy to edit them.
If we move game settings from plist files to source-code files, such that they get compiled into the binary, it will require at least a modification of the binary to change settings. On non-jailbroken phones - will modified binaries still run, or does the apple codesigning prevent from modifying the binaries in any way?
What are some quick and easy to implement measures to make it a bit harder to tamper with game-data (especially on non-jailbroken phones. Optimally we'd like to provide some kind of security that will at least require a jailbreak to make modifications to the game)?
so - to summarize the questions:
can the binary part of an iOS app be modified and still run on non-jailbroken devices?
what are some quick and easy to implement measures to make it harder to tamper with gamedata on non-jailbroken devices?
You can't modify the binary as it would invalidate the signature. I would just use some sort of encryption on the data you don't want users to modify. You can make this as simple or as complex as you want. I don't think iOS provides any kind of encryption services out of the box, but you don't need to go hog wild with it - a simple ROT13 algorithm would do, since we're not talking about password-level security here. If you want, you can even add a checksum on the encrypted data, then invalidate it if the checksums don't match.
To answer your questions:
No. The application will be required to be signed again.
A simple but not unbreakable measurement is to safe the data in a secure container (key chain for example) or encrypt it yourself before you safe it to disk. An attacker now have to monitor a running app to get to the decrypted data in memory - or need to crack the secure store.
There are a few ways on iOS (and Mac OS X) where you can accomplish to encrypt and decrypt data. One way is pretty nicely described here in the official docs:
Encrypting and Decrypting Data.