A key derivation function, or KDF, derives one or many secret keys from a secret value. If you’ve ever needed to store a password in a database or create a private key from a password, you may have used a KDF.
Examples of popular KDFs:
Are KDFs just hash functions?
No, but there is overlap. In order to understand KDFs, let’s first go through a quick refresher on hash functions.
Examples of hash functions include:
- Sha256
- MD5
- Bcrypt
A hash function takes an input and creates an output. In most password hashing scenarios it looks something like this:
sha256("password123") -> ef92b778bafe771e89245b89ecbc08a44a4e166c06659911881f383d4473e94f
The function must have the following properties:
- Data is scrambled deterministically (Same input, same output)
- No matter the input, the output of a hash function always has the same size
- The input can not be retrieved from the output (one-way function)
So what is the difference?
As it turns out, all key derivation functions are secure hash functions, but not all hash functions are secure KDFs.
In addition to the properties of a hash function, KDFs can serve the following purposes:
- Key Stretching
- Key Whitening
- Key Separation
- Key Strengthening
Let’s look at each case separately, with the following definition of our general KDF in mind:
derivedKey = keyDerivationFunction(originalKey, salt, difficulty)
Salt is random data used to protect against pre-computation attacks or rainbow tables.
Difficulty can be used to make the KDF slower via intense computation, memory, or parallelism requirements. This protects against brute force attacks because it will take an attacker longer per guess.
Key Stretching
Key stretching is the most common use case for the average developer. The idea is to take a key with low-entropy (security or randomness) and stretch it into a longer key that is more secure. Passwords are a great example. Many websites use Bcrypt to stretch keys:
passwordForDB = bcrypt(password, salt, difficulty)
Key Whitening
Some encryption schemes require specific key lengths, for example, 256 bits. Let’s say we have a system that already has keys generated, but the keys are 512 bits long. We can use a KDF to get the keys into the correct format and size.
Key Separation
KDFs allow child keys to be created from a master key. This can be used in applications like Bitcoin where child keys can control sections of a wallet, and only the master has full control. This is done by use of different salts. For example:
childOne = kdf(masterKey, saltOne, difficulty)
childTwo = kdf(masterKey, saltTwo, difficulty)
childThree = kdf(masterKey, saltThree, difficulty)
Key Strengthening
Strengthing extends a key with a random salt, but then deletes the salt so it can’t be used again. This makes the resulting key stronger without adding significant vulnerabilities to the system.
Should I Use KDFs?
Yes. Most often when storing passwords in databases, but also if any of these other use cases fall into the domain of your code. Tweet at me if you have comments or questions.
Lane on Twitter: @wagslane
Lane on Dev.to: wagslane
Download Qvault: https://qvault.io
Star our Github: https://github.com/q-vault/qvault
The post (Very) Basic Intro to Key Derivation Functions (Argon2, Scrypt, etc) appeared first on Qvault.
Top comments (2)
What are the use-cases for doing key strengthening the way you describe it ? If you throw the salt away, there is no way to replicate the process, so it would not work for operations like password-based auth, but I'm genuinely interested in knowing other use-cases for single-use key generation (post key agreement strengthening, maybe ?)
Good question, truth be told I've had a couple of discussions with others about this subject as well, and I'm not sure how useful this is. Maybe the method of determining the salt is well known to participants so there is no need to keep it around.