HMAC Key Derivation function (HKDF) is used to derive an encryption key from a pass phrase. Initially HKDF creates a pseudorandom key (PRK) using a pass phrase and a salt value (and any other random functions which are relavent), in order to produce an HMAC hash function (such as HMAC-SHA256), andalong with a salt value. Next the PRK output is used to produce a key of the required length. If we generate a 16-byte output (32 hex characters), we have a 128-bit key, and a 32-byte output (64 hex characters) will generate a 256-bit key. HKDF is used in TLS 1.3 for generating encryption keys [RFC 5869][article]. In this case we will use SHA-256.
HMAC Key Derivation Function (HKDF) in Golang |
HKDF
The following shows how an encryption key can be generated using HKDF, and where we need a secret and a salt value. Both Bob and Alice have the same secret and salt.
Coding
The outline code is:
package main import ( "crypto/rand" "crypto/sha256" "fmt" "io" "os" "golang.org/x/crypto/hkdf" ) func getSalt(n int) []byte { nonce := make([]byte, n) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { panic(err.Error()) } return (nonce) } func main() { hash := sha256.New s := "The quick brown fox jumps over the lazy dog" salt := getSalt(hash().Size()) info := []byte("") argCount := len(os.Args[1:]) if argCount > 0 { s = os.Args[1] } secret := []byte(s) kdf := hkdf.New(hash, secret, salt, info) key1 := make([]byte, 16) _, _ = io.ReadFull(kdf, key1) fmt.Printf("Secret: %s\n", s) fmt.Printf("HKDF 16 byte key: %x\n", key1) key2 := make([]byte, 32) _, _ = io.ReadFull(kdf, key2) fmt.Printf("HKDF 32 byte key: %x\n", key2) }
A sample run is:
Secret: The quick brown fox jumps over the lazy dog Salt: c357e487d08ebb3a219d7370b26d424c7c642275e8a76cab1544d47b4c9458f4 HKDF 16 byte key: 2332a50d3306be40cfc044b0a48d5818 HKDF 32 byte key: 2b368335f306b6cf5ffd97b3077e0181de940d5e6c6eafd9b22dbeedf464c38a