These are the steps:
Hash ECDH shared secret with SHA3-512
Concatenate odd bytes and rehash with SHA3-512 for AES-256 key
Concatenate even bytes and rehash with SHA3-512 for KMAC key
Is this key derivation secure? If not, what are the weaknesses?
These are the steps:
Hash ECDH shared secret with SHA3-512
Concatenate odd bytes and rehash with SHA3-512 for AES-256 key
Concatenate even bytes and rehash with SHA3-512 for KMAC key
Is this key derivation secure? If not, what are the weaknesses?
The key derivation process you describe is reasonably secure in a technical sense, but not a good choice—it's not very flexible, it will raise auditors' eyebrows, and SHA3-512 is just not a good design.
Security if we model SHA3-512 as a uniform random function $H$: Each of the 512 bytes of $H$ on distinct DH secrets is independently uniform random, so the string of 256 odd-position bytes is uniform random and the string of 256 even-position bytes is independently uniform random. The probability of collision between the even-position bytes and the odd-position bytes is negligible, and in the event of no collision, the resulting keys are independent uniform random.
Why is it a bad choice?
It's not very flexible. What happens when you want to derive another key? You've used up all the bytes (or, most of them, anyway); you'll need to find a different mechanism for this purpose, and it'll be another ad hoc thing that the remaining reasons still apply to. This fragility may hurt security: Will your successor who needs to extend the protocol make a decision that remains secure?
It will raise auditors' eyebrows. This is not a standard construction for key derivation. By adopting this, you make an auditor's job harder by forcing them do cryptographic reasoning like the paragraph above, which auditors would rather not do. They don't want to think about the even-position and odd-position bytes of a SHA3-512 hash. They'd rather spend their effort simply confirming that you're using a well-studied and well-understood construction without having to think about it, so they can move on to higher-level protocol issues that will actually be more important in assessing the security of your application.
SHA3-512 is just not a good design. SHA3-512 pays extra for an unimaginably high security level that doesn't matter to you for two reasons:
General advice aside: Ignore SHA3-256 and SHA3-512. Use SHAKE128 (with sufficiently long outputs) for a 128-bit security level. Use SHAKE256 only if you're a paranoid worrying about hedging against modest cryptanalytic advances, like for use with Ed448.
So what should you do instead? Here are a couple options:
Use HKDF with your favorite hash function. SHA-256 is a perfectly respectable choice. If you insist on using SHA-3, you could use SHA3-256, but SHAKE128-256 would be faster for essentially same security—or you could just use SHAKE128 or KMAC128 directly, below.
HKDF comes in two stages, which some APIs weld together:
HKDF-Extract takes initial key material and a salt and hashes them into a master key.
\begin{equation*} k_{\mathrm{master}} = \operatorname{HKDF-Extract}(\mathit{dhsecret}) \end{equation*}
You must never reuse the same initial key material. (Actually, in practical terms, if you reuse it with distinct salts, you won't get into security trouble—but you will make the auditor's job harder which will make your life harder and hurt your user's confidence in your system.)
HKDF-Expand takes a master key and an info parameter that uniquely describes a purpose and derives a subkey from them.
The master key is what you got out of HKDF-Extract. (Aside: It could also be from a password hash like Argon2 or PBKDF2, or any short uniform random secret key that you got from somewhere else and you just want to derive multiple subkeys from.)
The info parameter distinguishes the subkeys for different purposes: for each distinct info, there is an effectively independent uniform random subkey; it is as if you generated the subkey independently, but you can get it deterministically and reproducibly from the master key by passing in the same info.
The subkey is what you then use as an AES-256 key or whatever.
\begin{align*} k_{\mathrm{AES}} &= \operatorname{HKDF-Expand}_{k_{\mathrm{master}}}(\text{‘AES encryption key’}), \\ k_{\mathrm{KMAC}} &= \operatorname{HKDF-Expand}_{k_{\mathrm{master}}}(\text{‘KMAC authentication key’}). \end{align*}
You must never reuse the same info parameter for two different purposes. The auditor will want it to be easy to confirm that every purpose for which you derive a subkey has a distinct info parameter, so you should clearly document what each info parameter is used for, and if you ever programmatically format info parameters, make sure that you use a unique encoding of whatever data you put in them to ensure they will be unique.
Use KMAC128, or SHAKE128, directly. For KMAC128, you can safely just feed in the DH secret as the KMAC128 key, and uniquely encode the salt and info parameters as the KMAC128 message. Similarly, you could also just uniquely encode the DH secret, the salt, and the info parameters as the SHAKE128 message: $\operatorname{SHAKE128}(\text{32-byte DH secret} \mathbin\| \text{32-byte salt} \mathbin\| \text{‘AES key’})$.
This may be simpler for your application, and it doesn't hurt security. As long as it's conceptually structured the same way as HKDF—never reuse a DH secret except with distinct info parameters—it should be straightforward for an auditor to follow.
The easiest way maybe is running a single SHA-512 or SHA3-512 and split the result into half.
$$\text{AES-KEY}\mathbin\|\text{KMAC-KEY} = \operatorname{SHA-512}(secret)$$
Actually, it is better to use domain separation for arriving different keys from a single secret, or input key material. This can be achieved like:
$$\text{AES-KEY} = \operatorname{SHA-256}(\textit{"aes-key"}\mathbin\| secret)$$ $$\text{KMAC-KEY} = \operatorname{SHA-256}(\textit{"kmac-key"}\mathbin\| secret)$$
The prefixes can be considered as a nonce to separate the domain so that different hash results can be achieved for different results. This domain separation is also used in Key Derivation Functions.
Indeed, there are standardized ways of using hash functions to derive keys instead of work factor based on KDF's like PBKDF2.
For example, HKDF with HMAC from pycryptodome's The HMAC-based Extract-and-Expand key derivation function (HKDF). It is standardized in RFC 5869 and in NIST SP-800 56C.
HKDFHKDF(master, key_len, salt, hashmod, num_keys=1, context=None)
Interestingly this library can output multiple keys at once. For example, you can call the below to arrive two AES-256 keys.
key1, key2 = HKDF(master_secret, 32, salt, SHA512, 2)
If you want, you can use the context and derive the two keys in different domain.
AES-Key = HKDF(master_secret, 32, salt, SHA512, 1, ""aes-key"")
KMAC-Key= HKDF(master_secret, 32, salt, SHA512, 1, "hmac-key")
hkdf.derive
multiple times with the same salt and different keys is exactly the opposite of how HKDF should be used—and the documentation is bad. The purpose of the salt is not to ‘increase entropy’. The purpose of the salt is to mitigate multi-target attacks by using a different salt with each different user's initial key material. The info parameter is the parameter that you should vary for each different purpose: use the same initial key material and same salt multiple times, once with info="aes key"
and once with info="kmac key"
, for example.
$\endgroup$
Commented
Oct 18, 2019 at 15:54