Password protecting files in NSDocumentsDirectory - ios

Hi I asked a question earlier and could not get a perfect answer for it.
So let me ask this question once more, I have a requirement where I will be password protecting all my files in the NSDocumentsDirectory with a key that will be pushed from a server every day. What is the best way to do it without taking a hit on performance.
I would also be doing the key refresh whenever a key expires and I should re-encrypt or re-protect all my files in the directory. I would be storing the key from server using iOS keychain.
I tried NSFileManager's File Protection Values but I could not use my own key there.
I saw all this
http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/AdvancedAppTricks/AdvancedAppTricks.html
What are the new "iOS data protection APIs"?
What are the new "iOS data protection APIs"?
Secure contents in Documents directory
http://iphonedevelopment.blogspot.in/2009/02/strong-encryption-for-cocoa-cocoa-touch.html
http://pastie.org/426530
NSFileProtectionComplete for iOS 4.0 apps
and did not know how to proceed. So please guys any help would be of great use. Any sample or good way to implement or any one has done something like this before.
Thanks a ton, in advance.

Related

Do users have access to the Documents directory in an iOS sandbox?

I'm saving data that keeps track of a users virtual purchases inside the Documents directory of the app's sandbox. For obvious reasons I don't want the user to have access to this file or be able to manipulate it.
Is this the proper directory for storing these files? If not where can I store files that can not be accessed by the user?
I did find this link from Apple that suggests that data such as this should be stored in the Library directory. It doesn't seem to say if it's secure from users accessing it though.
I'm not an iOS security expert, however, I can share my experience of working with users data on iOS. Any corrections/remarks are appreciated.
Generally speaking, the best recommendation would be to store important user's data remotely (i.e. having a server backend or using iCloud) with SSL-protected connection. However, if you are forced to store data locally for some reason, here are some recommendations:
1) Do not ever save important data in Documents directory or in NSUserDefaults as is. It's pretty easily accessible for user even on non-jailbroken devices. For instance, you can check iExplorer: as far as I remember, it does the trick.
2) If you really need to store some data locally, whatever your choice is: Documents folder, UserDefaults or CoreData, you have to encrypt it. Algorithm choice is up to you, but it's better to use some iOS built-in solution for it.
3) The data encryption assumes having a key for your app to decrypt it. The best way to store your key is KeyChain. Probably, that is the only place where you can store keys and other stuff like user's authorization data with no worries of being stolen from the outside.
Eventually, after all these steps your user's encrypted data can still be accessible by user. One won't be able to read it unless it is encrypted, but having access to the own keychain and some skill, an advanced user can finally get the original data. Moreover, it still can be damaged. So, in terms of saving data from being damaged or removed you still need to store backups or the data itself somewhere remotely.
You should treat data in the Documents directory as public. Anyone with an iOS device hooked up to a computer via USB using a tool such as iExplorer or iFunBox can view the contents of your application's Documents and Caches directory. For safety, consider using the keychain (if applicable), or a web service which validates the receipt (shared secret, user information, etc) to make sure that the user actually purchased the product, and isn't trying to spoof a transaction.

Is secure save some sensitive data in Localizable.strings?

My question is very clear. I need save some sensitive static data. For example, the url of my service or a password of encrypt. Now I have the next doubt: Is secure save this data in Localizable.strings?
No. A malicious user can easily see this in the IPA of an iTunes backup. But the user can also see this in any file in your app bundle. You will need to encrypt the string somehow. The tricky part is to hide the key as well: it may be a good idea to calculate the key somehow (you can be creative here).
Also pay attention to secure your transmission: if you would be using plain HTTP anyone who can use Wireshark would be able to see your sensitive information. Make sure you've set up HTTPS correctly and that you are validating the certificate of the server on connect (search StackOverflow about that).
I totally agree with #DarkDust. Just to add more things:
A malicious user can see the data because he does the jailbreak on one of the devices. Then he installs the app and may get whole contents of the app. He may change some code and run it.
Whole process of getting the data is called reverse engineering. It's quite wide branch and it's good to know the basics if you care about data security.
You may read more about reverse engineering at e.g. this free book: https://github.com/iosre/iOSAppReverseEngineering.
The best hacker always gets the data, it's just the matter of time. For you, as a developer, the task is to forbid getting the data for less experienced "hackers".
To make things more difficult, you can obfuscate the data.
If you need to save some credentials in app (eg login token), always use the keychain, never any other storage.

Building a secure anonymous uploader

I want to build a website in which people can upload files to my S3 bucket via a rails app. I want the upload to be encrypted so that I have no knowledge of what is being uploaded and I want only the user to have the key to decrypt it.
Could someone give me some suggestions on how to go about this or some methods of achieving this?
You can only encrypt it localy, everything else on the serverside (or even the ISP) can be manipulated somehow what is delivered
Lichtamberg is right, the best and most secure way would be for the user to do it clientside. Perhaps you could tell them what encryption types are accepted (such as GPG) and provide instructions for doing so, or recommend tools that might make it easier.
You could probably enforce this in your code by checking whether an uploaded file is encrypted, and rejecting it if not. The check would be similar to an image upload feature that rejects non-image files, for instance.

Secure keys in iOS App scenario, is it safe?

I am trying to hide 2 secrets that I am using in one of my apps.
As I understand the keychain is a good place but I can not add them before I submit the app.
I thought about this scenario -
Pre seed the secrets in my app's CoreData Database by spreading them in other entities to obscure them. (I already have a seed DB in that app).
As the app launches for the first time, generate and move the keys to the keychain.
Delete the records from CoreData.
Is that safe or can the hacker see this happening and get those keys?
*THIRD EDIT**
Sorry for not explaining this scenario from the beginning - The App has many levels, each level contains files (audio, video, images). The user can purchase a level (IAP) and after the purchase is completed I need to download the files to his device.
For iOS6 the files are stored with Apple new "Hosted Content" feature. For iOS5 the files are stored in amazon S3.
So in all this process I have 2 keys:
1. IAP key, for verifying the purchase at Apple IAP.
2. S3 keys, for getting the files from S3 for iOS5 users:
NSString *secretAccessKey = #"xxxxxxxxx";
NSString *accessKey = #"xxxxxxxxx";
Do I need to protect those keys at all? I am afraid that people will be able to get the files from S3 with out purchasing the levels. Or that hackers will be able to build a hacked version with all the levels pre-downloaded inside.
Let me try to break down your question to multiple subquestions/assumption:
Assumptions:
a) Keychain is safe place
Actually, it's not that safe. If your application is installed on jailbroked device, a hacker will be able to get your keys from the keychain
Questions:
a) Is there a way to put some key into an app (binary which is delivered form AppStore) and be completely secure?
Short answer is NO. As soon as there is something in your binary, it could be reverse engineered.
b) Will obfuscation help?
Yes. It will increase time for a hacker to figure it out. If the keys which you have in app will "cost" less than a time spend on reverse engineering - generally speaking, you are good.
However, in most cases, security through obscurity is bad practice, It gives you a feeling that you are secure, but you aren't.
So, this could be one of security measures, but you need to have other security measures in place too.
c) What should I do in such case?*
It's hard to give you a good solution without knowing background what you are trying to do.
As example, why everybody should have access to the same Amazon S3? Do they need to read-only or write (as pointed out by Kendall Helmstetter Gein).
I believe one of the most secure scenarios would be something like that:
Your application should be passcode protected
First time you enter your application it requests a user to authenticate (enter his username, password) to the server
This authenticates against your server or other authentication provider (e.g. Google)
The server sends some authentication token to a device (quite often it's some type of cookie).
You encrypt this token based on hash of your application passcode and save it in keychain in this form
And now you can do one of two things:
hand over specific keys from the server to the client (so each client will have their own keys) and encrypt them with the hash of your application passcode
handle all operation with S3 on the server (and require client to send)
This way your protect from multiple possible attacks.
c) Whoooa.... I don't plan to implement all of this stuff which you just wrote, because it will take me months. Is there anything simpler?
I think it would be useful, if you have one set of keys per client.
If even this is too much then download encrypted keys from the server and save them in encrypted form on the device and have decryption key hardcoded into your app. I would say it's minimally invasive and at least your binary doesn't have keys in it.
P.S. Both Kendall and Rob are right.
Update 1 (based on new info)
First of all, have you seen in app purchase programming guide.
There is very good drawing under Server Product Model. This model protects against somebody who didn't buy new levels. There will be no amazon keys embedded in your application and your server side will hand over levels when it will receive receipt of purchase.
There is no perfect solution to protect against somebody who purchased the content (and decided to rip it off from your application), because at the end of days your application will have the content downloaded to a device and will need it in plain (unencrypted form) at some point of time.
If you are really concerned about this case, I would recommend to encrypt all your assets and hand over it in encrypted form from the server together with encryption key. Encryption key should be generated per client and asset should be encrypted using it.
This won't stop any advanced hacker, but at least it will protect from somebody using iExplorer and just copying files (since they will be encrypted).
Update 2
One more thing regarding update 1. You should store files unencrypted and store encryption key somewhere (e.g. in keychain).
In case your game requires internet connection, the best idea is to not store encryption key on the device at all. You can get it from the server each time when your app is started.
DO NOT store an S3 key used for write in your app! In short order someone sniffing traffic will see the write call to S3, in shorter order they will find that key and do whatever they like.
The ONLY way an application can write content to S3 with any degree of security is by going through a server you control.
If it's a key used for read-only use, meaning your S3 cannot be read publicly but the key can be used for read-only access with no ability to write, then you could embed it in the application but anyone wanting to can pull it out.
To lightly obscure pre-loaded sensitive data you could encrypt it in a file and the app can read it in to memory and decrypt before storing in the keychain. Again, someone will be able to get to these keys so it better not matter much if they can.
Edit:
Based on new information you are probably better off just embedding the secrets in code. Using a tool like iExplorer a causal user can easily get to a core data database or anything else in your application bundle, but object files are somewhat encrypted. If they have a jailbroken device they can easily get the un-encrypted versions but it still can be hard to find meaningful strings, perhaps store them in two parts and re-assemble in code.
Again it will not stop a determined hacker but it's enough to keep most people out.
You might want to also add some code that would attempt to ask your server if there's any override secrets it can download. That way if the secrets are leaked you could quickly react to it by changing the secrets used for your app, while shutting out anyone using a copied secret. To start with there would be no override to download. You don't want to have to wait for an application update to be able to use new keys.
There is no good way to hide a secret in a piece of code you send your attacker. As with most things of this type, you need to focus more on how to mitigate the problem when the key does leak rather than spend unbounded time trying to protect it. For instance, generating different keys for each user allows you to disable a key if it is being used abusively. Or working through a intermediary server allows you to control the protocol (i.e. the server has the key and is only willing to do certain things with it).
It is not a waste of time to do a little obfuscating. That's fine. But don't spend a lot of time on it. If it's in the program and it's highly valuable, then it will be hacked out. Focus on how to detect when that happens, and how to recover when it does. And as much as possible, move that kind of sensitive data into some other server that you control.

what's an alternative to use instead of a CommonCrypto on iphone?

Getting ready to submit my app to the Apple's Itunes store and got puzzled by a question during the submission process: "Export laws require that products containing encryption be properly authorized for export...... Does your product use encryption?"
I've used CommonCrypto CommonCryptor.h to encode settings file against its unauthorized modifications.
So now I'm not sure if I have to remove all the encryption completely and leave just an xml file basically as is or should I use some other method to protect the file.
What other simple protection mechanisms I can use to protect it and at the same time do not use any encryption so I can submit my app without tons of extra paperwork?
Your use of "encryption" is not subject to US export rules because it's not for "information security" (I think you answer "yes, yes, yes, no" or so, ICBW, or they could have changed the order). Essentially, if it doesn't stop the NSA from spying on you, they're happy to let you use it.
However, encryption traditionally provides confidentiality, not message integrity. If you want to ensure that the user hasn't tampered with the settings file (e.g. by editing the iPhone backup), just save it with a MAC. That is,
Generate a MAC key (pull some bytes out of /dev/random).
Calculate the MAC of the file when you save it (see Objective-C sample code for HMAC-SHA1; note that the accepted answer is actually HMAC-SHA-256)
Append the MAC to the end of the file (or set it as a file attribute, or stick it in another file).
When reading, calculate the MAC on the file and verify that it's the one you saved. If it's appended to the file, you'll have to remove the last few bytes (e.g. [NSData dataWithContentsOfFile:path], then -subdataWithRange: twice to get the "message" and MAC, then verify the MAC, and parse the "message" if verification succeeds.
It won't stop someone with a jailbroken phone from extracting the MAC key from your binary, but not much will. It also won't stop someone from reading the plaintext settings file, but that might not be such a problem.
If you're generating the file on a computer you control (e.g. it's a file downloaded from a server), then sign it. Technically, RSA signature validation is equivalent to encryption, but I don't think it counts as encryption for export purposes (if it does, it's for "authentication" purposes and still doesn't count). DSA signature validation isn't encryption (I think, the math behind it went way over my head) and should also be fine.

Resources