]> Cypherpunks.ru repositories - gostls13.git/blob - src/crypto/hmac/hmac.go
[dev.boringcrypto] misc/boring: add go1.9.2b4 release
[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         // CheckMAC reports whether messageMAC is a valid HMAC tag for message.
15         func CheckMAC(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/internal/boring"
26         "crypto/subtle"
27         "hash"
28 )
29
30 // FIPS 198-1:
31 // http://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf
32
33 // key is zero padded to the block size of the hash function
34 // ipad = 0x36 byte repeated for key length
35 // opad = 0x5c byte repeated for key length
36 // hmac = H([key ^ opad] H([key ^ ipad] text))
37
38 type hmac struct {
39         size         int
40         blocksize    int
41         opad, ipad   []byte
42         outer, inner hash.Hash
43 }
44
45 func (h *hmac) Sum(in []byte) []byte {
46         origLen := len(in)
47         in = h.inner.Sum(in)
48         h.outer.Reset()
49         h.outer.Write(h.opad)
50         h.outer.Write(in[origLen:])
51         return h.outer.Sum(in[:origLen])
52 }
53
54 func (h *hmac) Write(p []byte) (n int, err error) {
55         return h.inner.Write(p)
56 }
57
58 func (h *hmac) Size() int { return h.size }
59
60 func (h *hmac) BlockSize() int { return h.blocksize }
61
62 func (h *hmac) Reset() {
63         h.inner.Reset()
64         h.inner.Write(h.ipad)
65 }
66
67 // New returns a new HMAC hash using the given hash.Hash type and key.
68 func New(h func() hash.Hash, key []byte) hash.Hash {
69         if boring.Enabled {
70                 hm := boring.NewHMAC(h, key)
71                 if hm != nil {
72                         return hm
73                 }
74                 // BoringCrypto did not recognize h, so fall through to standard Go code.
75         }
76         hm := new(hmac)
77         hm.outer = h()
78         hm.inner = h()
79         hm.size = hm.inner.Size()
80         hm.blocksize = hm.inner.BlockSize()
81         hm.ipad = make([]byte, hm.blocksize)
82         hm.opad = make([]byte, hm.blocksize)
83         if len(key) > hm.blocksize {
84                 // If key is too big, hash it.
85                 hm.outer.Write(key)
86                 key = hm.outer.Sum(nil)
87         }
88         copy(hm.ipad, key)
89         copy(hm.opad, key)
90         for i := range hm.ipad {
91                 hm.ipad[i] ^= 0x36
92         }
93         for i := range hm.opad {
94                 hm.opad[i] ^= 0x5c
95         }
96         hm.inner.Write(hm.ipad)
97         return hm
98 }
99
100 // Equal compares two MACs for equality without leaking timing information.
101 func Equal(mac1, mac2 []byte) bool {
102         // We don't have to be constant time if the lengths of the MACs are
103         // different as that suggests that a completely different hash function
104         // was used.
105         return subtle.ConstantTimeCompare(mac1, mac2) == 1
106 }