]> Cypherpunks.ru repositories - gostls13.git/blob - src/crypto/hmac/hmac.go
[dev.boringcrypto] all: merge master into dev.boringcrypto
[gostls13.git] / src / crypto / hmac / hmac.go
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 /*
6 Package hmac implements the Keyed-Hash Message Authentication Code (HMAC) as
7 defined in U.S. Federal Information Processing Standards Publication 198.
8 An HMAC is a cryptographic hash that uses a key to sign a message.
9 The receiver verifies the hash by recomputing it using the same key.
10
11 Receivers should be careful to use Equal to compare MACs in order to avoid
12 timing side-channels:
13
14         // ValidMAC reports whether messageMAC is a valid HMAC tag for message.
15         func ValidMAC(message, messageMAC, key []byte) bool {
16                 mac := hmac.New(sha256.New, key)
17                 mac.Write(message)
18                 expectedMAC := mac.Sum(nil)
19                 return hmac.Equal(messageMAC, expectedMAC)
20         }
21 */
22 package hmac
23
24 import (
25         "crypto/subtle"
26         "hash"
27 )
28
29 import "crypto/internal/boring"
30
31 // FIPS 198-1:
32 // https://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf
33
34 // key is zero padded to the block size of the hash function
35 // ipad = 0x36 byte repeated for key length
36 // opad = 0x5c byte repeated for key length
37 // hmac = H([key ^ opad] H([key ^ ipad] text))
38
39 // Marshalable is the combination of encoding.BinaryMarshaler and
40 // encoding.BinaryUnmarshaler. Their method definitions are repeated here to
41 // avoid a dependency on the encoding package.
42 type marshalable interface {
43         MarshalBinary() ([]byte, error)
44         UnmarshalBinary([]byte) error
45 }
46
47 type hmac struct {
48         opad, ipad   []byte
49         outer, inner hash.Hash
50
51         // If marshaled is true, then opad and ipad do not contain a padded
52         // copy of the key, but rather the marshaled state of outer/inner after
53         // opad/ipad has been fed into it.
54         marshaled bool
55 }
56
57 func (h *hmac) Sum(in []byte) []byte {
58         origLen := len(in)
59         in = h.inner.Sum(in)
60
61         if h.marshaled {
62                 if err := h.outer.(marshalable).UnmarshalBinary(h.opad); err != nil {
63                         panic(err)
64                 }
65         } else {
66                 h.outer.Reset()
67                 h.outer.Write(h.opad)
68         }
69         h.outer.Write(in[origLen:])
70         return h.outer.Sum(in[:origLen])
71 }
72
73 func (h *hmac) Write(p []byte) (n int, err error) {
74         return h.inner.Write(p)
75 }
76
77 func (h *hmac) Size() int      { return h.outer.Size() }
78 func (h *hmac) BlockSize() int { return h.inner.BlockSize() }
79
80 func (h *hmac) Reset() {
81         if h.marshaled {
82                 if err := h.inner.(marshalable).UnmarshalBinary(h.ipad); err != nil {
83                         panic(err)
84                 }
85                 return
86         }
87
88         h.inner.Reset()
89         h.inner.Write(h.ipad)
90
91         // If the underlying hash is marshalable, we can save some time by
92         // saving a copy of the hash state now, and restoring it on future
93         // calls to Reset and Sum instead of writing ipad/opad every time.
94         //
95         // If either hash is unmarshalable for whatever reason,
96         // it's safe to bail out here.
97         marshalableInner, innerOK := h.inner.(marshalable)
98         if !innerOK {
99                 return
100         }
101         marshalableOuter, outerOK := h.outer.(marshalable)
102         if !outerOK {
103                 return
104         }
105
106         imarshal, err := marshalableInner.MarshalBinary()
107         if err != nil {
108                 return
109         }
110
111         h.outer.Reset()
112         h.outer.Write(h.opad)
113         omarshal, err := marshalableOuter.MarshalBinary()
114         if err != nil {
115                 return
116         }
117
118         // Marshaling succeeded; save the marshaled state for later
119         h.ipad = imarshal
120         h.opad = omarshal
121         h.marshaled = true
122 }
123
124 // New returns a new HMAC hash using the given hash.Hash type and key.
125 // Note that unlike other hash implementations in the standard library,
126 // the returned Hash does not implement encoding.BinaryMarshaler
127 // or encoding.BinaryUnmarshaler.
128 func New(h func() hash.Hash, key []byte) hash.Hash {
129         if boring.Enabled {
130                 hm := boring.NewHMAC(h, key)
131                 if hm != nil {
132                         return hm
133                 }
134                 // BoringCrypto did not recognize h, so fall through to standard Go code.
135         }
136         hm := new(hmac)
137         hm.outer = h()
138         hm.inner = h()
139         blocksize := hm.inner.BlockSize()
140         hm.ipad = make([]byte, blocksize)
141         hm.opad = make([]byte, blocksize)
142         if len(key) > blocksize {
143                 // If key is too big, hash it.
144                 hm.outer.Write(key)
145                 key = hm.outer.Sum(nil)
146         }
147         copy(hm.ipad, key)
148         copy(hm.opad, key)
149         for i := range hm.ipad {
150                 hm.ipad[i] ^= 0x36
151         }
152         for i := range hm.opad {
153                 hm.opad[i] ^= 0x5c
154         }
155         hm.inner.Write(hm.ipad)
156
157         return hm
158 }
159
160 // Equal compares two MACs for equality without leaking timing information.
161 func Equal(mac1, mac2 []byte) bool {
162         // We don't have to be constant time if the lengths of the MACs are
163         // different as that suggests that a completely different hash function
164         // was used.
165         return subtle.ConstantTimeCompare(mac1, mac2) == 1
166 }