Source File
hmac.go
Belonging Package
crypto/hmac
// Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file./*Package hmac implements the Keyed-Hash Message Authentication Code (HMAC) asdefined in U.S. Federal Information Processing Standards Publication 198.An HMAC is a cryptographic hash that uses a key to sign a message.The receiver verifies the hash by recomputing it using the same key.Receivers should be careful to use Equal to compare MACs in order to avoidtiming side-channels:// ValidMAC reports whether messageMAC is a valid HMAC tag for message.func ValidMAC(message, messageMAC, key []byte) bool {mac := hmac.New(sha256.New, key)mac.Write(message)expectedMAC := mac.Sum(nil)return hmac.Equal(messageMAC, expectedMAC)}*/package hmacimport ()// FIPS 198-1:// https://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf// key is zero padded to the block size of the hash function// ipad = 0x36 byte repeated for key length// 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 {opad, ipad []byteouter, 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 ( *hmac) ( []byte) []byte {:= len()= .inner.Sum()if .marshaled {if := .outer.(marshalable).UnmarshalBinary(.opad); != nil {panic()}} else {.outer.Reset().outer.Write(.opad)}.outer.Write([:])return .outer.Sum([:])}func ( *hmac) ( []byte) ( int, error) {return .inner.Write()}func ( *hmac) () int { return .outer.Size() }func ( *hmac) () int { return .inner.BlockSize() }func ( *hmac) () {if .marshaled {if := .inner.(marshalable).UnmarshalBinary(.ipad); != nil {panic()}return}.inner.Reset().inner.Write(.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., := .inner.(marshalable)if ! {return}, := .outer.(marshalable)if ! {return}, := .MarshalBinary()if != nil {return}.outer.Reset().outer.Write(.opad), := .MarshalBinary()if != nil {return}// Marshaling succeeded; save the marshaled state for later.ipad =.opad =.marshaled = true}// 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.func ( func() hash.Hash, []byte) hash.Hash {:= new(hmac).outer = ().inner = ():= truefunc() {defer func() {// The comparison might panic if the underlying types are not comparable._ = recover()}()if .outer == .inner {= false}}()if ! {panic("crypto/hmac: hash generation function does not produce unique values")}:= .inner.BlockSize().ipad = make([]byte, ).opad = make([]byte, )if len() > {// If key is too big, hash it..outer.Write()= .outer.Sum(nil)}copy(.ipad, )copy(.opad, )for := range .ipad {.ipad[] ^= 0x36}for := range .opad {.opad[] ^= 0x5c}.inner.Write(.ipad)return}// Equal compares two MACs for equality without leaking timing information.func (, []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(, ) == 1}