package gostdlib import ( "errors" "fmt" "io" "github.com/safing/jess/tools" "github.com/safing/portbase/container" "golang.org/x/crypto/hkdf" ) func init() { tools.Register(&tools.Tool{ Info: &tools.ToolInfo{ Name: "HKDF", Purpose: tools.PurposeKeyDerivation, Options: []uint8{tools.OptionNeedsDedicatedHasher}, SecurityLevel: 0, // depends on used hash function Comment: "RFC 5869", Author: "Hugo Krawczyk, 2010", }, Factory: func() tools.ToolLogic { return &HKDF{} }, }) } // HKDF implements the cryptographic interface for HKDF key derivation. type HKDF struct { tools.ToolLogicBase reader io.Reader } // InitKeyDerivation implements the ToolLogic interface. func (keyder *HKDF) InitKeyDerivation(nonce []byte, material ...[]byte) error { // hkdf arguments: hash func() hash.Hash, secret, salt, info []byte // `secret` and `salt` are used for the initial `extract` operation // `info` is mixed into every `expand` operation if len(material) < 1 || len(material[0]) == 0 || len(nonce) == 0 { return errors.New("must supply at least one key and a nonce as key material") } keyder.reader = hkdf.New( keyder.HashTool().New, container.New(material...).CompileData(), // cryptographically secure master secret(s) nonce, // non-secret salt nil, // non-secret info ) return nil } // DeriveKey implements the ToolLogic interface. func (keyder *HKDF) DeriveKey(size int) ([]byte, error) { key := make([]byte, size) return key, keyder.DeriveKeyWriteTo(key) } // DeriveKeyWriteTo implements the ToolLogic interface. func (keyder *HKDF) DeriveKeyWriteTo(new []byte) error { n, err := io.ReadFull(keyder.reader, new) if err != nil { return fmt.Errorf("failed to generate key: %s", err) } if n != len(new) { return errors.New("failed to generate key: EOF") } return nil }