-
Notifications
You must be signed in to change notification settings - Fork 0
/
hmacr.go
100 lines (87 loc) · 1.76 KB
/
hmacr.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package hmacr
import (
"crypto/subtle"
"hash"
)
// HMAC extension of hash.Hash interface with SetKey and ClearKey methods.
type HMAC interface {
hash.Hash
ClearKey()
SetKey(key []byte)
}
type hmacr struct {
inner hash.Hash
outer hash.Hash
ipad []byte
opad []byte
}
// New create a new HMAC with given key.
func New(h func() hash.Hash, key []byte) HMAC {
inner := h()
n := inner.BlockSize()
b := make([]byte, 2*n, 2*n+inner.Size())
r := &hmacr{
inner: inner,
outer: h(),
ipad: b[:n:n],
opad: b[n:],
}
r.SetKey(key)
return r
}
func (r *hmacr) Size() int {
return r.inner.Size()
}
func (r *hmacr) BlockSize() int {
return r.inner.BlockSize()
}
func (r *hmacr) ClearKey() {
for i := range r.ipad {
r.ipad[i] = 0
}
for i := range r.opad {
r.opad[i] = 0
}
r.inner.Reset()
r.outer.Reset()
}
func (r *hmacr) SetKey(key []byte) {
for i := range r.ipad {
r.ipad[i] = 0
}
r.inner.Reset()
if len(key) > r.inner.BlockSize() {
r.inner.Write(key)
r.inner.Sum(r.ipad[:0])
r.inner.Reset()
} else {
copy(r.ipad, key)
}
copy(r.opad, r.ipad)
for i := range r.ipad {
r.ipad[i] ^= 0x36
}
for i := range r.opad {
r.opad[i] ^= 0x5C
}
r.inner.Write(r.ipad)
}
func (r *hmacr) Reset() {
r.inner.Reset()
r.inner.Write(r.ipad)
}
func (r *hmacr) Write(in []byte) (int, error) {
return r.inner.Write(in)
}
func (r *hmacr) Sum(in []byte) []byte {
r.outer.Reset()
r.outer.Write(r.inner.Sum(r.opad))
return r.outer.Sum(in)
}
// Equal compares two MACs for equality without leaking timing information.
func Equal(mac1, mac2 []byte) bool {
// We don't have to be constant time if the lengths of the MACs are
// different as that suggests that a completely different hash function
// was used.
return subtle.ConstantTimeCompare(mac1, mac2) == 1
}