Source file src/vendor/golang.org/x/crypto/hkdf/hkdf.go
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 package hkdf 12 13 import ( 14 "crypto/hkdf" 15 "crypto/hmac" 16 "errors" 17 "hash" 18 "io" 19 ) 20 21 // Extract generates a pseudorandom key for use with Expand from an input secret 22 // and an optional independent salt. 23 // 24 // Only use this function if you need to reuse the extracted key with multiple 25 // Expand invocations and different context values. Most common scenarios, 26 // including the generation of multiple keys, should use New instead. 27 func Extract(hash func() hash.Hash, secret, salt []byte) []byte { 28 // Use the stdlib Extract, which disables FIPS 140 enforcement of the HMAC 29 // key (which in HKDF is the salt). The only possible error is FIPS 140 30 // enforcement of the hash, which had to panic under this API anyway. We 31 // don't use the stdlib Expand, because it switched to returning a []byte 32 // instead of an io.Reader, and Expand uses the HMAC key as a key. 33 out, err := hkdf.Extract(hash, secret, salt) 34 if err != nil { 35 panic(err) 36 } 37 return out 38 } 39 40 type hkdfReader struct { 41 expander hash.Hash 42 size int 43 44 info []byte 45 counter byte 46 47 prev []byte 48 buf []byte 49 } 50 51 func (f *hkdfReader) Read(p []byte) (int, error) { 52 // Check whether enough data can be generated 53 need := len(p) 54 remains := len(f.buf) + int(255-f.counter+1)*f.size 55 if remains < need { 56 return 0, errors.New("hkdf: entropy limit reached") 57 } 58 // Read any leftover from the buffer 59 n := copy(p, f.buf) 60 p = p[n:] 61 62 // Fill the rest of the buffer 63 for len(p) > 0 { 64 if f.counter > 1 { 65 f.expander.Reset() 66 } 67 f.expander.Write(f.prev) 68 f.expander.Write(f.info) 69 f.expander.Write([]byte{f.counter}) 70 f.prev = f.expander.Sum(f.prev[:0]) 71 f.counter++ 72 73 // Copy the new batch into p 74 f.buf = f.prev 75 n = copy(p, f.buf) 76 p = p[n:] 77 } 78 // Save leftovers for next run 79 f.buf = f.buf[n:] 80 81 return need, nil 82 } 83 84 // Expand returns a Reader, from which keys can be read, using the given 85 // pseudorandom key and optional context info, skipping the extraction step. 86 // 87 // The pseudorandomKey should have been generated by Extract, or be a uniformly 88 // random or pseudorandom cryptographically strong key. See RFC 5869, Section 89 // 3.3. Most common scenarios will want to use New instead. 90 func Expand(hash func() hash.Hash, pseudorandomKey, info []byte) io.Reader { 91 expander := hmac.New(hash, pseudorandomKey) 92 return &hkdfReader{expander, expander.Size(), info, 1, nil, nil} 93 } 94 95 // New returns a Reader, from which keys can be read, using the given hash, 96 // secret, salt and context info. Salt and info can be nil. 97 func New(hash func() hash.Hash, secret, salt, info []byte) io.Reader { 98 prk := Extract(hash, secret, salt) 99 return Expand(hash, prk, info) 100 } 101