github.com/maenmax/kairep@v0.0.0-20210218001208-55bf3df36788/src/golang.org/x/crypto/hkdf/hkdf.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package hkdf implements the HMAC-based Extract-and-Expand Key Derivation 6 // Function (HKDF) as defined in RFC 5869. 7 // 8 // HKDF is a cryptographic key derivation function (KDF) with the goal of 9 // expanding limited input keying material into one or more cryptographically 10 // strong secret keys. 11 // 12 // RFC 5869: https://tools.ietf.org/html/rfc5869 13 package hkdf // import "golang.org/x/crypto/hkdf" 14 15 import ( 16 "crypto/hmac" 17 "errors" 18 "hash" 19 "io" 20 ) 21 22 type hkdf struct { 23 expander hash.Hash 24 size int 25 26 info []byte 27 counter byte 28 29 prev []byte 30 cache []byte 31 } 32 33 func (f *hkdf) Read(p []byte) (int, error) { 34 // Check whether enough data can be generated 35 need := len(p) 36 remains := len(f.cache) + int(255-f.counter+1)*f.size 37 if remains < need { 38 return 0, errors.New("hkdf: entropy limit reached") 39 } 40 // Read from the cache, if enough data is present 41 n := copy(p, f.cache) 42 p = p[n:] 43 44 // Fill the buffer 45 for len(p) > 0 { 46 f.expander.Reset() 47 f.expander.Write(f.prev) 48 f.expander.Write(f.info) 49 f.expander.Write([]byte{f.counter}) 50 f.prev = f.expander.Sum(f.prev[:0]) 51 f.counter++ 52 53 // Copy the new batch into p 54 f.cache = f.prev 55 n = copy(p, f.cache) 56 p = p[n:] 57 } 58 // Save leftovers for next run 59 f.cache = f.cache[n:] 60 61 return need, nil 62 } 63 64 // New returns a new HKDF using the given hash, the secret keying material to expand 65 // and optional salt and info fields. 66 func New(hash func() hash.Hash, secret, salt, info []byte) io.Reader { 67 if salt == nil { 68 salt = make([]byte, hash().Size()) 69 } 70 extractor := hmac.New(hash, salt) 71 extractor.Write(secret) 72 prk := extractor.Sum(nil) 73 74 return &hkdf{hmac.New(hash, prk), extractor.Size(), info, 1, nil, nil} 75 }