...

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 // 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			f.expander.Reset()
    60			f.expander.Write(f.prev)
    61			f.expander.Write(f.info)
    62			f.expander.Write([]byte{f.counter})
    63			f.prev = f.expander.Sum(f.prev[:0])
    64			f.counter++
    65	
    66			// Copy the new batch into p
    67			f.buf = f.prev
    68			n = copy(p, f.buf)
    69			p = p[n:]
    70		}
    71		// Save leftovers for next run
    72		f.buf = f.buf[n:]
    73	
    74		return need, nil
    75	}
    76	
    77	// Expand returns a Reader, from which keys can be read, using the given
    78	// pseudorandom key and optional context info, skipping the extraction step.
    79	//
    80	// The pseudorandomKey should have been generated by Extract, or be a uniformly
    81	// random or pseudorandom cryptographically strong key. See RFC 5869, Section
    82	// 3.3. Most common scenarios will want to use New instead.
    83	func Expand(hash func() hash.Hash, pseudorandomKey, info []byte) io.Reader {
    84		expander := hmac.New(hash, pseudorandomKey)
    85		return &hkdf{expander, expander.Size(), info, 1, nil, nil}
    86	}
    87	
    88	// New returns a Reader, from which keys can be read, using the given hash,
    89	// secret, salt and context info. Salt and info can be nil.
    90	func New(hash func() hash.Hash, secret, salt, info []byte) io.Reader {
    91		prk := Extract(hash, secret, salt)
    92		return Expand(hash, prk, info)
    93	}
    94	

View as plain text