github.com/JimmyHuang454/JLS-go@v0.0.0-20230831150107-90d536585ba0/boring/hmac.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build boringcrypto && linux && (amd64 || arm64) && !android && !cmd_go_bootstrap && !msan 6 7 package boring 8 9 // #include "goboringcrypto.h" 10 import "C" 11 import ( 12 "bytes" 13 "crypto" 14 "hash" 15 "runtime" 16 "unsafe" 17 ) 18 19 // hashToMD converts a hash.Hash implementation from this package 20 // to a BoringCrypto *C.GO_EVP_MD. 21 func hashToMD(h hash.Hash) *C.GO_EVP_MD { 22 switch h.(type) { 23 case *sha1Hash: 24 return C._goboringcrypto_EVP_sha1() 25 case *sha224Hash: 26 return C._goboringcrypto_EVP_sha224() 27 case *sha256Hash: 28 return C._goboringcrypto_EVP_sha256() 29 case *sha384Hash: 30 return C._goboringcrypto_EVP_sha384() 31 case *sha512Hash: 32 return C._goboringcrypto_EVP_sha512() 33 } 34 return nil 35 } 36 37 // cryptoHashToMD converts a crypto.Hash 38 // to a BoringCrypto *C.GO_EVP_MD. 39 func cryptoHashToMD(ch crypto.Hash) *C.GO_EVP_MD { 40 switch ch { 41 case crypto.MD5: 42 return C._goboringcrypto_EVP_md5() 43 case crypto.MD5SHA1: 44 return C._goboringcrypto_EVP_md5_sha1() 45 case crypto.SHA1: 46 return C._goboringcrypto_EVP_sha1() 47 case crypto.SHA224: 48 return C._goboringcrypto_EVP_sha224() 49 case crypto.SHA256: 50 return C._goboringcrypto_EVP_sha256() 51 case crypto.SHA384: 52 return C._goboringcrypto_EVP_sha384() 53 case crypto.SHA512: 54 return C._goboringcrypto_EVP_sha512() 55 } 56 return nil 57 } 58 59 // NewHMAC returns a new HMAC using BoringCrypto. 60 // The function h must return a hash implemented by 61 // BoringCrypto (for example, h could be boring.NewSHA256). 62 // If h is not recognized, NewHMAC returns nil. 63 func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { 64 ch := h() 65 md := hashToMD(ch) 66 if md == nil { 67 return nil 68 } 69 70 // Note: Could hash down long keys here using EVP_Digest. 71 hkey := bytes.Clone(key) 72 hmac := &boringHMAC{ 73 md: md, 74 size: ch.Size(), 75 blockSize: ch.BlockSize(), 76 key: hkey, 77 } 78 hmac.Reset() 79 return hmac 80 } 81 82 type boringHMAC struct { 83 md *C.GO_EVP_MD 84 ctx C.GO_HMAC_CTX 85 ctx2 C.GO_HMAC_CTX 86 size int 87 blockSize int 88 key []byte 89 sum []byte 90 needCleanup bool 91 } 92 93 func (h *boringHMAC) Reset() { 94 if h.needCleanup { 95 C._goboringcrypto_HMAC_CTX_cleanup(&h.ctx) 96 } else { 97 h.needCleanup = true 98 // Note: Because of the finalizer, any time h.ctx is passed to cgo, 99 // that call must be followed by a call to runtime.KeepAlive(h), 100 // to make sure h is not collected (and finalized) before the cgo 101 // call returns. 102 runtime.SetFinalizer(h, (*boringHMAC).finalize) 103 } 104 C._goboringcrypto_HMAC_CTX_init(&h.ctx) 105 106 if C._goboringcrypto_HMAC_Init(&h.ctx, unsafe.Pointer(base(h.key)), C.int(len(h.key)), h.md) == 0 { 107 panic("boringcrypto: HMAC_Init failed") 108 } 109 if int(C._goboringcrypto_HMAC_size(&h.ctx)) != h.size { 110 println("boringcrypto: HMAC size:", C._goboringcrypto_HMAC_size(&h.ctx), "!=", h.size) 111 panic("boringcrypto: HMAC size mismatch") 112 } 113 runtime.KeepAlive(h) // Next line will keep h alive too; just making doubly sure. 114 h.sum = nil 115 } 116 117 func (h *boringHMAC) finalize() { 118 C._goboringcrypto_HMAC_CTX_cleanup(&h.ctx) 119 } 120 121 func (h *boringHMAC) Write(p []byte) (int, error) { 122 if len(p) > 0 { 123 C._goboringcrypto_HMAC_Update(&h.ctx, (*C.uint8_t)(unsafe.Pointer(&p[0])), C.size_t(len(p))) 124 } 125 runtime.KeepAlive(h) 126 return len(p), nil 127 } 128 129 func (h *boringHMAC) Size() int { 130 return h.size 131 } 132 133 func (h *boringHMAC) BlockSize() int { 134 return h.blockSize 135 } 136 137 func (h *boringHMAC) Sum(in []byte) []byte { 138 if h.sum == nil { 139 size := h.Size() 140 h.sum = make([]byte, size) 141 } 142 // Make copy of context because Go hash.Hash mandates 143 // that Sum has no effect on the underlying stream. 144 // In particular it is OK to Sum, then Write more, then Sum again, 145 // and the second Sum acts as if the first didn't happen. 146 C._goboringcrypto_HMAC_CTX_init(&h.ctx2) 147 if C._goboringcrypto_HMAC_CTX_copy_ex(&h.ctx2, &h.ctx) == 0 { 148 panic("boringcrypto: HMAC_CTX_copy_ex failed") 149 } 150 C._goboringcrypto_HMAC_Final(&h.ctx2, (*C.uint8_t)(unsafe.Pointer(&h.sum[0])), nil) 151 C._goboringcrypto_HMAC_CTX_cleanup(&h.ctx2) 152 return append(in, h.sum...) 153 }