Some of you know, and some of you don’t, but we all fail at building secure mobile apps.
Today we going to talk about key management. We start our journey step by step: discovering infrastructure layout, digging into ideas of threats, trust, and keys. Discussing key management system: what is a key generation, how to access and revoke keys, and many other exciting theoretical things! But of course, we will apply this knowledge to the mobile apps.
How do you know that you should trust someone in a real world? How do you know, that your friend over the phone is the one you should trust? You recognize them by their voice or typical words. How about a stranger? Probably you would use a secret keyword.
In shiny worlds of computers, there’re many ways to build trust to parties you don’t know and can’t easily recognize: sharing passwords, asymmetric keys, zero knowledge proof.
Usually, we establish trust on servers, mobile, data in transit via public channels, and so on. I mean, real things. Like cables and stuff. Our infrastructure is full of keys and data, all that in cables, yeah. Those cables are important — they’re out of your control, and whatever you reach outside your office — you rely on these creatures.
Why do we need trust?
– To protect the data in those cables, where evil CIA and badass crackers are looking for your secrets. Using special super mathematical techniques, we provide guarantees of confidentiality, authenticity, and integrity towards protected data, bound to trusted keys or secrets. It’s provable and unhackable if you manage the keys correctly.
Since “keys are what we trust” and they control trust in the system, managing them is managing trust. So, let’s talk about key management.
– What is a key? – It’s an array of bytes.
Based on what kind of process is going on, we need different arrays of bytes with different properties:
1. We use secret keys for symmetric ciphers.
2. Public/private keypair for asymmetric ciphers
3. Passwords are strings that you can remember. It’s a poor key, by the way. We should use KDF instead of user password itself.
4. One-time PINs are small and easy to transfer key with risky properties. It’s an additional trust token, like that thing you get via SMS from your bank when logging into their system.
– What kinds of keys we know in our shiny iOS world?
App tokens, server tokens, user passwords, certificates, well, familiar things, aren’t they? They all are keys.
– What do we need them for?
Keys protect the data!
They let you access the data, verify data authenticity and integrity. Of course, mostly we deal with user-generated data that users are putting into our apps. However, we also care about access to external resources (like 3rd party services or your web servers), and identifiable data of other users in our app (for example, user info from those who like your tweets, if any).
– What do we protect data from?
Oh well, you know, all those threats we can and can’t handle. Like data tampering and leakage, a man in the middle, active and passive, and of course really common problems like rubber-hose cryptanalysis.
Keys are arrays of bytes that are stored somewhere, and they unlock protected data and facilitate trust. Of course, the attacker wants them. Basically, keys are small chunks of data, and they’re subject to threats too.
Keys are small chunks of data and should be protected too!
What can happen to the keys?
1. Attackers can steal the keys, and that’s bad (reasons are obvious, no?).
2. What’s worse, stolen keys can be replayed — they can be used to access something protected.
3. And, if the attackers are lucky enough, and you’re not, keys can even be replaced: attackers can throw in their own evil keys to access resources.
So we need to build a system which protects and manages keys.
Key management system: goals and actions
In key management, there is one practical goal: trust and security are preserved yet the system is usable. If you don’t do that, you’ll end up with another ultra-secure super-paranoid end-to-end system nobody’s willing to use :)
Any key management system consists of several processes, which are linked sequentially: from generation to exchange, from exchange to storage and access, with revocation to control compromised and outdated keys, and rotation to ensure key lifetime. Sometimes, this system should contain service processes too: like backups and admin access to encrypted data.
Generation and exchange
The goal of key generation is to create mathematically strong trust tokens: ones that stand against brute force and smart enumeration. We need to use good random number generator and an algorithm, combined with a secret, to produce a key. To ensure it does not leak, we need to produce it where user inputs secret, or where it is safe to store the key.
Basically, keep it as close to usage and storage location as possible.
How about a password? A password is not a very good key: it’s easy to brute force, and usually, users come up with poor passwords. Key derivation function (KDF) helps to convert the password to the cryptographically strong key so that attackers will be sad.
After we generate the keys, next step is exchanging the keys between trusted parties. Key exchange is an essential process in establishing trust: we need to exchange or distribute keys securely.
Storage and access
Key storing is a big deal: we need to store them in a way which minimizes the risk. One big point: never store the keys with the data encrypted with these keys.
Once the keys are stored, we want to access them to actually use them. Achieving the balance is tricky: keys should be protected, but still easy to access legitimately.
Rotation and revocation
Now that we know that keys are generated and stored… do they live forever? Of course no!
The key lifecycle is a biography of a single mr. Key — from birth to oblivion.
The lifecycle will specify when a key should no longer be used for encryption, when a key should no longer be used for decryption, when a key is a key no more.
And of course, you don’t want everything to be encrypted with one key, right? If you leak it, you’re done. You want to have several keys — one per user, or maybe one per group, or at least one per certain number of records. It’s all about controlling the risk.
Now, what if key should be changed?
You need your system to support re-encryption with new keys. What if somebody finds an attack for the algorithm you’re using? You need to change it. To do that, you need to decrypt the data, generate new kinds of keys, encrypt and store the data, sometimes eliminate unused records, sometimes ensure correct purging of non-encrypted data from memory. Wheeeww. A lot of things to consider for key rotation.
Now that we’re mostly done with theoretical ideas, there’s a practical consideration.
Apart from user features, the system has certain maintenance procedures, which require special access to data, like backups, admin access, password resets. These things are better implemented through additional keys and separate protection layer for them.
Key management in practice
There are three main ways to establish trust on mobile.
1. On channel exchange. You connect first to a server, record it’s certificate, and when you connect again, you can compare the certificates. This away, apart from trusting the certificate itself, you trust the server too.
2. Mediated exchange. You know remote party’s identifier and can ask someone you trust for their public key. For example, you may use keybase.io to exchange public keys in a trusted fashion.
3. Trusted channel exchange. Two methods above rely on many assumptions: you have to trust somebody. The most simple way is always just handing the key or secret to the party you’re establishing trust with. For example, to build trust with Facebook in your app, you need to authenticate via app token. To do that, you register the app in Facebook dev portal and copy app token into your code. That is exactly trusted channel key exchange — via you!
Storing or not storing?
So people, where do you store the keys?
Keychain is great, but sometimes you can’t use it, or you don’t want to use it (by the way, Keychain will break if the device is jailbroken).
The easiest way to avoid leaking keys — don’t store them at all! :)
But if I need to store..?
Mostly, we deal with two kinds of keys: user-defined and app-defined.
App-defined keys are built in. You already have them in the app, but they should be stored and accessed correctly.
User-defined keys are something that user inputs or based on user input. Those keys should be put in right place on right time.
Obfuscation is fun, but don’t rely on it
There are different ways to obfuscate the keys: store them as hex chars, or replace characters inside key strings.
Obfuscation depends on social engineering, and the goal is to confuse the attacker: save certificate, but rename it to mp3 file, for example. Or split key to different pieces and put them in different places. Experiment.
However, a well-trained attacker will break this defense in minutes. Better spend your time on serious defenses.
1. Encrypt keys during development
2. Store encrypted keys only
3. Decrypt before using
This technique works well with app-defined keys. You may ask: how to store keys that were used to encrypt keys? :)
The answer is: not every key should be stored. You can generate or calculate encryption key based on something you already know, something like bundle id or next 4-digits of the result of division 27 by 13.
Poison keys and Honeypot
Another prominent technique in the school of deception known as poison keys.
Make attackers think they have the right keys, make them use those keys. And be alarmed: attackers are poking in your app, naive enough to try fake keys on you.
This technique works well with honeypot: store these poison keys in obvious places and just watch the logs.
For example, store a fake key in the plist file, or put “server.cert” in the app bundle. Sometimes, the best you can do to prevent attacks is actually detect them timely. This is such case. By the way, you still have to protect the real keys really well.
For every fragment of your system, trust is applied differently. There are no religious choices. Best solutions come from assessing your real architecture and fitting the tools to it.
- Cryptographic Storage Cheat Sheet [OWASP]
- Key Management Cheat Sheet [OWASP]
- Managing Keys, Certificates, and Passwords [Apple]