diff options
Diffstat (limited to 'libgo/go/crypto/hmac/hmac.go')
-rw-r--r-- | libgo/go/crypto/hmac/hmac.go | 80 |
1 files changed, 68 insertions, 12 deletions
diff --git a/libgo/go/crypto/hmac/hmac.go b/libgo/go/crypto/hmac/hmac.go index 801ece6..a6ba71c 100644 --- a/libgo/go/crypto/hmac/hmac.go +++ b/libgo/go/crypto/hmac/hmac.go @@ -34,18 +34,36 @@ import ( // opad = 0x5c byte repeated for key length // hmac = H([key ^ opad] H([key ^ ipad] text)) +// Marshalable is the combination of encoding.BinaryMarshaler and +// encoding.BinaryUnmarshaler. Their method definitions are repeated here to +// avoid a dependency on the encoding package. +type marshalable interface { + MarshalBinary() ([]byte, error) + UnmarshalBinary([]byte) error +} + type hmac struct { - size int - blocksize int opad, ipad []byte outer, inner hash.Hash + + // If marshaled is true, then opad and ipad do not contain a padded + // copy of the key, but rather the marshaled state of outer/inner after + // opad/ipad has been fed into it. + marshaled bool } func (h *hmac) Sum(in []byte) []byte { origLen := len(in) in = h.inner.Sum(in) - h.outer.Reset() - h.outer.Write(h.opad) + + if h.marshaled { + if err := h.outer.(marshalable).UnmarshalBinary(h.opad); err != nil { + panic(err) + } + } else { + h.outer.Reset() + h.outer.Write(h.opad) + } h.outer.Write(in[origLen:]) return h.outer.Sum(in[:origLen]) } @@ -54,13 +72,51 @@ func (h *hmac) Write(p []byte) (n int, err error) { return h.inner.Write(p) } -func (h *hmac) Size() int { return h.size } - -func (h *hmac) BlockSize() int { return h.blocksize } +func (h *hmac) Size() int { return h.outer.Size() } +func (h *hmac) BlockSize() int { return h.inner.BlockSize() } func (h *hmac) Reset() { + if h.marshaled { + if err := h.inner.(marshalable).UnmarshalBinary(h.ipad); err != nil { + panic(err) + } + return + } + h.inner.Reset() h.inner.Write(h.ipad) + + // If the underlying hash is marshalable, we can save some time by + // saving a copy of the hash state now, and restoring it on future + // calls to Reset and Sum instead of writing ipad/opad every time. + // + // If either hash is unmarshalable for whatever reason, + // it's safe to bail out here. + marshalableInner, innerOK := h.inner.(marshalable) + if !innerOK { + return + } + marshalableOuter, outerOK := h.outer.(marshalable) + if !outerOK { + return + } + + imarshal, err := marshalableInner.MarshalBinary() + if err != nil { + return + } + + h.outer.Reset() + h.outer.Write(h.opad) + omarshal, err := marshalableOuter.MarshalBinary() + if err != nil { + return + } + + // Marshaling succeeded; save the marshaled state for later + h.ipad = imarshal + h.opad = omarshal + h.marshaled = true } // New returns a new HMAC hash using the given hash.Hash type and key. @@ -71,11 +127,10 @@ func New(h func() hash.Hash, key []byte) hash.Hash { hm := new(hmac) hm.outer = h() hm.inner = h() - hm.size = hm.inner.Size() - hm.blocksize = hm.inner.BlockSize() - hm.ipad = make([]byte, hm.blocksize) - hm.opad = make([]byte, hm.blocksize) - if len(key) > hm.blocksize { + blocksize := hm.inner.BlockSize() + hm.ipad = make([]byte, blocksize) + hm.opad = make([]byte, blocksize) + if len(key) > blocksize { // If key is too big, hash it. hm.outer.Write(key) key = hm.outer.Sum(nil) @@ -89,6 +144,7 @@ func New(h func() hash.Hash, key []byte) hash.Hash { hm.opad[i] ^= 0x5c } hm.inner.Write(hm.ipad) + return hm } |