HKDF vector creation

This page documents the code that was used to generate a longer HKDF test vector (1200 bytes) than is available in RFC 5869. All the vectors were generated using OpenSSL and verified with Go.

Creation

The following Python script was run to generate the vector files.

# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.

import binascii

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.hkdf import HKDF

IKM = binascii.unhexlify(b"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b")
L = 1200
OKM = HKDF(
    algorithm=hashes.SHA256(),
    length=L,
    salt=None,
    info=None,
).derive(IKM)


def _build_vectors():
    output = [
        "COUNT = 0",
        "Hash = SHA-256",
        "IKM = " + binascii.hexlify(IKM).decode("ascii"),
        "salt = ",
        "info = ",
        f"L = {L}",
        "OKM = " + binascii.hexlify(OKM).decode("ascii"),
    ]
    return "\n".join(output)


def _write_file(data, filename):
    with open(filename, "w") as f:
        f.write(data)


if __name__ == "__main__":
    _write_file(_build_vectors(), "hkdf.txt")

Download link: generate_hkdf.py

Verification

The following Go code was used to verify the vectors.

package main

import (
	"bufio"
	"bytes"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"golang.org/x/crypto/hkdf"
	"io"
	"os"
	"strconv"
	"strings"
)

func unhexlify(s string) []byte {
	bytes, err := hex.DecodeString(s)
	if err != nil {
		panic(err)
	}
	return bytes
}

func verifier(l uint64, ikm, okm []byte) bool {
	hash := sha256.New
	hkdf := hkdf.New(hash, ikm, nil, nil)
	okmComputed := make([]byte, l)
	io.ReadFull(hkdf, okmComputed)
	return bytes.Equal(okmComputed, okm)
}

func validateVectors(filename string) bool {
	vectors, err := os.Open(filename)
	if err != nil {
		panic(err)
	}
	defer vectors.Close()

	var segments []string
	var l uint64
	var ikm, okm string

	scanner := bufio.NewScanner(vectors)
	for scanner.Scan() {
		segments = strings.Split(scanner.Text(), " = ")

		switch {
		case strings.ToUpper(segments[0]) == "L":
			l, err = strconv.ParseUint(segments[1], 10, 64)
			if err != nil {
				panic(err)
			}
		case strings.ToUpper(segments[0]) == "IKM":
			ikm = segments[1]
		case strings.ToUpper(segments[0]) == "OKM":
			okm = segments[1]
		}
	}
	return verifier(l, unhexlify(ikm), unhexlify(okm))
}

func main() {
	if validateVectors("vectors/cryptography_vectors/KDF/hkdf-generated.txt") {
		fmt.Println("HKDF OK.")
	} else {
		fmt.Println("HKDF failed.")
		os.Exit(1)
	}
}

Download link: verify_hkdf.go