]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.boringcrypto] crypto/hmac: use BoringCrypto
authorRuss Cox <rsc@golang.org>
Thu, 3 Aug 2017 04:02:43 +0000 (00:02 -0400)
committerRuss Cox <rsc@golang.org>
Thu, 17 Aug 2017 19:32:23 +0000 (19:32 +0000)
Change-Id: Id4019d601c615b4835b0337d82be3d508292810e
Reviewed-on: https://go-review.googlesource.com/55475
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
src/crypto/hmac/hmac.go
src/crypto/internal/boring/hmac.go [new file with mode: 0644]
src/crypto/internal/boring/notboring.go

index 9ef9c448ee20b1d8fac437e385748e1c8e4b9568..69969636600e5092fb1f5da523d96fa369561404 100644 (file)
@@ -22,6 +22,7 @@ timing side-channels:
 package hmac
 
 import (
+       "crypto/internal/boring"
        "crypto/subtle"
        "hash"
 )
@@ -65,6 +66,13 @@ func (h *hmac) Reset() {
 
 // New returns a new HMAC hash using the given hash.Hash type and key.
 func New(h func() hash.Hash, key []byte) hash.Hash {
+       if boring.Enabled {
+               hm := boring.NewHMAC(h, key)
+               if hm != nil {
+                       return hm
+               }
+               // BoringCrypto did not recognize h, so fall through to standard Go code.
+       }
        hm := new(hmac)
        hm.outer = h()
        hm.inner = h()
diff --git a/src/crypto/internal/boring/hmac.go b/src/crypto/internal/boring/hmac.go
new file mode 100644 (file)
index 0000000..a70bc5e
--- /dev/null
@@ -0,0 +1,137 @@
+// Copyright 2017 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.
+
+// +build linux,amd64
+// +build !cmd_go_bootstrap
+
+package boring
+
+// #include "goboringcrypto.h"
+import "C"
+import (
+       "hash"
+       "runtime"
+       "unsafe"
+)
+
+// hashToMD converts a hash.Hash implementation from this package
+// to a BoringCrypto *C.GO_EVP_MD.
+func hashToMD(h hash.Hash) *C.GO_EVP_MD {
+       switch h.(type) {
+       case *sha1Hash:
+               return C._goboringcrypto_EVP_sha1()
+       case *sha224Hash:
+               return C._goboringcrypto_EVP_sha224()
+       case *sha256Hash:
+               return C._goboringcrypto_EVP_sha256()
+       case *sha384Hash:
+               return C._goboringcrypto_EVP_sha384()
+       case *sha512Hash:
+               return C._goboringcrypto_EVP_sha512()
+       }
+       return nil
+}
+
+// NewHMAC returns a new HMAC using BoringCrypto.
+// The function h must return a hash implemented by
+// BoringCrypto (for example, h could be boring.NewSHA256).
+// If h is not recognized, NewHMAC returns nil.
+func NewHMAC(h func() hash.Hash, key []byte) hash.Hash {
+       ch := h()
+       md := hashToMD(ch)
+       if md == nil {
+               return nil
+       }
+
+       // Note: Could hash down long keys here using EVP_Digest.
+       hkey := make([]byte, len(key))
+       copy(hkey, key)
+       hmac := &boringHMAC{
+               md:        md,
+               size:      ch.Size(),
+               blockSize: ch.BlockSize(),
+               key:       hkey,
+       }
+       hmac.Reset()
+       return hmac
+}
+
+type boringHMAC struct {
+       md          *C.GO_EVP_MD
+       ctx         C.GO_HMAC_CTX
+       size        int
+       blockSize   int
+       key         []byte
+       sum         []byte
+       needCleanup bool
+}
+
+func (h *boringHMAC) Reset() {
+       if h.needCleanup {
+               C._goboringcrypto_HMAC_CTX_cleanup(&h.ctx)
+       } else {
+               h.needCleanup = true
+               runtime.SetFinalizer(h, (*boringHMAC).finalize)
+       }
+       C._goboringcrypto_HMAC_CTX_init(&h.ctx)
+
+       if C._goboringcrypto_HMAC_Init(&h.ctx, unsafe.Pointer(&h.key[0]), C.int(len(h.key)), h.md) == 0 {
+               panic("boringcrypto: HMAC_Init failed")
+       }
+       if int(C._goboringcrypto_HMAC_size(&h.ctx)) != h.size {
+               println("boringcrypto: HMAC size:", C._goboringcrypto_HMAC_size(&h.ctx), "!=", h.size)
+               panic("boringcrypto: HMAC size mismatch")
+       }
+       h.sum = nil
+}
+
+func (h *boringHMAC) finalize() {
+       C._goboringcrypto_HMAC_CTX_cleanup(&h.ctx)
+}
+
+var badSum = make([]byte, 1)
+
+func (h *boringHMAC) Write(p []byte) (int, error) {
+       if h.sum != nil {
+               h.sum = badSum
+       } else if len(p) > 0 {
+               C._goboringcrypto_HMAC_Update(&h.ctx, (*C.uint8_t)(unsafe.Pointer(&p[0])), C.size_t(len(p)))
+       }
+       return len(p), nil
+}
+
+func (h *boringHMAC) Size() int {
+       return h.size
+}
+
+func (h *boringHMAC) BlockSize() int {
+       return h.blockSize
+}
+
+func (h *boringHMAC) Sum(in []byte) []byte {
+       if h.sum == nil {
+               size := h.Size()
+               h.sum = make([]byte, size)
+               C._goboringcrypto_HMAC_Final(&h.ctx, (*C.uint8_t)(unsafe.Pointer(&h.sum[0])), nil)
+
+               // Clean up and disable finalizer since most of the time
+               // there is no Reset coming. If we do get a Reset, we will
+               // re-enable the finalizer. We have a saved copy of the key.
+               C._goboringcrypto_HMAC_CTX_cleanup(&h.ctx)
+               h.needCleanup = false
+               runtime.SetFinalizer(h, nil)
+       } else if &h.sum[0] == &badSum[0] {
+               // crypto/tls's tls10.MAC method calls Write after Sum,
+               // in an attempt to do more-like-constant-time checksums
+               // during TLS 1.0 SHA1-based MACs. We can't support that,
+               // so we ignore the Write in that case above, but we also
+               // poison h.sum so that future Sum calls panic, to avoid
+               // returning the pre-Write checksum.
+               // We expect no code actually does Sum, Write, Sum.
+               // Under FIPS restrictions, crypto/tls would not use
+               // any SHA1-based MACs anyway.
+               panic("boringcrypto: hmac used with Sum, Write, Sum")
+       }
+       return append(in, h.sum...)
+}
index 6cd1413239a764914aaaec1f7a41bf083241fd3d..727247bc619765a9dc41f7b13bd1542cb2f8e3d4 100644 (file)
@@ -29,3 +29,5 @@ func NewSHA224() hash.Hash { panic("boringcrypto: not available") }
 func NewSHA256() hash.Hash { panic("boringcrypto: not available") }
 func NewSHA384() hash.Hash { panic("boringcrypto: not available") }
 func NewSHA512() hash.Hash { panic("boringcrypto: not available") }
+
+func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { panic("boringcrypto: not available") }