From: Dmitry Chestnykh Date: Tue, 22 Mar 2016 15:41:11 +0000 (+0100) Subject: crypto/hmac: simplify implementation X-Git-Tag: go1.7beta1~1105 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=6a6a0734163567545aed2b558f24f2aafc6c9072;p=gostls13.git crypto/hmac: simplify implementation Store already padded keys instead of storing key and padding it during Reset and Sum. This simplifies code and makes Reset-Write-Sum sequences faster, which helps /x/crypto/pbkdf2. HMAC benchmark: benchmark old ns/op new ns/op delta BenchmarkHMACSHA256_1K-4 7669 7613 -0.73% BenchmarkHMACSHA256_32-4 1880 1737 -7.61% benchmark old MB/s new MB/s speedup BenchmarkHMACSHA256_1K-4 133.52 134.50 1.01x BenchmarkHMACSHA256_32-4 17.02 18.41 1.08x PBKDF2 benchmark: benchmark old ns/op new ns/op delta BenchmarkPBKDF2HMACSHA256-4 1943196 1807699 -6.97% Change-Id: I6697028370c226715ab477b0844951a83eb3488c Reviewed-on: https://go-review.googlesource.com/21024 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Adam Langley --- diff --git a/src/crypto/hmac/hmac.go b/src/crypto/hmac/hmac.go index 3b41cde0bd..a748107838 100644 --- a/src/crypto/hmac/hmac.go +++ b/src/crypto/hmac/hmac.go @@ -37,26 +37,16 @@ import ( type hmac struct { size int blocksize int - key, tmp []byte + opad, ipad []byte outer, inner hash.Hash } -func (h *hmac) tmpPad(xor byte) { - for i, k := range h.key { - h.tmp[i] = xor ^ k - } - for i := len(h.key); i < h.blocksize; i++ { - h.tmp[i] = xor - } -} - func (h *hmac) Sum(in []byte) []byte { origLen := len(in) in = h.inner.Sum(in) - h.tmpPad(0x5c) - copy(h.tmp[h.blocksize:], in[origLen:]) h.outer.Reset() - h.outer.Write(h.tmp) + h.outer.Write(h.opad) + h.outer.Write(in[origLen:]) return h.outer.Sum(in[:origLen]) } @@ -70,8 +60,7 @@ func (h *hmac) BlockSize() int { return h.blocksize } func (h *hmac) Reset() { h.inner.Reset() - h.tmpPad(0x36) - h.inner.Write(h.tmp[:h.blocksize]) + h.inner.Write(h.ipad) } // New returns a new HMAC hash using the given hash.Hash type and key. @@ -81,15 +70,22 @@ func New(h func() hash.Hash, key []byte) hash.Hash { hm.inner = h() hm.size = hm.inner.Size() hm.blocksize = hm.inner.BlockSize() - hm.tmp = make([]byte, hm.blocksize+hm.size) + hm.ipad = make([]byte, hm.blocksize) + hm.opad = make([]byte, hm.blocksize) if len(key) > hm.blocksize { // If key is too big, hash it. hm.outer.Write(key) key = hm.outer.Sum(nil) } - hm.key = make([]byte, len(key)) - copy(hm.key, key) - hm.Reset() + copy(hm.ipad, key) + copy(hm.opad, key) + for i := range hm.ipad { + hm.ipad[i] ^= 0x36 + } + for i := range hm.opad { + hm.opad[i] ^= 0x5c + } + hm.inner.Write(hm.ipad) return hm } diff --git a/src/crypto/hmac/hmac_test.go b/src/crypto/hmac/hmac_test.go index e80b7e0baa..aac9aa96a8 100644 --- a/src/crypto/hmac/hmac_test.go +++ b/src/crypto/hmac/hmac_test.go @@ -568,3 +568,29 @@ func TestEqual(t *testing.T) { t.Error("Equal accepted unequal slices") } } + +func BenchmarkHMACSHA256_1K(b *testing.B) { + key := make([]byte, 32) + buf := make([]byte, 1024) + h := New(sha256.New, key) + b.SetBytes(int64(len(buf))) + for i := 0; i < b.N; i++ { + h.Write(buf) + h.Reset() + mac := h.Sum(nil) + buf[0] = mac[0] + } +} + +func BenchmarkHMACSHA256_32(b *testing.B) { + key := make([]byte, 32) + buf := make([]byte, 32) + h := New(sha256.New, key) + b.SetBytes(int64(len(buf))) + for i := 0; i < b.N; i++ { + h.Write(buf) + h.Reset() + mac := h.Sum(nil) + buf[0] = mac[0] + } +}