I have an application that stores data locally on the iPhone.
I want to encrypt data so i am confused which method should i use.
I have used Core Data framework in application.
NSFileManager (NSFileProtectionKey), CoreData (NSFileProtectionKey), NSData (NSDataWritingOptions) are the options or is there some other method as well.
Please suggest me something
Thanks
Use the Keychain Service.
But you need to now that to encrypt the data you need a private key or a passphrase.
I would then say, encryption make only sense, when the user needs to authenticate when using your application. Then you could encrypt the data with the entered password.
Here you could AES256 encrypt data with the a PBKDF2 like function for generating a encryption key (thanks to Robert).
But providing a code sample would go to far. Read in yourself! :)
But also know: since iOS 4 the "disk" space is already encrypted with the Device PIN!
Related
I have been using Google Keyczar for encrypting data in my JAVA app. And I want to change the crypto solution to Google Tink.
But the problem is the already encrypted data by Keyczar. Can I decrypt them by Tink?
If yes, I want to change the crypto solution from Keyczar to Tink. If no, I have to think about another solution.
Thank you.
I did it.
Keyczar is using AES. So I use TinyAES.
Keyczar is also using HMAC. So I use HMAC of avr-crypto-lib.
Just one thing is I have to extract the key from Keyczar key.
I must save a string (a passphrase) in the keychain but the original string:
doesn't come from the server;
is not generated by the user;
it must be compared on a server (I send it over https);
So, the string must live somewhere in the app (hardcoded?).
I'm quite sure you can't prepare data for the keychain to be readily available for the app after it is installed, like you can just add a plist to the app bundle so that it can be loaded right away if the app is running (even if it's the first time it gets launched).
I have read about Data Protection: it allows applications that work with sensitive data to take advantage of encryption available on some devices. Is that the way to go? That is: I store my data into a text file, then I protect the file, then I retrieve my data from the file, then I save it to the keychain?
Any tip is appreciated.
If it is not possible to provide the string from outside (user input, a server) developer is forced to put it in the application bundle in some form. It can be hardcoded, stored in a file, or generated by a function. It means application has all necessary information to get/produce such a string. Thus it is not able to secure the information as good as encryption would do.
iOS apps are protected by Apple's DRM, so you can feel safe if someone copies your binary to Mac and starts disassembling it. However, if hacker has a jailbroken device there are tools to dump your application binary from memory to disk, unfortunately.
So it boils down to obfuscation. You could write a function that generates the string dynamically (e.g. a series of operations on hardcoded array of bytes and then convert it to the string). This will make your string harder to intercept by the hacker.
As main concern is with paraphrase or access token, it can be saved as encrypted data in keychain but this will be decrypted whenever we will send a request & it can be tracked on jailbroken devices.But using more agnostic algos to encrypt request data will increase API response time.However defining user based permissions at server side is best way as in worst case only 1 user's data can be tracked.
SSL Pinning - using challenge response authentication, we can prevent app from man in the middle attack. Yes, ssl pinning can be bypassed but it's not that easy & only possible on jailbroken devices.
Defining expiry time to few seconds could be another way to prevent user's data.Identifying source of request is also very important before granting permissions..
So by collaborating multiple ways we can try to make better system.
EDIT
Generally we encrypt data using 1 key as token & it can be decrypted once that key is revealed.
Asymmetric Encryption adds 1 more layer of encryption using public & private keys.
https://developer.apple.com/library/content/documentation/Security/Conceptual/Security_Overview/CryptographicServices/CryptographicServices.html#//apple_ref/doc/uid/TP30000976-CH3-SW12
here is one more example where random salt is used over token to encode data https://en.wikipedia.org/wiki/PBKDF2
Variants of this question have been discussed on SO a bunch of times already, and unfortunately you won't find a perfect answer, as there isn't one.
Essentially, you want to ship authentication credentials in your app, i.e. you bundle a secret into it. This means that no matter what you do, there's a possibility that an attacker retrieves it via reverse engineering. Even if you encrypt it with a hard algorithm that is technically secure enough, at some point your app decrypts it and since the app might be in the hands of an attacker, they will be able to sniff the secret.
This means in the end you can only try to make it hard for them by basically obfuscating the way in which you handle the secret ("make sniffing complicated"). Bundling an encrypted file that gets decrypted and then packed into the keychain seems not like a bad idea to me for a start, but keep in mind that for somebody looking at your app, especially on a jailbroken iPhone, this vanishing file can be a good first hint. Also, deleting it doesn't really help, as one re-install easily restores it.
Another idea could be to use On-Demand Resources to distribute your secret, this might also make it easier to replace it with an updated version in case your secret gets compromised. I am not that familiar with on-demand resources myself, though, so I can't tell you how suited they would be for actually revoking things.
This all assumes that you have no way of implementing an authentication mechanism based on user input. That way an attacker could only steal their own password (assuming they don't steal someone else's iPhone...) and not a vital part of your entire app (which could potentially affect all users).
Other SO answers from my bookmarks that might help you are these:
https://stackoverflow.com/a/9183066/710041
https://stackoverflow.com/a/9448821/710041
Okay, after re-reading your last comment under the question again, here's a concrete suggestion. I don't know why you need this second password/token at all if you're already having user authentication (you talk about them logging in), but here you go:
You don't bundle a token/pass together with the app at all. When first running your app, user's have to log in anyways (if I got you right), so your server can be involved and this is where you start.
During this login, the server generates a token/password and will send this to the user (depending on your exact implementation/custom protocol this might be done in a second request/response done by the app that uses the same user credentials or you put it into the headers of the response to the very first request sent by the app). Note that you don't need to encrypt this as long as you use https, as this already encrypts this data. So the channel by which your token arrives within your app is secure.
The app then saves this token/pass in the keychain immediately. This is as good encrypted as it gets on a mobile device. Do not save the token in anything else, even temporarily. The pass only ever exists in plain when it's in memory (you can't avoid that).
You use that token for whatever you need it (I am actually wondering why you need it if you're already using https and a user login system at all).
All in all this sounds like a pretty standard pseudo-OAuth-like token approach, if you're just wanting to use the token to avoid always relying on the user credentials (username and password) in each request. Technically you could also just save username and password in the keychain and always get those for each request. Usually these tokens have a limited time-to-live after which they become invalid anyways and the app has to rely on username and password again to get a new one anyways.
The potential downside of a token is if it's static and not user-bound or if it doesn't have this time-to-live limit. You would have to generate this in a clever way on the server and obviously note which user uses which token. That way you can pinpoint security breaches and react accordingly (instead of suddenly shutting down the server for all users by invalidating your one and only token). Again, I don't see why you need this, though.
Regarding a man-in-the-middle attack: A token, be it app-bundled (which is a risk in itself) or server generated, doesn't in itself protect against that. I have no idea what your boss would aim for here, but perhaps I'm missing some information. In general, https already protects you from this (well, usually only the server is authenticated, but if you already have a username and password system, you should be fine for the client side, too). It's actually a big point of it in general. To me this sounds more and more like something in your original problem is simply a misunderstanding of the existing infrastructure and/or a "boss-induced" problem... :)
What you can do is have your parameters encrypted using AES 256 encryption while calling an API, then the server decrypts the parameters and again sends encrypted response.You can decrypt and read the response, provided your server and app shares the same key used for encryption and decryption.
I had a similar functionality in my app so my Util class encrypts and decrypts the request and response using the following code,
class func encrypt (stringToEncrypt: String) -> String {
let messageData = stringToEncrypt.data(using: .utf8)
let encryptedBytes = try! AES(key: "abcdefghijklmnopqrstuvwxyz012345", iv: "abcdefghijklmost").encrypt([UInt8](messageData!))
return encryptedBytes.toBase64()!
}
class func decrypt ( message: String) -> String {
let messageData = Data(base64Encoded: message, options: .ignoreUnknownCharacters)
let decryptedBytes: [UInt8] = try! AES(key: "abcdefghijklmnopqrstuvwxyz012345", iv: "abcdefghijklmost").decrypt([UInt8](messageData!))
let unencryptedString = String(bytes: decryptedBytes, encoding: .utf8)
return unencryptedString!
}
Again this is just a suggestion you can do it using other ways also.
For saving some string values in Keychain you can make use of a pod library
pod 'SSKeychain'
You can save a string to keychain as follows
let appName = NSBundle.mainBundle().infoDictionary!["CFBundleName"] as! String
SSKeychain.setAccessibilityType(kSecAttrAccessibleAlways)
SSKeychain.setPassword(stringToSave, forService: appName, account: "MyAppName")
Also retrieve the same using
let appName = NSBundle.mainBundle().infoDictionary!["CFBundleName"] as! String
let stringRetrieved = SSKeychain.passwordForService(appName, account: "MyAppName")
Import these once you installed the above pod
import SystemConfiguration
import SSKeychain
This will be retained even if the app the deleted and re-installed. If you want additional encryption you can make use of any encryption algorithm this one is useful
AES encryption in swift
Encryption techniques may help to get solve the requirement. Here is the simple elaboration how we can maintain a keys on top of the Diffie–Hellman key exchange encryption techniques.
Prerequisites:
Maintain public and private key pairs on both the sides client and server.
Algorithm or logic to generate private keys should use same for both client and server end.
Logic to break the final acquire keys to compare the own string.
Process:
Both app and backend should have a common public key what ever it is in this case just take it as application name like MyApplication.
public key: MyApplication
Should generate private keys on the both the ends by using some encryption process or logic. For suppose generate random number as private key like below.
Suppose App private key is: 10
Suppose Backend private key is: 90
Generate exchange keys on both app and backend by following some kind of algorithm. Here just to combine both public and private keys like
App final key: MyApplication + 10
Backend final key: MyApplication + 90
Exchange the keys in between app and backend.
App Got key: MyApplication + 90
Backend Got key: MyApplication + 10
Compare the received key with own by using some kind of technique like
i. Generated new App key by combining app private key and App Got key like: MyApplication + 90 + 10
ii. Generated new Backend key by combining Backend private key and Backend Got key like: MyApplication + 10 + 90
To Check both the key are same need follow to logic For example here Just add last two number in the keys result will be like
App owned key: MyApplication + 100
App acquired key: MyApplication + 100
BackEnd owned key: MyApplication + 100
BackEnd acquired key: MyApplication + 100
Hola finally both backend and app has the same key.
Depends on the requirements needs maintain different private key per each session and store it on keychains. or make one private key and store it on app side.
NOTE: This description illustrates just an overview how to maintain the keys, It may involves lot of logics and also has a provision to break up the keys by others that totally depends on encryptions and logics using to generate and break the keys.
References:
https://en.wikipedia.org/wiki/Diffie-Hellman_key_exchange
https://security.stackexchange.com/questions/7390/how-to-properly-encrypt-a-communication-channel-between-a-client-and-a-server-w
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.
I would like to store encrypted data in my db as well as its signature so that I could read it back at another time. How do I store the symmetric key used for encryption safely?
Store it on the file system and never version track it!
I think I found the answer to my question here: Where do you store your secret key in a Java Web Application?
Please let me know if there's a better way of doing things.
TLDR: Store it on the file system.
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.