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 }