aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2017-08-03 00:02:43 -0400
committerRuss Cox <rsc@golang.org>2017-08-26 00:52:18 +0000
commit065bb6eb3012d2dcdd8a58b7f772a1542af4520f (patch)
tree563169e841c550ae20c0994b284a61deea2717c2
parent367461427eaa93142bf27547b13d861b59f58be9 (diff)
downloadgo-065bb6eb3012d2dcdd8a58b7f772a1542af4520f.tar.gz
go-065bb6eb3012d2dcdd8a58b7f772a1542af4520f.zip
[dev.boringcrypto.go1.8] crypto/hmac: use BoringCrypto
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> Reviewed-on: https://go-review.googlesource.com/57936
-rw-r--r--src/crypto/hmac/hmac.go8
-rw-r--r--src/crypto/internal/boring/hmac.go137
-rw-r--r--src/crypto/internal/boring/notboring.go2
3 files changed, 147 insertions, 0 deletions
diff --git a/src/crypto/hmac/hmac.go b/src/crypto/hmac/hmac.go
index 9ef9c448ee..6996963660 100644
--- a/src/crypto/hmac/hmac.go
+++ b/src/crypto/hmac/hmac.go
@@ -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
index 0000000000..a70bc5ee8b
--- /dev/null
+++ b/src/crypto/internal/boring/hmac.go
@@ -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...)
+}
diff --git a/src/crypto/internal/boring/notboring.go b/src/crypto/internal/boring/notboring.go
index 6cd1413239..727247bc61 100644
--- a/src/crypto/internal/boring/notboring.go
+++ b/src/crypto/internal/boring/notboring.go
@@ -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") }