github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/pkg/net/proxy/shadowsocksr/utils/hmac.go (about)

     1  package ssr
     2  
     3  import (
     4  	"crypto"
     5  	"hash"
     6  )
     7  
     8  type CHmac interface {
     9  	hash.Hash
    10  	ResetKey(key []byte)
    11  	Hash() crypto.Hash
    12  }
    13  
    14  type chmac struct {
    15  	opad, ipad   []byte
    16  	outer, inner hash.Hash
    17  
    18  	h crypto.Hash
    19  }
    20  
    21  func (h *chmac) Sum(in []byte) []byte {
    22  	origLen := len(in)
    23  	in = h.inner.Sum(in)
    24  
    25  	h.outer.Reset()
    26  	h.outer.Write(h.opad)
    27  	h.outer.Write(in[origLen:])
    28  	return h.outer.Sum(in[:origLen])
    29  }
    30  
    31  func (h *chmac) Write(p []byte) (n int, err error) {
    32  	return h.inner.Write(p)
    33  }
    34  
    35  func (h *chmac) Size() int      { return h.outer.Size() }
    36  func (h *chmac) BlockSize() int { return h.inner.BlockSize() }
    37  
    38  func memsetRepeat(a []byte, v byte) {
    39  	if len(a) == 0 {
    40  		return
    41  	}
    42  	a[0] = v
    43  	for bp := 1; bp < len(a); bp *= 2 {
    44  		copy(a[bp:], a[:bp])
    45  	}
    46  }
    47  
    48  func (h *chmac) Reset() { h.ResetKey(nil) }
    49  
    50  func (h *chmac) ResetKey(key []byte) {
    51  	if key != nil {
    52  		blockSize := h.inner.BlockSize()
    53  		if len(key) > blockSize {
    54  			h.outer.Reset()
    55  			// If key is too big, hash it.
    56  			h.outer.Write(key)
    57  			key = h.outer.Sum(nil)
    58  		}
    59  		memsetRepeat(h.ipad, 0x0)
    60  		memsetRepeat(h.opad, 0x0)
    61  		copy(h.ipad, key)
    62  		copy(h.opad, key)
    63  		for i := range h.ipad {
    64  			h.ipad[i] ^= 0x36
    65  		}
    66  		for i := range h.opad {
    67  			h.opad[i] ^= 0x5c
    68  		}
    69  	}
    70  	h.inner.Reset()
    71  	h.inner.Write(h.ipad)
    72  }
    73  
    74  // NewHmac returns a new HMAC hash using the given hash.Hash type and key.
    75  // NewHmac functions like sha256.NewHmac from crypto/sha256 can be used as h.
    76  // h must return a new Hash every time it is called.
    77  // Note that unlike other hash implementations in the standard library,
    78  // the returned Hash does not implement encoding.BinaryMarshaler
    79  // or encoding.BinaryUnmarshaler.
    80  func NewHmac(h crypto.Hash) CHmac {
    81  	hm := new(chmac)
    82  	hm.h = h
    83  	hm.outer = h.New()
    84  	hm.inner = h.New()
    85  	unique := true
    86  	func() {
    87  		defer func() {
    88  			// The comparison might panic if the underlying types are not comparable.
    89  			_ = recover()
    90  		}()
    91  		if hm.outer == hm.inner {
    92  			unique = false
    93  		}
    94  	}()
    95  	if !unique {
    96  		panic("crypto/hmac: hash generation function does not produce unique values")
    97  	}
    98  	blocksize := hm.inner.BlockSize()
    99  	hm.ipad = make([]byte, blocksize)
   100  	hm.opad = make([]byte, blocksize)
   101  	return hm
   102  }
   103  
   104  func (h *chmac) Hash() crypto.Hash { return h.h }