crypto/hmac: panic if reusing hash.Hash values
Also put Reset in the correct place for the other
benchmarks.
name old time/op new time/op delta
NewWriteSum-8 1.01µs ± 0% 1.01µs ± 1% ~ (p=0.945 n=9+9)
name old speed new speed delta
NewWriteSum-8 31.7MB/s ± 0% 31.6MB/s ± 1% ~ (p=0.948 n=9+9)
name old alloc/op new alloc/op delta
NewWriteSum-8 544B ± 0% 544B ± 0% ~ (all equal)
name old allocs/op new allocs/op delta
NewWriteSum-8 7.00 ± 0% 7.00 ± 0% ~ (all equal)
Fixes #41089
Change-Id: I3dae660adbe4993963130bf3c2636bd53899164b
Reviewed-on: https://go-review.googlesource.com/c/go/+/261960
Trust: Katie Hockman <katie@golang.org>
Trust: Roland Shoemaker <roland@golang.org>
Run-TryBot: Katie Hockman <katie@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
diff --git a/doc/go1.16.html b/doc/go1.16.html
index 7b99e0c..43bcc77 100644
--- a/doc/go1.16.html
+++ b/doc/go1.16.html
@@ -181,6 +181,14 @@
TODO
</p>
+<h3 id="crypto/hmac"><a href="/pkg/crypto/hmac">crypto/hmac</a></h3>
+
+<p><!-- CL 261960 -->
+ <a href="/pkg/crypto/hmac/#New">New</a> will now panic if separate calls to
+ the hash generation function fail to return new values. Previously, the
+ behavior was undefined and invalid outputs were sometimes generated.
+</p>
+
<h3 id="crypto/tls"><a href="/pkg/crypto/tls">crypto/tls</a></h3>
<p><!-- CL 256897 -->
diff --git a/src/crypto/hmac/hmac.go b/src/crypto/hmac/hmac.go
index a6ba71c..cdda33c 100644
--- a/src/crypto/hmac/hmac.go
+++ b/src/crypto/hmac/hmac.go
@@ -120,6 +120,8 @@
}
// New returns a new HMAC hash using the given hash.Hash type and key.
+// New functions like sha256.New from crypto/sha256 can be used as h.
+// h must return a new Hash every time it is called.
// Note that unlike other hash implementations in the standard library,
// the returned Hash does not implement encoding.BinaryMarshaler
// or encoding.BinaryUnmarshaler.
@@ -127,6 +129,19 @@
hm := new(hmac)
hm.outer = h()
hm.inner = h()
+ unique := true
+ func() {
+ defer func() {
+ // The comparison might panic if the underlying types are not comparable.
+ _ = recover()
+ }()
+ if hm.outer == hm.inner {
+ unique = false
+ }
+ }()
+ if !unique {
+ panic("crypto/hmac: hash generation function does not produce unique values")
+ }
blocksize := hm.inner.BlockSize()
hm.ipad = make([]byte, blocksize)
hm.opad = make([]byte, blocksize)
diff --git a/src/crypto/hmac/hmac_test.go b/src/crypto/hmac/hmac_test.go
index 453bfb3..25e67d7 100644
--- a/src/crypto/hmac/hmac_test.go
+++ b/src/crypto/hmac/hmac_test.go
@@ -556,6 +556,17 @@
}
}
+func TestNonUniqueHash(t *testing.T) {
+ sha := sha256.New()
+ defer func() {
+ err := recover()
+ if err == nil {
+ t.Error("expected panic when calling New with a non-unique hash generation function")
+ }
+ }()
+ New(func() hash.Hash { return sha }, []byte("bytes"))
+}
+
// justHash implements just the hash.Hash methods and nothing else
type justHash struct {
hash.Hash
@@ -587,8 +598,8 @@
b.SetBytes(int64(len(buf)))
for i := 0; i < b.N; i++ {
h.Write(buf)
- h.Reset()
mac := h.Sum(nil)
+ h.Reset()
buf[0] = mac[0]
}
}
@@ -600,7 +611,18 @@
b.SetBytes(int64(len(buf)))
for i := 0; i < b.N; i++ {
h.Write(buf)
+ mac := h.Sum(nil)
h.Reset()
+ buf[0] = mac[0]
+ }
+}
+
+func BenchmarkNewWriteSum(b *testing.B) {
+ buf := make([]byte, 32)
+ b.SetBytes(int64(len(buf)))
+ for i := 0; i < b.N; i++ {
+ h := New(sha256.New, make([]byte, 32))
+ h.Write(buf)
mac := h.Sum(nil)
buf[0] = mac[0]
}