Go's ed25519 package exposes a function which allows creating a private key from a 32 byte seed.

See: https://godoc.org/golang.org/x/crypto/ed25519#NewKeyFromSeed

The reason I want to use this is because this is only 32 bytes, hence easy to copy and pass around.

I assume if I use a cryptograpically secure source of random for the seed, I should be ok in terms of security for the ed25519 key.

(Ideally I'd go even smaller if I could, without compromising on security).

Now I'd like to derive an AES key for encryption from those 32 bytes I already have (or the pub/priv key generated by the seed).

I would like anyone with the seed (or the private key) to be able to do the same.

Now there might be three types of clients:

  1. Clients that have the seed/private key, who are able to derive the AES key, encrypt and sign the encrypted data. (needs 32 bytes for privkey or seed)
  2. Clients that have the public key, and are able to verify the data has not been tampered with, but not be able to decrypt the data. (needs 32 bytes for pubkey)
  3. Clients that have the public key and AES key, who area able to verify and decrypt data, but not able to sign it themselves (needs 64 bytes, 32 for pubkey, 32 for aes key)

How could I derive an AES key securely for this matter?

My gut says to use pbkdf2 on the private part of the ed25519 key to generate a AES key, but I am not sure if it somehow weakens the security.

Using pbkdf2 on the seed feels like it would compromise the security even more?


You should pick a key-based key derivation function, such as HKDF-SHA256. Then:

  1. Generate a master key $k$ uniformly at random.
  2. Derive an Ed25519 seed $k_0$ from it by $$k_0 = \operatorname{HKDF-Expand}_k(\text{info=‘Ed25519 signing key’},\, \text{size=32 bytes}).$$
  3. Derive an AES key $k_1$ from it by $$k_1 = \operatorname{HKDF-Expand}_k(\text{info=‘AES encryption key’},\, \text{size=32 bytes}).$$
  4. Derive any other keys you want for any other purposes—perhaps even other Ed25519 or AES keys, just for different purposes—using HKDF-Extract with the same master key and a distinct info parameter for each distinct purpose.

You can organize the tree as you see fit to distribute subtrees with partial authority, like the authority to sign (give out $k_0$ but not $k$ or $k_1$) or the authority to encrypt/decrypt (give out $k_1$ but not $k$ or $k_0$).

Any other reasonable keyed XOF, such as KMAC128 from SHA-3 or keyed BLAKE2x, will serve too. Functions with fixed-length outputs like HMAC-SHA256 or keyed BLAKE2s are a little finickier in case you need, e.g., a 64-byte key for some reason instead of just a 32-byte key; HKDF is a generic way to turn these into a variable-length output. HKDF also includes an optional initial step, HKDF-Extract, to turn a nonuniform but high-entropy seed—such as a computer-generated BIP39 passphrase—into an effectively uniform random master key.

There is no need for a password-based key derivation function (or just ‘password hash’) such as PBKDF2 because the input—your 32-byte master key—is already a uniform random bit string. All that you really need is derived subkeys—$k_0$, $k_1$, etc.—that are apparently independent.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.