# 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.backends import default_backend
    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,
        backend=default_backend(),
    ).derive(IKM)

    def _build_vectors():
        output = [
            "COUNT = 0",
            "Hash = SHA-256",
            "IKM = " + binascii.hexlify(IKM).decode("ascii"),
            "salt = ",
            "info = ",
            "L = {}".format(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`