Storing encryption key within iOS app? - ios

I need to store an encryption key within my app, so that it can use the same key to encrypt and upload data, and download and decrypt data, from a public store. That way, the data can't be read by any other party in between.
What I'm concerned about is the potential for somebody to hijack my app. Once my app has been archived, would it be possible for someone to read a hardcoded encryption key held within the app?

If the key is in the app bundle there is a chance it can be discovered and doing this is not secure. As #Cristik states authenticate the user to the server and download the key at that point.
To secure the key the best you can do is to save the key in the Keychain.
Protecting against the owner of the device is very difficult and falls more under DRM.
Protecting against an non-owner depends on the owner having set a good passcode/password.
Protecting against data in transit (upload/download) is easy, use https, ensure the server is current (TLS 1.2 and Perfect Forward Secrecy) and pin the server certificate in the app.
Update:
In the ipa only the executable files are encrypted so other files can be accessed from the download. If a file is encrypted the attacker will need the encryption key and that can be strong: random bytes.
But the app needs the encryption key so the problem is how can the app know the key and not an attacker. Encryption does increase the work factor be the need to obtain the key.
There are disassemble tools so if the key is in the code it can be found by an experienced attacker.
If the key comes from a server it is not coded into the app so the work factor again increases. A MITM attack can be used to see the key in transit and pinning the certificate and using current https best practices can mitigate this attack vector.
Finally the key is in RAM memory at the time of decryption and can be found but again the work factor is increased.
In general what is necessary to protect data at the highest levels is complicated, requires special hardware and physical security.
Bottom line: determine the level of attacker you are defending against and the value of the data; code to that level. Do not underestimate the attacker.

Instead of storing the encryption key within the application bundle, you can request it from a server via a secure connection (HTTPS), and then save it in keychain for later retrieval.
You can add more security layers to the https connection by adding SSL pinning or/and other security measures.
Plus, you can generate different encryption keys every time the user logins, and if the store API supports it, you can invalidate all keys generated for a user if for example his phone is stolen.

Related

Storing encrypted version of user's email password on my app's server

I'm working on an iOS app where I need to store user's credentials for a 3rd party service on my server. (For example, storing IMAP login/password so that when they sign into my app it fetches from their IMAP server, so my server doesn't store their email)
I am not considering OAuth since not every email service provides OAuth. To do this I was thinking about the following option:
User enters username/password to sign into MyApp (MyApp server implements standard security measures, meaning it stores hashed version of the password and not the raw password, so MyApp server does not know what a user's password is)
Once signed into MyApp, MyApp stores the raw password into local keychain.
User 'connects' their 3rd party email account by signing into the 3rd party email account.
When the 3rd party email account successfully signs in, MyApp encrypts the email's password using the MyApp password (which is stored in keychain from step 2)
The encrypted password is stored on MyApp's server as "emailPassword"
From then on, whenever user signs into MyApp, MyApp fetches the encrypted "emailPassword" from MyApp's server and decrypts it back to its original form using the MyApp password stored locally on the user's keychain (which was used to encrypt in step 4).
Using the raw password decrypted from step 6 MyApp fetches emails from the 3rd party email server.
I am new to encryption so not sure if this is a safe (or even possible) option. Could anyone help? Thank you.
[UPDATED] Updated to clarify concepts and changed "encoded" to "encrypted"
You should rather say "encrypt", not "encode". Encoding is a mechanism which translates data using some set of fixed rules (algorithm). Base64 is an encoding, so is urlencoding. Encoding doesn't provide ANY security.
Encryption, however translates cleartext to ciphertext using an algorithm that uses crypto keys. Without knowledge of the key, the reversion of the ciphertext is very hard. (never impossible)
Okay, regarding your example:
It is implementable, but even though there are some attacking chances.
At some point in runtime, MyApp knows the cleartext password. At the time it is decrypted. The plaintext password then lies in RAM and could possibly read out by malicious software with respective permissions (root malware e.g.)
Also you need to make sure to use suitable algorithms in the right mode. AES-256 in CBC is more secure than in ECB mode. Then you also have to think of how to convert the password into a crypto key. Would not be too secure if you just used the password. Then you should also use a trustworthy library, no library from an unknown guy or so
Well, these are just some thoughts. You should get a little background knowledge before struggling with encryption. There are many options and you should really know, what you do.

iOS Security: Web server and File system

I have gone through apple developer videos on Security they have mentioned to use ssl https certificates and keychain to deal with security.
My iOS app will be giving access to sensitive paid files. so hackers should not get access to these files. I will be using in app purchase, so that user can buy these file.
1) My first question is: Should i host my files on apple server (Hosted Contents) , is the apple to client communication secure enough or should i implement my own server code with certificates and ssl authentication.
2) i want to know or get idea on how to encrypt files using private key on my desktop machine and then upload it on my server. When asked for by my iOS app pass the public key and encrypted file and save the public key in Keychain for further use. I want this feature so as to save the file on disk without anyone getting access to it by jailbreaking or other hack.
3) What should be used as public and private keys and what type of encryption to use. Currently i have come across AES looks good enough but is there a better way? Can certificates itself used to encrypt data or pass keys?
4) Which certificate authority to contact for most secure certificates.
Thanks in advance...
EDIT:
Main purpose to achieve is to download pdf and that pdf should not be accessible to user outside the app.
1) I have decided to use root certificates from CA and https to transfer content, to avoid MINM.
2) On app side i will generate public private key pair.
3) Save Private key in keychain.
4) Send Public key to server.
5) Server will encrypt pdf using MAIN-AES-Key.
6) MAIN-AES-Key will be encrypted using Public key sent by app.
7) Encrypted-pdf and Encrypted-MAIN-AES-Key will be sent to app.
8) Encrypted-pdf will saved to disk with secure write options just incase.
9) Encrypted-MAIN-AES-Key will be saved in keychain.
10) To decrypt pdf: Private key generated by app will be used to decrypt Encrypted MAIN-AES-Key and MAIN-AES-KEY will be used to decrypt pdf.
11) Finally will be trusting Apple-KeyChain to keep Private-Key secure.
The solution is unnecessarily complicated. The more complicated, the less secure due to more potential errors/over-sights.
Do use https with a CA signed certificate
To avoid MITM pin the certificate on the app side
There is no need to further encrypt the data being sent over https
Encrypt the file on the device and save:
Create an encryption from random bytes
Save the key in the Keychain
Create an iv from random bytes
Add the iv to the beginning of the encryption buffer
Encrypt the data with AES, CBC mode and PKS7 padding into the buffer following the iv
Save the data into a file the the app file area, possibly under the Documents or Library directory
Decrypt the file on the device and use:
Get the key from the Keychain
Read the encrypted data file
Get the iv from the beginning of the data
Decrypt the data starting just past the iv
Do not ignore the server
Use two factor authentication.
Properly hash with a salt any passwords
Use good user authentication
For the app data encryption consider using RNCryptor instead of writing the encryption portion yourself.

How to protect JSON API from being accessed by anyone but my iOS client?

I have an iPhone app that uses a Rails server HTTP API. The API is public at this point - no authorisation is required to get the data.
Currently anyone can go to API's URL and download the data.
http://server.com/mydata
The data is not very sensitive. But I still want to prevent people from easily getting it. What are the ways of doing that? I do not want iOS app users to log in either.
Current solution I have
iPhone app adds a secret token to the HTTP header or query of the request. The data goes over HTTPS.
https://server.com/mydata?secret=my_secret
Is there a better approach?
You could try an approach where the client is only allowed X number of requests per time period (based on IP address or username)
HTTPS is extremely easy to man in the middle on a device you control. You can do SSL cert validation, but there is always someone out there with more time, so best off to handle it server side.
Distribute and use your own SSL certificate.
Apps that transfer sensitive customer data, like credit card and payment information, must be protected from man-in-the middle attacks. The best protection is a mutual authentication scheme, where certificates are exchanged to make sure the app is connected to a trusted server and to make sure the server is connected to a trusted app.
Then only individuals (who have presumably installed your application) have access. If someone digs through the code and gets the public certificate then they can impersonate the client; but at that point they win anyway and two-factor authentication should be explored.

Retrieve Client ios app certificate

I want to proxy traffic from an ios application to Fiddler (or Burp). It looks like the application sends a client certificate to the server.
I will need to retrieve this cert from the phone(it's jailbroken) and import it to my proxy. Is there a way to do that ?
The client certificate is used to identify the client. If the programmer of the app made his job well, you will face difficulties (hopefully). Likely, and most secure, the private key and identity resides in the key-chain. Less secure, it resides in a secured archive (.p12, .pkcs12, .pfx) in the bundle, whose password resides in the key-chain.
If the programmer did his job not so well, you might find the password of the secured archive in the clear somewhere in the apps binary (there're actually floating samples around which do exactly this).

Sending Device Token Safely for APNs

For iOS applications that require push notifications, it must first request the user for permission to do so. After that, a device token is generated and with this, the remote server may communicate to the user through this token.
I have read a similar question here and I do not feel it is enough. The picture below is a trusted certificate, it allows me to view all traffic that happens on this device.
With Fiddler2 as well as CertMaker, I can sniff HTTPS traffic, which means the client can probably know what data they are sending, and to where.
My question is, knowing that SSL is not secure from protecting my clients from seeing what I send to the remote server, should I simply encypt with a secret key found within my application?
Such as encrypt("device_token","secretkey_a0a0a0a") (pretend this is Objective-C)?
Couldn't someone just find that key within my application? I also read this question, and it seems that it would be possible to get back the secret key.
My plan for this goes like this:
Within the iOS application, Generate a random string named activate.
Encrypt (not hash), the token by the random string and a secret key that I only know. (secretkey_a0a0a0)
Send the encrypted string along with the generated randomly generated string (active).
Within serverside, I check if I can decrypt a valid token from using the active and my secret key.
I save the token in my database if it is valid.
This prevents people from random entering tokens yes, however, secretkey_a0a0a0 is a string literal. It's very possible to get this within the application binary itself.
My question is, how do I protect this secret key? The answer can also be, how can I prevent people from sending invalid tokens to my server as well.
I have heard of encryption, but doesn't that only apply to resource files?
How should I approach this?
If you do SSL-Pinning ( AFNetworking has this implemented ) you won't be able to (in a reasonable timeframe) sniff the https traffic between the client and server if you don't have the servers private key.
If your fear is that man in the middle can steal your token and send fake push notifications to users of your application, be sure that this cant happend. Since requests to apple apn servers must be signed with pem file, the main concern should be how to keep certificate file secured, and not apn token. If you want to prevent writing invalid tokens in your database then you should implement some CRC or odd/even bit mechanism.
You might want to check the security section in the Push Notifications Guide, in particular the section titled "Token Generation and Dispersal".
The device token is generated by the device connecting through the Apple's APNS. My guess (they don't say in the docs) is that it's unique for a given app identifier.
The APNS then will probably match those identifiers with the pem certificate you use to communicate with it thus validating that the push notifications are actually originating from your app.
Encrypting the device token seems overkill in this scenario.
To prevent someone maliciously spamming your server with tokens, I would hash the token when a secret key and send both the token and the hash to the server. You can then hash the token again on the server, with your secret key, and check that the request is valid.

Resources