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