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  

View as plain text