Frequently overlooked, much less hyped than quantum computers breaking trapdoor functions, managing keys is actually the most important part of building a security system. Secret keys, public-private key pairs, passwords and other factors of authentication are the control vessels within security system.
In this article, we will go through basic key management concepts, explain some important ideas for next articles and provide some practical advice you can start implementing within your application tomorrow.
Why keys are important?
Algorithms are like safe doors: they just stand still against those who don’t have the keys. Those who do - algorithms surrender their strength and expose secrets. If the data is properly encrypted, all adversary can do it look for keys.
Since your application needs those keys to manage cryptography - choosing where to keep the keys, where to perform encryption/decryption is an architectural choice, which affects overall security seriously.
Key management processes
In a typical system, there are 3 goals key management processes have to achieve:
Whatever is the process keys are used for - authentication/identity, encryption/decryption, participants of the system have to somehow circulate the keys for others to have access to data.
Secure key storage
Keys have to be stored safely - that means clever choice of where to store keys and how to store them.
Key lifetime (time until key gets rotated) should be a compromise of maintainability and security demands. In ideal world, every next encryption should be done with new keys, and in some cryptosystems it’s achievable.
It all starts with simple things: things you can do yourself within existing application infrastructure and instantly lower the risks.
Don’t: Store secrets with data
If secrets are stored with data, they will be leaked with the data and attacker will be able to decrypt everything.
Don’t: Hard-code secrets
Similarly, code is not the best place to store secrets - code changes, breaks, is easy to read if the app is compromised, and sometimes can be leaked via improper deployment procedure.
Goal: Rotate keys frequently
What if attackers seize the keys from somewhere? If the data is encrypted with the same keys long enough, chances for a leak constantly grow. If the keys were leaked, data can be compromised anytime. Unless you rotate the keys - data has to be re-encrypted with new keys once in a while.
Goal: Personalise access
Issue keys to people / processes, not resources. “Keys from X” should have very limited use, “X’s keys to Y” should be dominant key pattern. Taken straightforward, this might impair usability, but there are patterns to make it work.
Problem: Think about maintenance
Sometimes, you want the data to be not only secure, but managed properly. Flipside of good security (e.g. data being encrypted with just 1 key) is that data becomes un-encryptable if that key gets lost. You might want to separate access keys from storage keys, or have several encrypted containers. Or you might want absolute security. In any case this is something you have to think about.
Direct implementations of aforementioned principles should be core part of your applications, not some specialised security tooling built around it. You don’t need special software to isolate keys from user-facing application or database files.
Build agile schemes
Symmetric cryptography is:
- performant, supported by hardware
- very hard to break without the key
Asymmetric cryptography is:
- less performant
- potentially easier to break
Solution? Wrap symmetric cryptography into asymmetric. Encrypt everything with symmetric key, which changes every once in a while, then encrypt the symmetric key into asymmetric envelope - from some system entity to addressee. This way, to access the data addressee has to have access to up-to-date public system key and his private key, which proves his identity.
Random key schemes
As suggested previously, wrapping symmetric cryptography into asymmetric helps prevent leakage of means to access. However, once the key was leaked, the whole encrypted storage is exposed. A classic technique is to encrypt everything with random key, and then encrypt this key into asymmetric envelope. This way, for every encrypted record we generate additional set of key envelopes, which has to be stored somewhere. Yet this adds a lot of security guarantees.
The biggest question is when to rotate keys? In ideal world, every next chunk of data should be encrypted with a new key, so key leakage ends up exposing precisely one record. Practically, this is barely achievable - you will need a key for every piece of data.
Depending on the key scheme in use, right schedule could be every access, every periodic password change (if secrets are derived or protected by password) or every database compaction cycle.
If the system trust model allows system to store keys to the data directly - this is not a problem. But in modern systems with tight trust, you shouldn’t store keys directly, because everything will be broken, and the system, which contains keys, could be, too.
If you are able to effectively decouple access keys from storage keys, you can use random storage keys and rotate them anytime you want, so only the access keys remain static. However, to re-key the data you will need to decrypt it - which means it can happen only when user with legitimate private access key decrypts previous storage keys.
One thing you’d like to know is who is accessing the data. In every asymmetric scheme, there are two keys - one public (sender, “system” in this case) and one private (receiver, “role user” in this case). When you’re decrypting the data, you’ll need the public key.
By making up-to-date system public key available via API request (for example, via CA, either directly or via CRL scheme), you can track who requested the key to decrypt the envelopes and who could’ve been leakage source.
Having public key/certificate authority is a continuation of idea for public key accessibility. If you have asymmetric layer, you need some way to:
- get public keys you don’t have
- verify public keys you have for validity
For that, you need central public key directory, which is sometimes dubbed as Certificate Authority. It works as both key distribution mechanism and way to enforce key lifetime - when key-pair gets expired (or revoked), Certificate Authority fails to validate it’s public key.
Key lending daemons
One idea is to hold the keys in specialised service, and “lend” them to users when they need it, with proper accountability. Cloudflare’s Red October does that in a really elegant way.
Essentially, keys are about who you trust. There is popular pattern on how to isolate things you trust - just run them separately, in a very secure environment, to limit attack scope to one well-protected place. Think of castle gates. Secure that thing well and you’re good.
For example, Hardware Security Module is an approach to storing and managing keys in technically isolated environment, whose behaviour does not alter based on any input tampering, so there’s certain level of trust to it.
Another good idea is to store the keys and run encryption/decryption process on a separate server, which acts as a proxy between database and application. This way you can minimize attack surface to one simple item.
Managing keys is one of the most important security practices once you get technical part right.
In this article, we’ve outlined mostly challenges - what you need to do in order to achieve certain security guarantees. In the next posts in this series, we’ll talk about interesting practical approaches and real-world examples.