github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/commons/signatures/hmac.go (about) 1 /* 2 * Copyright 2023 Wang Min Xiang 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package signatures 19 20 import ( 21 "crypto/hmac" 22 "encoding/hex" 23 "github.com/cespare/xxhash/v2" 24 "hash" 25 "sync" 26 ) 27 28 func HMAC(key []byte) Signature { 29 h := &hmacSigner{ 30 key: key, 31 pool: sync.Pool{}, 32 } 33 h.pool.New = func() any { 34 return hmac.New(func() hash.Hash { 35 return xxhash.New() 36 }, h.key) 37 } 38 return h 39 } 40 41 type hmacSigner struct { 42 key []byte 43 pool sync.Pool 44 } 45 46 func (s *hmacSigner) acquire() (h hash.Hash) { 47 v := s.pool.Get() 48 if v != nil { 49 h = v.(hash.Hash) 50 return 51 } 52 h = hmac.New(func() hash.Hash { 53 return xxhash.New() 54 }, s.key) 55 return 56 } 57 58 func (s *hmacSigner) release(h hash.Hash) { 59 h.Reset() 60 s.pool.Put(h) 61 return 62 } 63 64 func (s *hmacSigner) Sign(target []byte) (signature []byte) { 65 h := s.acquire() 66 h.Write(target) 67 p := h.Sum(nil) 68 s.release(h) 69 signature = make([]byte, hex.EncodedLen(len(p))) 70 hex.Encode(signature, p) 71 return 72 } 73 74 func (s *hmacSigner) Verify(target []byte, signature []byte) (ok bool) { 75 n, err := hex.Decode(signature, signature) 76 if err != nil { 77 return 78 } 79 signature = signature[0:n] 80 h := s.acquire() 81 h.Write(target) 82 p := h.Sum(nil) 83 s.release(h) 84 ok = hmac.Equal(p, signature) 85 return 86 }