hkdf.go 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. /*
  2. HKDF is a simple key derivation function (KDF) based on
  3. a hash-based message authentication code (HMAC). It was initially proposed by its authors as a building block in
  4. various protocols and applications, as well as to discourage the proliferation of multiple KDF mechanisms.
  5. The main approach HKDF follows is the "extract-then-expand" paradigm, where the KDF logically consists of two modules:
  6. the first stage takes the input keying material and "extracts" from it a fixed-length pseudorandom key, and then the
  7. second stage "expands" this key into several additional pseudorandom keys (the output of the KDF).
  8. */
  9. package hkdf
  10. import (
  11. "crypto/hmac"
  12. "crypto/sha256"
  13. "fmt"
  14. "golang.org/x/crypto/hkdf"
  15. "io"
  16. )
  17. /*
  18. Expand expands a given key with the HKDF algorithm.
  19. */
  20. func Expand(key []byte, length int, info string) ([]byte, error) {
  21. if info == "" {
  22. keyBlock := hmac.New(sha256.New, key)
  23. var out, last []byte
  24. var blockIndex byte = 1
  25. for i := 0; len(out) < length; i++ {
  26. keyBlock.Reset()
  27. //keyBlock.Write(append(append(last, []byte(info)...), blockIndex))
  28. keyBlock.Write(last)
  29. keyBlock.Write([]byte(info))
  30. keyBlock.Write([]byte{blockIndex})
  31. last = keyBlock.Sum(nil)
  32. blockIndex += 1
  33. out = append(out, last...)
  34. }
  35. return out[:length], nil
  36. } else {
  37. h := hkdf.New(sha256.New, key, nil, []byte(info))
  38. out := make([]byte, length)
  39. n, err := io.ReadAtLeast(h, out, length)
  40. if err != nil {
  41. return nil, err
  42. }
  43. if n != length {
  44. return nil, fmt.Errorf("new key to short")
  45. }
  46. return out[:length], nil
  47. }
  48. }