hmac.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. // Copyright 2009 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 hmac implements the Keyed-Hash Message Authentication Code (HMAC) as
  6. defined in U.S. Federal Information Processing Standards Publication 198.
  7. An HMAC is a cryptographic hash that uses a key to sign a message.
  8. The receiver verifies the hash by recomputing it using the same key.
  9. Receivers should be careful to use Equal to compare MACs in order to avoid
  10. timing side-channels:
  11. // ValidMAC reports whether messageMAC is a valid HMAC tag for message.
  12. func ValidMAC(message, messageMAC, key []byte) bool {
  13. mac := hmac.New(sha256.New, key)
  14. mac.Write(message)
  15. expectedMAC := mac.Sum(nil)
  16. return hmac.Equal(messageMAC, expectedMAC)
  17. }
  18. */
  19. package hmac
  20. import (
  21. "crypto/subtle"
  22. "hash"
  23. )
  24. // FIPS 198-1:
  25. // https://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf
  26. // key is zero padded to the block size of the hash function
  27. // ipad = 0x36 byte repeated for key length
  28. // opad = 0x5c byte repeated for key length
  29. // hmac = H([key ^ opad] H([key ^ ipad] text))
  30. type hmac struct {
  31. size int
  32. blocksize int
  33. opad, ipad []byte
  34. outer, inner hash.Hash
  35. }
  36. func (h *hmac) Sum(in []byte) []byte {
  37. origLen := len(in)
  38. in = h.inner.Sum(in)
  39. h.outer.Reset()
  40. h.outer.Write(h.opad)
  41. h.outer.Write(in[origLen:])
  42. return h.outer.Sum(in[:origLen])
  43. }
  44. func (h *hmac) Write(p []byte) (n int, err error) {
  45. return h.inner.Write(p)
  46. }
  47. func (h *hmac) Size() int { return h.size }
  48. func (h *hmac) BlockSize() int { return h.blocksize }
  49. func (h *hmac) Reset() {
  50. h.inner.Reset()
  51. h.inner.Write(h.ipad)
  52. }
  53. // New returns a new HMAC hash using the given hash.Hash type and key.
  54. // Note that unlike other hash implementations in the standard library,
  55. // the returned Hash does not implement encoding.BinaryMarshaler
  56. // or encoding.BinaryUnmarshaler.
  57. func New(h func() hash.Hash, key []byte) hash.Hash {
  58. hm := new(hmac)
  59. hm.outer = h()
  60. hm.inner = h()
  61. hm.size = hm.inner.Size()
  62. hm.blocksize = hm.inner.BlockSize()
  63. hm.ipad = make([]byte, hm.blocksize)
  64. hm.opad = make([]byte, hm.blocksize)
  65. if len(key) > hm.blocksize {
  66. // If key is too big, hash it.
  67. hm.outer.Write(key)
  68. key = hm.outer.Sum(nil)
  69. }
  70. copy(hm.ipad, key)
  71. copy(hm.opad, key)
  72. for i := range hm.ipad {
  73. hm.ipad[i] ^= 0x36
  74. }
  75. for i := range hm.opad {
  76. hm.opad[i] ^= 0x5c
  77. }
  78. hm.inner.Write(hm.ipad)
  79. return hm
  80. }
  81. // Equal compares two MACs for equality without leaking timing information.
  82. func Equal(mac1, mac2 []byte) bool {
  83. // We don't have to be constant time if the lengths of the MACs are
  84. // different as that suggests that a completely different hash function
  85. // was used.
  86. return subtle.ConstantTimeCompare(mac1, mac2) == 1
  87. }