[go/dev.boringcrypto] crypto/boring: Refactor boringcrypto codebase

50 views
Skip to first unread message

Gerrit Bot (Gerrit)

unread,
Jul 6, 2021, 6:25:19 PM7/6/21
to goph...@pubsubhelper.golang.org, Derek Parker, golang-co...@googlegroups.com

Gerrit Bot has uploaded this change for review.

View Change

crypto/boring: Refactor boringcrypto codebase

This patch refactors the boringcrypto implementation in an attempt to
make it more general and abstract away the actual external crypto
backend being used.

This is in effort to enable other external crypto libraries such as
OpenSSL to be used instead.

This approach uses a series of small, targeted and unexported interfaces which represent an "external" crypto library. The initial "external" crypto library is, of course, boringcrypto. The change makes it so the "backend" crypto implementation of the `boring` package can be swapped out without requiring any new imports throughout the rest of the code base. Calls into the `boring` package will defer the actual implementation to this "external" crypto library.

Change-Id: I50e43d25c308065f14082f1a702b2a183295d7bf
GitHub-Last-Rev: 43628cf3c775a3e333008cb42cd523830b059405
GitHub-Pull-Request: golang/go#47073
---
M src/cmd/link/internal/ld/lib.go
M src/crypto/internal/boring/aes.go
M src/crypto/internal/boring/boring.go
R src/crypto/internal/boring/boringcrypto/Dockerfile
A src/crypto/internal/boring/boringcrypto/aes.go
A src/crypto/internal/boring/boringcrypto/boringcrypto.go
R src/crypto/internal/boring/boringcrypto/build.sh
A src/crypto/internal/boring/boringcrypto/ecdsa.go
R src/crypto/internal/boring/boringcrypto/goboringcrypto.h
R src/crypto/internal/boring/boringcrypto/goboringcrypto_linux_amd64.syso
A src/crypto/internal/boring/boringcrypto/hmac.go
A src/crypto/internal/boring/boringcrypto/rand.go
A src/crypto/internal/boring/boringcrypto/rsa.go
A src/crypto/internal/boring/boringcrypto/sha.go
M src/crypto/internal/boring/ecdsa.go
M src/crypto/internal/boring/hmac.go
M src/crypto/internal/boring/rand.go
M src/crypto/internal/boring/rsa.go
M src/crypto/internal/boring/sha.go
19 files changed, 1,759 insertions(+), 1,410 deletions(-)

diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index eb85c88..1a18353 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -1008,6 +1008,7 @@
// Others trigger external mode.
var internalpkg = []string{
"crypto/internal/boring",
+ "crypto/internal/boring/boringcrypto",
"crypto/x509",
"net",
"os/user",
diff --git a/src/crypto/internal/boring/aes.go b/src/crypto/internal/boring/aes.go
index 504a841..9a93ef7 100644
--- a/src/crypto/internal/boring/aes.go
+++ b/src/crypto/internal/boring/aes.go
@@ -9,383 +9,14 @@

package boring

-/*
-
-#include "goboringcrypto.h"
-
-// These wrappers allocate out_len on the C stack, and check that it matches the expected
-// value, to avoid having to pass a pointer from Go, which would escape to the heap.
-
-int EVP_AEAD_CTX_seal_wrapper(const GO_EVP_AEAD_CTX *ctx, uint8_t *out,
- size_t exp_out_len,
- const uint8_t *nonce, size_t nonce_len,
- const uint8_t *in, size_t in_len,
- const uint8_t *ad, size_t ad_len) {
- size_t out_len;
- int ok = _goboringcrypto_EVP_AEAD_CTX_seal(ctx, out, &out_len, exp_out_len,
- nonce, nonce_len, in, in_len, ad, ad_len);
- if (out_len != exp_out_len) {
- return 0;
- }
- return ok;
-};
-
-int EVP_AEAD_CTX_open_wrapper(const GO_EVP_AEAD_CTX *ctx, uint8_t *out,
- size_t exp_out_len,
- const uint8_t *nonce, size_t nonce_len,
- const uint8_t *in, size_t in_len,
- const uint8_t *ad, size_t ad_len) {
- size_t out_len;
- int ok = _goboringcrypto_EVP_AEAD_CTX_open(ctx, out, &out_len, exp_out_len,
- nonce, nonce_len, in, in_len, ad, ad_len);
- if (out_len != exp_out_len) {
- return 0;
- }
- return ok;
-};
-
-*/
-import "C"
import (
"crypto/cipher"
- "errors"
- "runtime"
- "strconv"
- "unsafe"
)

-type aesKeySizeError int
-
-func (k aesKeySizeError) Error() string {
- return "crypto/aes: invalid key size " + strconv.Itoa(int(k))
+type aes interface {
+ NewAESCipher(key []byte) (cipher.Block, error)
}

-const aesBlockSize = 16
-
-type aesCipher struct {
- key []byte
- enc C.GO_AES_KEY
- dec C.GO_AES_KEY
-}
-
-type extraModes interface {
- // Copied out of crypto/aes/modes.go.
- NewCBCEncrypter(iv []byte) cipher.BlockMode
- NewCBCDecrypter(iv []byte) cipher.BlockMode
- NewCTR(iv []byte) cipher.Stream
- NewGCM(nonceSize, tagSize int) (cipher.AEAD, error)
-
- // Invented for BoringCrypto.
- NewGCMTLS() (cipher.AEAD, error)
-}
-
-var _ extraModes = (*aesCipher)(nil)
-
func NewAESCipher(key []byte) (cipher.Block, error) {
- c := &aesCipher{key: make([]byte, len(key))}
- copy(c.key, key)
- // Note: 0 is success, contradicting the usual BoringCrypto convention.
- if C._goboringcrypto_AES_set_decrypt_key((*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.uint(8*len(c.key)), &c.dec) != 0 ||
- C._goboringcrypto_AES_set_encrypt_key((*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.uint(8*len(c.key)), &c.enc) != 0 {
- return nil, aesKeySizeError(len(key))
- }
- return c, nil
-}
-
-func (c *aesCipher) BlockSize() int { return aesBlockSize }
-
-func (c *aesCipher) Encrypt(dst, src []byte) {
- if inexactOverlap(dst, src) {
- panic("crypto/cipher: invalid buffer overlap")
- }
- if len(src) < aesBlockSize {
- panic("crypto/aes: input not full block")
- }
- if len(dst) < aesBlockSize {
- panic("crypto/aes: output not full block")
- }
- C._goboringcrypto_AES_encrypt(
- (*C.uint8_t)(unsafe.Pointer(&src[0])),
- (*C.uint8_t)(unsafe.Pointer(&dst[0])),
- &c.enc)
-}
-
-func (c *aesCipher) Decrypt(dst, src []byte) {
- if inexactOverlap(dst, src) {
- panic("crypto/cipher: invalid buffer overlap")
- }
- if len(src) < aesBlockSize {
- panic("crypto/aes: input not full block")
- }
- if len(dst) < aesBlockSize {
- panic("crypto/aes: output not full block")
- }
- C._goboringcrypto_AES_decrypt(
- (*C.uint8_t)(unsafe.Pointer(&src[0])),
- (*C.uint8_t)(unsafe.Pointer(&dst[0])),
- &c.dec)
-}
-
-type aesCBC struct {
- key *C.GO_AES_KEY
- mode C.int
- iv [aesBlockSize]byte
-}
-
-func (x *aesCBC) BlockSize() int { return aesBlockSize }
-
-func (x *aesCBC) CryptBlocks(dst, src []byte) {
- if inexactOverlap(dst, src) {
- panic("crypto/cipher: invalid buffer overlap")
- }
- if len(src)%aesBlockSize != 0 {
- panic("crypto/cipher: input not full blocks")
- }
- if len(dst) < len(src) {
- panic("crypto/cipher: output smaller than input")
- }
- if len(src) > 0 {
- C._goboringcrypto_AES_cbc_encrypt(
- (*C.uint8_t)(unsafe.Pointer(&src[0])),
- (*C.uint8_t)(unsafe.Pointer(&dst[0])),
- C.size_t(len(src)), x.key,
- (*C.uint8_t)(unsafe.Pointer(&x.iv[0])), x.mode)
- }
-}
-
-func (x *aesCBC) SetIV(iv []byte) {
- if len(iv) != aesBlockSize {
- panic("cipher: incorrect length IV")
- }
- copy(x.iv[:], iv)
-}
-
-func (c *aesCipher) NewCBCEncrypter(iv []byte) cipher.BlockMode {
- x := &aesCBC{key: &c.enc, mode: C.GO_AES_ENCRYPT}
- copy(x.iv[:], iv)
- return x
-}
-
-func (c *aesCipher) NewCBCDecrypter(iv []byte) cipher.BlockMode {
- x := &aesCBC{key: &c.dec, mode: C.GO_AES_DECRYPT}
- copy(x.iv[:], iv)
- return x
-}
-
-type aesCTR struct {
- key *C.GO_AES_KEY
- iv [aesBlockSize]byte
- num C.uint
- ecount_buf [16]C.uint8_t
-}
-
-func (x *aesCTR) XORKeyStream(dst, src []byte) {
- if inexactOverlap(dst, src) {
- panic("crypto/cipher: invalid buffer overlap")
- }
- if len(dst) < len(src) {
- panic("crypto/cipher: output smaller than input")
- }
- if len(src) == 0 {
- return
- }
- C._goboringcrypto_AES_ctr128_encrypt(
- (*C.uint8_t)(unsafe.Pointer(&src[0])),
- (*C.uint8_t)(unsafe.Pointer(&dst[0])),
- C.size_t(len(src)), x.key, (*C.uint8_t)(unsafe.Pointer(&x.iv[0])),
- &x.ecount_buf[0], &x.num)
-}
-
-func (c *aesCipher) NewCTR(iv []byte) cipher.Stream {
- x := &aesCTR{key: &c.enc}
- copy(x.iv[:], iv)
- return x
-}
-
-type aesGCM struct {
- ctx C.GO_EVP_AEAD_CTX
- aead *C.GO_EVP_AEAD
-}
-
-const (
- gcmBlockSize = 16
- gcmTagSize = 16
- gcmStandardNonceSize = 12
-)
-
-type aesNonceSizeError int
-
-func (n aesNonceSizeError) Error() string {
- return "crypto/aes: invalid GCM nonce size " + strconv.Itoa(int(n))
-}
-
-type noGCM struct {
- cipher.Block
-}
-
-func (c *aesCipher) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
- if nonceSize != gcmStandardNonceSize && tagSize != gcmTagSize {
- return nil, errors.New("crypto/aes: GCM tag and nonce sizes can't be non-standard at the same time")
- }
- // Fall back to standard library for GCM with non-standard nonce or tag size.
- if nonceSize != gcmStandardNonceSize {
- return cipher.NewGCMWithNonceSize(&noGCM{c}, nonceSize)
- }
- if tagSize != gcmTagSize {
- return cipher.NewGCMWithTagSize(&noGCM{c}, tagSize)
- }
- return c.newGCM(false)
-}
-
-func (c *aesCipher) NewGCMTLS() (cipher.AEAD, error) {
- return c.newGCM(true)
-}
-
-func (c *aesCipher) newGCM(tls bool) (cipher.AEAD, error) {
- var aead *C.GO_EVP_AEAD
- switch len(c.key) * 8 {
- case 128:
- if tls {
- aead = C._goboringcrypto_EVP_aead_aes_128_gcm_tls12()
- } else {
- aead = C._goboringcrypto_EVP_aead_aes_128_gcm()
- }
- case 256:
- if tls {
- aead = C._goboringcrypto_EVP_aead_aes_256_gcm_tls12()
- } else {
- aead = C._goboringcrypto_EVP_aead_aes_256_gcm()
- }
- default:
- // Fall back to standard library for GCM with non-standard key size.
- return cipher.NewGCMWithNonceSize(&noGCM{c}, gcmStandardNonceSize)
- }
-
- g := &aesGCM{aead: aead}
- if C._goboringcrypto_EVP_AEAD_CTX_init(&g.ctx, aead, (*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.size_t(len(c.key)), C.GO_EVP_AEAD_DEFAULT_TAG_LENGTH, nil) == 0 {
- return nil, fail("EVP_AEAD_CTX_init")
- }
- // Note: Because of the finalizer, any time g.ctx is passed to cgo,
- // that call must be followed by a call to runtime.KeepAlive(g),
- // to make sure g is not collected (and finalized) before the cgo
- // call returns.
- runtime.SetFinalizer(g, (*aesGCM).finalize)
- if g.NonceSize() != gcmStandardNonceSize {
- panic("boringcrypto: internal confusion about nonce size")
- }
- if g.Overhead() != gcmTagSize {
- panic("boringcrypto: internal confusion about tag size")
- }
-
- return g, nil
-}
-
-func (g *aesGCM) finalize() {
- C._goboringcrypto_EVP_AEAD_CTX_cleanup(&g.ctx)
-}
-
-func (g *aesGCM) NonceSize() int {
- return int(C._goboringcrypto_EVP_AEAD_nonce_length(g.aead))
-}
-
-func (g *aesGCM) Overhead() int {
- return int(C._goboringcrypto_EVP_AEAD_max_overhead(g.aead))
-}
-
-// base returns the address of the underlying array in b,
-// being careful not to panic when b has zero length.
-func base(b []byte) *C.uint8_t {
- if len(b) == 0 {
- return nil
- }
- return (*C.uint8_t)(unsafe.Pointer(&b[0]))
-}
-
-func (g *aesGCM) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
- if len(nonce) != gcmStandardNonceSize {
- panic("cipher: incorrect nonce length given to GCM")
- }
- if uint64(len(plaintext)) > ((1<<32)-2)*aesBlockSize || len(plaintext)+gcmTagSize < len(plaintext) {
- panic("cipher: message too large for GCM")
- }
- if len(dst)+len(plaintext)+gcmTagSize < len(dst) {
- panic("cipher: message too large for buffer")
- }
-
- // Make room in dst to append plaintext+overhead.
- n := len(dst)
- for cap(dst) < n+len(plaintext)+gcmTagSize {
- dst = append(dst[:cap(dst)], 0)
- }
- dst = dst[:n+len(plaintext)+gcmTagSize]
-
- // Check delayed until now to make sure len(dst) is accurate.
- if inexactOverlap(dst[n:], plaintext) {
- panic("cipher: invalid buffer overlap")
- }
-
- outLen := C.size_t(len(plaintext) + gcmTagSize)
- ok := C.EVP_AEAD_CTX_seal_wrapper(
- &g.ctx,
- (*C.uint8_t)(unsafe.Pointer(&dst[n])), outLen,
- base(nonce), C.size_t(len(nonce)),
- base(plaintext), C.size_t(len(plaintext)),
- base(additionalData), C.size_t(len(additionalData)))
- runtime.KeepAlive(g)
- if ok == 0 {
- panic(fail("EVP_AEAD_CTX_seal"))
- }
- return dst[:n+int(outLen)]
-}
-
-var errOpen = errors.New("cipher: message authentication failed")
-
-func (g *aesGCM) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
- if len(nonce) != gcmStandardNonceSize {
- panic("cipher: incorrect nonce length given to GCM")
- }
- if len(ciphertext) < gcmTagSize {
- return nil, errOpen
- }
- if uint64(len(ciphertext)) > ((1<<32)-2)*aesBlockSize+gcmTagSize {
- return nil, errOpen
- }
-
- // Make room in dst to append ciphertext without tag.
- n := len(dst)
- for cap(dst) < n+len(ciphertext)-gcmTagSize {
- dst = append(dst[:cap(dst)], 0)
- }
- dst = dst[:n+len(ciphertext)-gcmTagSize]
-
- // Check delayed until now to make sure len(dst) is accurate.
- if inexactOverlap(dst[n:], ciphertext) {
- panic("cipher: invalid buffer overlap")
- }
-
- outLen := C.size_t(len(ciphertext) - gcmTagSize)
- ok := C.EVP_AEAD_CTX_open_wrapper(
- &g.ctx,
- base(dst[n:]), outLen,
- base(nonce), C.size_t(len(nonce)),
- base(ciphertext), C.size_t(len(ciphertext)),
- base(additionalData), C.size_t(len(additionalData)))
- runtime.KeepAlive(g)
- if ok == 0 {
- return nil, errOpen
- }
- return dst[:n+int(outLen)], nil
-}
-
-func anyOverlap(x, y []byte) bool {
- return len(x) > 0 && len(y) > 0 &&
- uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
- uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
-}
-
-func inexactOverlap(x, y []byte) bool {
- if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
- return false
- }
- return anyOverlap(x, y)
+ return external.NewAESCipher(key)
}
diff --git a/src/crypto/internal/boring/boring.go b/src/crypto/internal/boring/boring.go
index 9ccad7e..3c238b8 100644
--- a/src/crypto/internal/boring/boring.go
+++ b/src/crypto/internal/boring/boring.go
@@ -9,23 +9,35 @@

package boring

-// #include "goboringcrypto.h"
-import "C"
import (
+ "crypto/internal/boring/boringcrypto"
"crypto/internal/boring/sig"
- "math/big"
)

+type externalCrypto interface {
+ Init()
+
+ aes
+ ecdsa
+ hmac
+ rsa
+ sha
+}
+
+var external externalCrypto
+
const available = true

func init() {
- C._goboringcrypto_BORINGSSL_bcm_power_on_self_test()
- if C._goboringcrypto_FIPS_mode() != 1 {
- panic("boringcrypto: not in FIPS mode")
- }
+ external = boringcrypto.NewBoringCrypto()
+ external.Init()
sig.BoringCrypto()
}

+type fail string
+
+func (e fail) Error() string { return "boringcrypto: " + string(e) + " failed" }
+
// Unreachable marks code that should be unreachable
// when BoringCrypto is in use. It panics.
func Unreachable() {
@@ -49,35 +61,3 @@
panic("boringcrypto: invalid code execution")
}
}
-
-type fail string
-
-func (e fail) Error() string { return "boringcrypto: " + string(e) + " failed" }
-
-func bigToBN(x *big.Int) *C.GO_BIGNUM {
- raw := x.Bytes()
- return C._goboringcrypto_BN_bin2bn(base(raw), C.size_t(len(raw)), nil)
-}
-
-func bnToBig(bn *C.GO_BIGNUM) *big.Int {
- raw := make([]byte, C._goboringcrypto_BN_num_bytes(bn))
- n := C._goboringcrypto_BN_bn2bin(bn, base(raw))
- return new(big.Int).SetBytes(raw[:n])
-}
-
-func bigToBn(bnp **C.GO_BIGNUM, b *big.Int) bool {
- if *bnp != nil {
- C._goboringcrypto_BN_free(*bnp)
- *bnp = nil
- }
- if b == nil {
- return true
- }
- raw := b.Bytes()
- bn := C._goboringcrypto_BN_bin2bn(base(raw), C.size_t(len(raw)), nil)
- if bn == nil {
- return false
- }
- *bnp = bn
- return true
-}
diff --git a/src/crypto/internal/boring/Dockerfile b/src/crypto/internal/boring/boringcrypto/Dockerfile
similarity index 100%
rename from src/crypto/internal/boring/Dockerfile
rename to src/crypto/internal/boring/boringcrypto/Dockerfile
diff --git a/src/crypto/internal/boring/boringcrypto/aes.go b/src/crypto/internal/boring/boringcrypto/aes.go
new file mode 100644
index 0000000..71bbcb2
--- /dev/null
+++ b/src/crypto/internal/boring/boringcrypto/aes.go
@@ -0,0 +1,384 @@
+// Copyright 2021 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 !android
+// +build !cmd_go_bootstrap
+// +build !msan
+
+package boringcrypto
+
+/*
+
+#include "goboringcrypto.h"
+
+// These wrappers allocate out_len on the C stack, and check that it matches the expected
+// value, to avoid having to pass a pointer from Go, which would escape to the heap.
+
+int EVP_AEAD_CTX_seal_wrapper(const GO_EVP_AEAD_CTX *ctx, uint8_t *out,
+ size_t exp_out_len,
+ const uint8_t *nonce, size_t nonce_len,
+ const uint8_t *in, size_t in_len,
+ const uint8_t *ad, size_t ad_len) {
+ size_t out_len;
+ int ok = _goboringcrypto_EVP_AEAD_CTX_seal(ctx, out, &out_len, exp_out_len,
+ nonce, nonce_len, in, in_len, ad, ad_len);
+ if (out_len != exp_out_len) {
+ return 0;
+ }
+ return ok;
+};
+
+int EVP_AEAD_CTX_open_wrapper(const GO_EVP_AEAD_CTX *ctx, uint8_t *out,
+ size_t exp_out_len,
+ const uint8_t *nonce, size_t nonce_len,
+ const uint8_t *in, size_t in_len,
+ const uint8_t *ad, size_t ad_len) {
+ size_t out_len;
+ int ok = _goboringcrypto_EVP_AEAD_CTX_open(ctx, out, &out_len, exp_out_len,
+ nonce, nonce_len, in, in_len, ad, ad_len);
+ if (out_len != exp_out_len) {
+ return 0;
+ }
+ return ok;
+};
+
+*/
+import "C"
+import (
+ "crypto/cipher"
+ "errors"
+ "runtime"
+ "strconv"
+ "unsafe"
+)
+
+type aes struct{}
+
+func (_ aes) NewAESCipher(key []byte) (cipher.Block, error) {
+ c := &aesCipher{key: make([]byte, len(key))}
+ copy(c.key, key)
+ // Note: 0 is success, contradicting the usual BoringCrypto convention.
+ if C._goboringcrypto_AES_set_decrypt_key((*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.uint(8*len(c.key)), &c.dec) != 0 ||
+ C._goboringcrypto_AES_set_encrypt_key((*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.uint(8*len(c.key)), &c.enc) != 0 {
+ return nil, aesKeySizeError(len(key))
+ }
+ return c, nil
+}
+
+type aesKeySizeError int
+
+func (k aesKeySizeError) Error() string {
+ return "crypto/aes: invalid key size " + strconv.Itoa(int(k))
+}
+
+const aesBlockSize = 16
+
+type aesCipher struct {
+ key []byte
+ enc C.GO_AES_KEY
+ dec C.GO_AES_KEY
+}
+
+type extraModes interface {
+ // Copied out of crypto/aes/modes.go.
+ NewCBCEncrypter(iv []byte) cipher.BlockMode
+ NewCBCDecrypter(iv []byte) cipher.BlockMode
+ NewCTR(iv []byte) cipher.Stream
+ NewGCM(nonceSize, tagSize int) (cipher.AEAD, error)
+
+ // Invented for BoringCrypto.
+ NewGCMTLS() (cipher.AEAD, error)
+}
+
+var _ extraModes = (*aesCipher)(nil)
+
+func (c *aesCipher) BlockSize() int { return aesBlockSize }
+
+func (c *aesCipher) Encrypt(dst, src []byte) {
+ if inexactOverlap(dst, src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+ if len(src) < aesBlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < aesBlockSize {
+ panic("crypto/aes: output not full block")
+ }
+ C._goboringcrypto_AES_encrypt(
+ (*C.uint8_t)(unsafe.Pointer(&src[0])),
+ (*C.uint8_t)(unsafe.Pointer(&dst[0])),
+ &c.enc)
+}
+
+func (c *aesCipher) Decrypt(dst, src []byte) {
+ if inexactOverlap(dst, src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+ if len(src) < aesBlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < aesBlockSize {
+ panic("crypto/aes: output not full block")
+ }
+ C._goboringcrypto_AES_decrypt(
+ (*C.uint8_t)(unsafe.Pointer(&src[0])),
+ (*C.uint8_t)(unsafe.Pointer(&dst[0])),
+ &c.dec)
+}
+
+type aesCBC struct {
+ key *C.GO_AES_KEY
+ mode C.int
+ iv [aesBlockSize]byte
+}
+
+func (x *aesCBC) BlockSize() int { return aesBlockSize }
+
+func (x *aesCBC) CryptBlocks(dst, src []byte) {
+ if inexactOverlap(dst, src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+ if len(src)%aesBlockSize != 0 {
+ panic("crypto/cipher: input not full blocks")
+ }
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
+ if len(src) > 0 {
+ C._goboringcrypto_AES_cbc_encrypt(
+ (*C.uint8_t)(unsafe.Pointer(&src[0])),
+ (*C.uint8_t)(unsafe.Pointer(&dst[0])),
+ C.size_t(len(src)), x.key,
+ (*C.uint8_t)(unsafe.Pointer(&x.iv[0])), x.mode)
+ }
+}
+
+func (x *aesCBC) SetIV(iv []byte) {
+ if len(iv) != aesBlockSize {
+ panic("cipher: incorrect length IV")
+ }
+ copy(x.iv[:], iv)
+}
+
+func (c *aesCipher) NewCBCEncrypter(iv []byte) cipher.BlockMode {
+ x := &aesCBC{key: &c.enc, mode: C.GO_AES_ENCRYPT}
+ copy(x.iv[:], iv)
+ return x
+}
+
+func (c *aesCipher) NewCBCDecrypter(iv []byte) cipher.BlockMode {
+ x := &aesCBC{key: &c.dec, mode: C.GO_AES_DECRYPT}
+ copy(x.iv[:], iv)
+ return x
+}
+
+type aesCTR struct {
+ key *C.GO_AES_KEY
+ iv [aesBlockSize]byte
+ num C.uint
+ ecount_buf [16]C.uint8_t
+}
+
+func (x *aesCTR) XORKeyStream(dst, src []byte) {
+ if inexactOverlap(dst, src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
+ if len(src) == 0 {
+ return
+ }
+ C._goboringcrypto_AES_ctr128_encrypt(
+ (*C.uint8_t)(unsafe.Pointer(&src[0])),
+ (*C.uint8_t)(unsafe.Pointer(&dst[0])),
+ C.size_t(len(src)), x.key, (*C.uint8_t)(unsafe.Pointer(&x.iv[0])),
+ &x.ecount_buf[0], &x.num)
+}
+
+func (c *aesCipher) NewCTR(iv []byte) cipher.Stream {
+ x := &aesCTR{key: &c.enc}
+ copy(x.iv[:], iv)
+ return x
+}
+
+type aesGCM struct {
+ ctx C.GO_EVP_AEAD_CTX
+ aead *C.GO_EVP_AEAD
+}
+
+const (
+ gcmBlockSize = 16
+ gcmTagSize = 16
+ gcmStandardNonceSize = 12
+)
+
+type aesNonceSizeError int
+
+func (n aesNonceSizeError) Error() string {
+ return "crypto/aes: invalid GCM nonce size " + strconv.Itoa(int(n))
+}
+
+type noGCM struct {
+ cipher.Block
+}
+
+func (c *aesCipher) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
+ if nonceSize != gcmStandardNonceSize && tagSize != gcmTagSize {
+ return nil, errors.New("crypto/aes: GCM tag and nonce sizes can't be non-standard at the same time")
+ }
+ // Fall back to standard library for GCM with non-standard nonce or tag size.
+ if nonceSize != gcmStandardNonceSize {
+ return cipher.NewGCMWithNonceSize(&noGCM{c}, nonceSize)
+ }
+ if tagSize != gcmTagSize {
+ return cipher.NewGCMWithTagSize(&noGCM{c}, tagSize)
+ }
+ return c.newGCM(false)
+}
+
+func (c *aesCipher) NewGCMTLS() (cipher.AEAD, error) {
+ return c.newGCM(true)
+}
+
+func (c *aesCipher) newGCM(tls bool) (cipher.AEAD, error) {
+ var aead *C.GO_EVP_AEAD
+ switch len(c.key) * 8 {
+ case 128:
+ if tls {
+ aead = C._goboringcrypto_EVP_aead_aes_128_gcm_tls12()
+ } else {
+ aead = C._goboringcrypto_EVP_aead_aes_128_gcm()
+ }
+ case 256:
+ if tls {
+ aead = C._goboringcrypto_EVP_aead_aes_256_gcm_tls12()
+ } else {
+ aead = C._goboringcrypto_EVP_aead_aes_256_gcm()
+ }
+ default:
+ // Fall back to standard library for GCM with non-standard key size.
+ return cipher.NewGCMWithNonceSize(&noGCM{c}, gcmStandardNonceSize)
+ }
+
+ g := &aesGCM{aead: aead}
+ if C._goboringcrypto_EVP_AEAD_CTX_init(&g.ctx, aead, (*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.size_t(len(c.key)), C.GO_EVP_AEAD_DEFAULT_TAG_LENGTH, nil) == 0 {
+ return nil, fail("EVP_AEAD_CTX_init")
+ }
+ // Note: Because of the finalizer, any time g.ctx is passed to cgo,
+ // that call must be followed by a call to runtime.KeepAlive(g),
+ // to make sure g is not collected (and finalized) before the cgo
+ // call returns.
+ runtime.SetFinalizer(g, (*aesGCM).finalize)
+ if g.NonceSize() != gcmStandardNonceSize {
+ panic("boringcrypto: internal confusion about nonce size")
+ }
+ if g.Overhead() != gcmTagSize {
+ panic("boringcrypto: internal confusion about tag size")
+ }
+
+ return g, nil
+}
+
+func (g *aesGCM) finalize() {
+ C._goboringcrypto_EVP_AEAD_CTX_cleanup(&g.ctx)
+}
+
+func (g *aesGCM) NonceSize() int {
+ return int(C._goboringcrypto_EVP_AEAD_nonce_length(g.aead))
+}
+
+func (g *aesGCM) Overhead() int {
+ return int(C._goboringcrypto_EVP_AEAD_max_overhead(g.aead))
+}
+
+func (g *aesGCM) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
+ if len(nonce) != gcmStandardNonceSize {
+ panic("cipher: incorrect nonce length given to GCM")
+ }
+ if uint64(len(plaintext)) > ((1<<32)-2)*aesBlockSize || len(plaintext)+gcmTagSize < len(plaintext) {
+ panic("cipher: message too large for GCM")
+ }
+ if len(dst)+len(plaintext)+gcmTagSize < len(dst) {
+ panic("cipher: message too large for buffer")
+ }
+
+ // Make room in dst to append plaintext+overhead.
+ n := len(dst)
+ for cap(dst) < n+len(plaintext)+gcmTagSize {
+ dst = append(dst[:cap(dst)], 0)
+ }
+ dst = dst[:n+len(plaintext)+gcmTagSize]
+
+ // Check delayed until now to make sure len(dst) is accurate.
+ if inexactOverlap(dst[n:], plaintext) {
+ panic("cipher: invalid buffer overlap")
+ }
+
+ outLen := C.size_t(len(plaintext) + gcmTagSize)
+ ok := C.EVP_AEAD_CTX_seal_wrapper(
+ &g.ctx,
+ (*C.uint8_t)(unsafe.Pointer(&dst[n])), outLen,
+ base(nonce), C.size_t(len(nonce)),
+ base(plaintext), C.size_t(len(plaintext)),
+ base(additionalData), C.size_t(len(additionalData)))
+ runtime.KeepAlive(g)
+ if ok == 0 {
+ panic(fail("EVP_AEAD_CTX_seal"))
+ }
+ return dst[:n+int(outLen)]
+}
+
+var errOpen = errors.New("cipher: message authentication failed")
+
+func (g *aesGCM) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ if len(nonce) != gcmStandardNonceSize {
+ panic("cipher: incorrect nonce length given to GCM")
+ }
+ if len(ciphertext) < gcmTagSize {
+ return nil, errOpen
+ }
+ if uint64(len(ciphertext)) > ((1<<32)-2)*aesBlockSize+gcmTagSize {
+ return nil, errOpen
+ }
+
+ // Make room in dst to append ciphertext without tag.
+ n := len(dst)
+ for cap(dst) < n+len(ciphertext)-gcmTagSize {
+ dst = append(dst[:cap(dst)], 0)
+ }
+ dst = dst[:n+len(ciphertext)-gcmTagSize]
+
+ // Check delayed until now to make sure len(dst) is accurate.
+ if inexactOverlap(dst[n:], ciphertext) {
+ panic("cipher: invalid buffer overlap")
+ }
+
+ outLen := C.size_t(len(ciphertext) - gcmTagSize)
+ ok := C.EVP_AEAD_CTX_open_wrapper(
+ &g.ctx,
+ base(dst[n:]), outLen,
+ base(nonce), C.size_t(len(nonce)),
+ base(ciphertext), C.size_t(len(ciphertext)),
+ base(additionalData), C.size_t(len(additionalData)))
+ runtime.KeepAlive(g)
+ if ok == 0 {
+ return nil, errOpen
+ }
+ return dst[:n+int(outLen)], nil
+}
+
+func anyOverlap(x, y []byte) bool {
+ return len(x) > 0 && len(y) > 0 &&
+ uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
+ uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
+}
+
+func inexactOverlap(x, y []byte) bool {
+ if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
+ return false
+ }
+ return anyOverlap(x, y)
+}
diff --git a/src/crypto/internal/boring/boringcrypto/boringcrypto.go b/src/crypto/internal/boring/boringcrypto/boringcrypto.go
new file mode 100644
index 0000000..d5213b3
--- /dev/null
+++ b/src/crypto/internal/boring/boringcrypto/boringcrypto.go
@@ -0,0 +1,83 @@
+// Copyright 2021 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 !android
+// +build !cmd_go_bootstrap
+// +build !msan
+
+package boringcrypto
+
+// #include "goboringcrypto.h"
+import "C"
+import (
+ "math/big"
+ "unsafe"
+)
+
+type boringcrypto struct {
+ aes
+ ecdsa
+ hmac
+ rsa
+ sha
+}
+
+func NewBoringCrypto() *boringcrypto {
+ return &boringcrypto{
+ aes: aes{},
+ ecdsa: ecdsa{},
+ hmac: hmac{},
+ rsa: rsa{},
+ sha: sha{},
+ }
+}
+
+func (_ *boringcrypto) Init() {
+ C._goboringcrypto_BORINGSSL_bcm_power_on_self_test()
+ if C._goboringcrypto_FIPS_mode() != 1 {
+ panic("boringcrypto: not in FIPS mode")
+ }
+}
+
+type fail string
+
+func (e fail) Error() string { return "boringcrypto: " + string(e) + " failed" }
+
+// base returns the address of the underlying array in b,
+// being careful not to panic when b has zero length.
+func base(b []byte) *C.uint8_t {
+ if len(b) == 0 {
+ return nil
+ }
+ return (*C.uint8_t)(unsafe.Pointer(&b[0]))
+}
+
+func bigToBN(x *big.Int) *C.GO_BIGNUM {
+ raw := x.Bytes()
+ return C._goboringcrypto_BN_bin2bn(base(raw), C.size_t(len(raw)), nil)
+}
+
+func bnToBig(bn *C.GO_BIGNUM) *big.Int {
+ raw := make([]byte, C._goboringcrypto_BN_num_bytes(bn))
+ n := C._goboringcrypto_BN_bn2bin(bn, base(raw))
+ return new(big.Int).SetBytes(raw[:n])
+}
+
+func bigToBn(bnp **C.GO_BIGNUM, b *big.Int) bool {
+ if *bnp != nil {
+ C._goboringcrypto_BN_free(*bnp)
+ *bnp = nil
+ }
+ if b == nil {
+ return true
+ }
+ raw := b.Bytes()
+ bn := C._goboringcrypto_BN_bin2bn(base(raw), C.size_t(len(raw)), nil)
+ if bn == nil {
+ return false
+ }
+ *bnp = bn
+ return true
+}
diff --git a/src/crypto/internal/boring/build.sh b/src/crypto/internal/boring/boringcrypto/build.sh
similarity index 100%
rename from src/crypto/internal/boring/build.sh
rename to src/crypto/internal/boring/boringcrypto/build.sh
diff --git a/src/crypto/internal/boring/boringcrypto/ecdsa.go b/src/crypto/internal/boring/boringcrypto/ecdsa.go
new file mode 100644
index 0000000..f5de26a
--- /dev/null
+++ b/src/crypto/internal/boring/boringcrypto/ecdsa.go
@@ -0,0 +1,177 @@
+// Copyright 2021 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 !android
+// +build !cmd_go_bootstrap
+// +build !msan
+
+package boringcrypto
+
+// #include "goboringcrypto.h"
+import "C"
+import (
+ "encoding/asn1"
+ "errors"
+ "math/big"
+ "runtime"
+ "unsafe"
+)
+
+type ecdsa struct{}
+
+type GoECKey = C.GO_EC_KEY
+
+type ecdsaSignature struct {
+ R, S *big.Int
+}
+
+var errUnknownCurve = errors.New("boringcrypto: unknown elliptic curve")
+
+func curveNID(curve string) (C.int, error) {
+ switch curve {
+ case "P-224":
+ return C.GO_NID_secp224r1, nil
+ case "P-256":
+ return C.GO_NID_X9_62_prime256v1, nil
+ case "P-384":
+ return C.GO_NID_secp384r1, nil
+ case "P-521":
+ return C.GO_NID_secp521r1, nil
+ }
+ return 0, errUnknownCurve
+}
+
+func (_ ecdsa) NewPublicKeyECDSA(curve string, X, Y *big.Int) (*GoECKey, error) {
+ return newECKey(curve, X, Y)
+}
+
+func (_ ecdsa) ECKeyFree(key *GoECKey) {
+ C._goboringcrypto_EC_KEY_free(key)
+}
+
+func newECKey(curve string, X, Y *big.Int) (*GoECKey, error) {
+ nid, err := curveNID(curve)
+ if err != nil {
+ return nil, err
+ }
+ key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid)
+ if key == nil {
+ return nil, fail("EC_KEY_new_by_curve_name")
+ }
+ group := C._goboringcrypto_EC_KEY_get0_group(key)
+ pt := C._goboringcrypto_EC_POINT_new(group)
+ if pt == nil {
+ C._goboringcrypto_EC_KEY_free(key)
+ return nil, fail("EC_POINT_new")
+ }
+ bx := bigToBN(X)
+ by := bigToBN(Y)
+ ok := bx != nil && by != nil && C._goboringcrypto_EC_POINT_set_affine_coordinates_GFp(group, pt, bx, by, nil) != 0 &&
+ C._goboringcrypto_EC_KEY_set_public_key(key, pt) != 0
+ if bx != nil {
+ C._goboringcrypto_BN_free(bx)
+ }
+ if by != nil {
+ C._goboringcrypto_BN_free(by)
+ }
+ C._goboringcrypto_EC_POINT_free(pt)
+ if !ok {
+ C._goboringcrypto_EC_KEY_free(key)
+ return nil, fail("EC_POINT_set_affine_coordinates_GFp")
+ }
+ return key, nil
+}
+
+func (_ ecdsa) NewPrivateKeyECDSA(curve string, X, Y *big.Int, D *big.Int) (*GoECKey, error) {
+ key, err := newECKey(curve, X, Y)
+ if err != nil {
+ return nil, err
+ }
+ bd := bigToBN(D)
+ ok := bd != nil && C._goboringcrypto_EC_KEY_set_private_key(key, bd) != 0
+ if bd != nil {
+ C._goboringcrypto_BN_free(bd)
+ }
+ if !ok {
+ C._goboringcrypto_EC_KEY_free(key)
+ return nil, fail("EC_KEY_set_private_key")
+ }
+ return key, nil
+}
+
+func (e ecdsa) SignECDSA(key *GoECKey, hash []byte) (r, s *big.Int, err error) {
+ // We could use ECDSA_do_sign instead but would need to convert
+ // the resulting BIGNUMs to *big.Int form. If we're going to do a
+ // conversion, converting the ASN.1 form is more convenient and
+ // likely not much more expensive.
+ sig, err := e.SignMarshalECDSA(key, hash)
+ if err != nil {
+ return nil, nil, err
+ }
+ var esig ecdsaSignature
+ if _, err := asn1.Unmarshal(sig, &esig); err != nil {
+ return nil, nil, err
+ }
+ return esig.R, esig.S, nil
+}
+
+func (_ ecdsa) SignMarshalECDSA(key *GoECKey, hash []byte) ([]byte, error) {
+ size := C._goboringcrypto_ECDSA_size(key)
+ sig := make([]byte, size)
+ var sigLen C.uint
+ if C._goboringcrypto_ECDSA_sign(0, base(hash), C.size_t(len(hash)), (*C.uint8_t)(unsafe.Pointer(&sig[0])), &sigLen, key) == 0 {
+ return nil, fail("ECDSA_sign")
+ }
+ runtime.KeepAlive(key)
+ return sig[:sigLen], nil
+}
+
+func (_ ecdsa) VerifyECDSA(key *GoECKey, hash []byte, r, s *big.Int) bool {
+ // We could use ECDSA_do_verify instead but would need to convert
+ // r and s to BIGNUM form. If we're going to do a conversion, marshaling
+ // to ASN.1 is more convenient and likely not much more expensive.
+ sig, err := asn1.Marshal(ecdsaSignature{r, s})
+ if err != nil {
+ return false
+ }
+ ok := C._goboringcrypto_ECDSA_verify(0, base(hash), C.size_t(len(hash)), (*C.uint8_t)(unsafe.Pointer(&sig[0])), C.size_t(len(sig)), key) != 0
+ runtime.KeepAlive(key)
+ return ok
+}
+
+func (_ ecdsa) GenerateKeyECDSA(curve string) (X, Y, D *big.Int, err error) {
+ nid, err := curveNID(curve)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid)
+ if key == nil {
+ return nil, nil, nil, fail("EC_KEY_new_by_curve_name")
+ }
+ defer C._goboringcrypto_EC_KEY_free(key)
+ if C._goboringcrypto_EC_KEY_generate_key_fips(key) == 0 {
+ return nil, nil, nil, fail("EC_KEY_generate_key_fips")
+ }
+ group := C._goboringcrypto_EC_KEY_get0_group(key)
+ pt := C._goboringcrypto_EC_KEY_get0_public_key(key)
+ bd := C._goboringcrypto_EC_KEY_get0_private_key(key)
+ if pt == nil || bd == nil {
+ return nil, nil, nil, fail("EC_KEY_get0_private_key")
+ }
+ bx := C._goboringcrypto_BN_new()
+ if bx == nil {
+ return nil, nil, nil, fail("BN_new")
+ }
+ defer C._goboringcrypto_BN_free(bx)
+ by := C._goboringcrypto_BN_new()
+ if by == nil {
+ return nil, nil, nil, fail("BN_new")
+ }
+ defer C._goboringcrypto_BN_free(by)
+ if C._goboringcrypto_EC_POINT_get_affine_coordinates_GFp(group, pt, bx, by, nil) == 0 {
+ return nil, nil, nil, fail("EC_POINT_get_affine_coordinates_GFp")
+ }
+ return bnToBig(bx), bnToBig(by), bnToBig(bd), nil
+}
diff --git a/src/crypto/internal/boring/goboringcrypto.h b/src/crypto/internal/boring/boringcrypto/goboringcrypto.h
similarity index 100%
rename from src/crypto/internal/boring/goboringcrypto.h
rename to src/crypto/internal/boring/boringcrypto/goboringcrypto.h
diff --git a/src/crypto/internal/boring/goboringcrypto_linux_amd64.syso b/src/crypto/internal/boring/boringcrypto/goboringcrypto_linux_amd64.syso
similarity index 100%
rename from src/crypto/internal/boring/goboringcrypto_linux_amd64.syso
rename to src/crypto/internal/boring/boringcrypto/goboringcrypto_linux_amd64.syso
Binary files differ
diff --git a/src/crypto/internal/boring/boringcrypto/hmac.go b/src/crypto/internal/boring/boringcrypto/hmac.go
new file mode 100644
index 0000000..603a4c0
--- /dev/null
+++ b/src/crypto/internal/boring/boringcrypto/hmac.go
@@ -0,0 +1,158 @@
+// Copyright 2021 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 !android
+// +build !cmd_go_bootstrap
+// +build !msan
+
+package boringcrypto
+
+// #include "goboringcrypto.h"
+import "C"
+import (
+ "crypto"
+ "hash"
+ "runtime"
+ "unsafe"
+)
+
+type hmac struct{}
+
+// 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
+}
+
+// cryptoHashToMD converts a crypto.Hash
+// to a BoringCrypto *C.GO_EVP_MD.
+func cryptoHashToMD(ch crypto.Hash) *C.GO_EVP_MD {
+ switch ch {
+ case crypto.MD5:
+ return C._goboringcrypto_EVP_md5()
+ case crypto.MD5SHA1:
+ return C._goboringcrypto_EVP_md5_sha1()
+ case crypto.SHA1:
+ return C._goboringcrypto_EVP_sha1()
+ case crypto.SHA224:
+ return C._goboringcrypto_EVP_sha224()
+ case crypto.SHA256:
+ return C._goboringcrypto_EVP_sha256()
+ case crypto.SHA384:
+ return C._goboringcrypto_EVP_sha384()
+ case crypto.SHA512:
+ 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 (_ hmac) 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
+ ctx2 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
+ // Note: Because of the finalizer, any time h.ctx is passed to cgo,
+ // that call must be followed by a call to runtime.KeepAlive(h),
+ // to make sure h is not collected (and finalized) before the cgo
+ // call returns.
+ runtime.SetFinalizer(h, (*boringHMAC).finalize)
+ }
+ C._goboringcrypto_HMAC_CTX_init(&h.ctx)
+
+ if C._goboringcrypto_HMAC_Init(&h.ctx, unsafe.Pointer(base(h.key)), 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")
+ }
+ runtime.KeepAlive(h) // Next line will keep h alive too; just making doubly sure.
+ h.sum = nil
+}
+
+func (h *boringHMAC) finalize() {
+ C._goboringcrypto_HMAC_CTX_cleanup(&h.ctx)
+}
+
+func (h *boringHMAC) Write(p []byte) (int, error) {
+ if len(p) > 0 {
+ C._goboringcrypto_HMAC_Update(&h.ctx, (*C.uint8_t)(unsafe.Pointer(&p[0])), C.size_t(len(p)))
+ }
+ runtime.KeepAlive(h)
+ 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)
+ }
+ // Make copy of context because Go hash.Hash mandates
+ // that Sum has no effect on the underlying stream.
+ // In particular it is OK to Sum, then Write more, then Sum again,
+ // and the second Sum acts as if the first didn't happen.
+ C._goboringcrypto_HMAC_CTX_init(&h.ctx2)
+ if C._goboringcrypto_HMAC_CTX_copy_ex(&h.ctx2, &h.ctx) == 0 {
+ panic("boringcrypto: HMAC_CTX_copy_ex failed")
+ }
+ C._goboringcrypto_HMAC_Final(&h.ctx2, (*C.uint8_t)(unsafe.Pointer(&h.sum[0])), nil)
+ C._goboringcrypto_HMAC_CTX_cleanup(&h.ctx2)
+ return append(in, h.sum...)
+}
diff --git a/src/crypto/internal/boring/boringcrypto/rand.go b/src/crypto/internal/boring/boringcrypto/rand.go
new file mode 100644
index 0000000..ed2744c
--- /dev/null
+++ b/src/crypto/internal/boring/boringcrypto/rand.go
@@ -0,0 +1,25 @@
+// 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 !android
+// +build !cmd_go_bootstrap
+// +build !msan
+
+package boringcrypto
+
+// #include "goboringcrypto.h"
+import "C"
+import "unsafe"
+
+type RandReader int
+
+func (RandReader) Read(b []byte) (int, error) {
+ // Note: RAND_bytes should never fail; the return value exists only for historical reasons.
+ // We check it even so.
+ if len(b) > 0 && C._goboringcrypto_RAND_bytes((*C.uint8_t)(unsafe.Pointer(&b[0])), C.size_t(len(b))) == 0 {
+ return 0, fail("RAND_bytes")
+ }
+ return len(b), nil
+}
diff --git a/src/crypto/internal/boring/boringcrypto/rsa.go b/src/crypto/internal/boring/boringcrypto/rsa.go
new file mode 100644
index 0000000..dae4cfe
--- /dev/null
+++ b/src/crypto/internal/boring/boringcrypto/rsa.go
@@ -0,0 +1,298 @@
+// 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 !android
+// +build !cmd_go_bootstrap
+// +build !msan
+
+package boringcrypto
+
+// #include "goboringcrypto.h"
+import "C"
+import (
+ "crypto"
+ "crypto/subtle"
+ "errors"
+ "hash"
+ "math/big"
+ "strconv"
+ "unsafe"
+)
+
+type rsa struct{}
+
+type GoRSA = C.GO_RSA
+
+func (_ rsa) GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv *big.Int, err error) {
+ bad := func(e error) (N, E, D, P, Q, Dp, Dq, Qinv *big.Int, err error) {
+ return nil, nil, nil, nil, nil, nil, nil, nil, e
+ }
+
+ key := C._goboringcrypto_RSA_new()
+ if key == nil {
+ return bad(fail("RSA_new"))
+ }
+ defer C._goboringcrypto_RSA_free(key)
+
+ if C._goboringcrypto_RSA_generate_key_fips(key, C.int(bits), nil) == 0 {
+ return bad(fail("RSA_generate_key_fips"))
+ }
+
+ var n, e, d, p, q, dp, dq, qinv *C.GO_BIGNUM
+ C._goboringcrypto_RSA_get0_key(key, &n, &e, &d)
+ C._goboringcrypto_RSA_get0_factors(key, &p, &q)
+ C._goboringcrypto_RSA_get0_crt_params(key, &dp, &dq, &qinv)
+ return bnToBig(n), bnToBig(e), bnToBig(d), bnToBig(p), bnToBig(q), bnToBig(dp), bnToBig(dq), bnToBig(qinv), nil
+}
+
+func (_ rsa) NewPublicKeyRSA(N, E *big.Int) (*GoRSA, error) {
+ key := C._goboringcrypto_RSA_new()
+ if key == nil {
+ return nil, fail("RSA_new")
+ }
+ if !bigToBn(&key.n, N) ||
+ !bigToBn(&key.e, E) {
+ return nil, fail("BN_bin2bn")
+ }
+ return key, nil
+}
+
+func (_ rsa) NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv *big.Int) (*GoRSA, error) {
+ key := C._goboringcrypto_RSA_new()
+ if key == nil {
+ return nil, fail("RSA_new")
+ }
+ if !bigToBn(&key.n, N) ||
+ !bigToBn(&key.e, E) ||
+ !bigToBn(&key.d, D) ||
+ !bigToBn(&key.p, P) ||
+ !bigToBn(&key.q, Q) ||
+ !bigToBn(&key.dmp1, Dp) ||
+ !bigToBn(&key.dmq1, Dq) ||
+ !bigToBn(&key.iqmp, Qinv) {
+ return nil, fail("BN_bin2bn")
+ }
+ return key, nil
+}
+
+func (_ rsa) RSAFree(key *GoRSA) {
+ C._goboringcrypto_RSA_free(key)
+}
+
+func setupRSA(key *GoRSA,
+ padding C.int, h hash.Hash, label []byte, saltLen int, ch crypto.Hash,
+ init func(*C.GO_EVP_PKEY_CTX) C.int) (pkey *C.GO_EVP_PKEY, ctx *C.GO_EVP_PKEY_CTX, err error) {
+ defer func() {
+ if err != nil {
+ if pkey != nil {
+ C._goboringcrypto_EVP_PKEY_free(pkey)
+ pkey = nil
+ }
+ if ctx != nil {
+ C._goboringcrypto_EVP_PKEY_CTX_free(ctx)
+ ctx = nil
+ }
+ }
+ }()
+
+ pkey = C._goboringcrypto_EVP_PKEY_new()
+ if pkey == nil {
+ return nil, nil, fail("EVP_PKEY_new")
+ }
+ if C._goboringcrypto_EVP_PKEY_set1_RSA(pkey, key) == 0 {
+ return nil, nil, fail("EVP_PKEY_set1_RSA")
+ }
+ ctx = C._goboringcrypto_EVP_PKEY_CTX_new(pkey, nil)
+ if ctx == nil {
+ return nil, nil, fail("EVP_PKEY_CTX_new")
+ }
+ if init(ctx) == 0 {
+ return nil, nil, fail("EVP_PKEY_operation_init")
+ }
+ if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_padding(ctx, padding) == 0 {
+ return nil, nil, fail("EVP_PKEY_CTX_set_rsa_padding")
+ }
+ if padding == C.GO_RSA_PKCS1_OAEP_PADDING {
+ md := hashToMD(h)
+ if md == nil {
+ return nil, nil, errors.New("crypto/rsa: unsupported hash function")
+ }
+ if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) == 0 {
+ return nil, nil, fail("EVP_PKEY_set_rsa_oaep_md")
+ }
+ // ctx takes ownership of label, so malloc a copy for BoringCrypto to free.
+ clabel := (*C.uint8_t)(C._goboringcrypto_OPENSSL_malloc(C.size_t(len(label))))
+ if clabel == nil {
+ return nil, nil, fail("OPENSSL_malloc")
+ }
+ copy((*[1 << 30]byte)(unsafe.Pointer(clabel))[:len(label)], label)
+ if C._goboringcrypto_EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, clabel, C.size_t(len(label))) == 0 {
+ return nil, nil, fail("EVP_PKEY_CTX_set0_rsa_oaep_label")
+ }
+ }
+ if padding == C.GO_RSA_PKCS1_PSS_PADDING {
+ if saltLen != 0 {
+ if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, C.int(saltLen)) == 0 {
+ return nil, nil, fail("EVP_PKEY_set_rsa_pss_saltlen")
+ }
+ }
+ md := cryptoHashToMD(ch)
+ if md == nil {
+ return nil, nil, errors.New("crypto/rsa: unsupported hash function")
+ }
+ if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md) == 0 {
+ return nil, nil, fail("EVP_PKEY_set_rsa_mgf1_md")
+ }
+ }
+
+ return pkey, ctx, nil
+}
+
+func cryptRSA(key *GoRSA,
+ padding C.int, h hash.Hash, label []byte, saltLen int, ch crypto.Hash,
+ init func(*C.GO_EVP_PKEY_CTX) C.int,
+ crypt func(*C.GO_EVP_PKEY_CTX, *C.uint8_t, *C.size_t, *C.uint8_t, C.size_t) C.int,
+ in []byte) ([]byte, error) {
+
+ pkey, ctx, err := setupRSA(key, padding, h, label, saltLen, ch, init)
+ if err != nil {
+ return nil, err
+ }
+ defer C._goboringcrypto_EVP_PKEY_free(pkey)
+ defer C._goboringcrypto_EVP_PKEY_CTX_free(ctx)
+
+ var outLen C.size_t
+ if crypt(ctx, nil, &outLen, base(in), C.size_t(len(in))) == 0 {
+ return nil, fail("EVP_PKEY_decrypt/encrypt")
+ }
+ out := make([]byte, outLen)
+ if crypt(ctx, base(out), &outLen, base(in), C.size_t(len(in))) == 0 {
+ return nil, fail("EVP_PKEY_decrypt/encrypt")
+ }
+ return out[:outLen], nil
+}
+
+func (_ rsa) DecryptRSAOAEP(h hash.Hash, priv *GoRSA, ciphertext, label []byte) ([]byte, error) {
+ return cryptRSA(priv, C.GO_RSA_PKCS1_OAEP_PADDING, h, label, 0, 0, decryptInit, decrypt, ciphertext)
+}
+
+func (_ rsa) EncryptRSAOAEP(h hash.Hash, pub *GoRSA, msg, label []byte) ([]byte, error) {
+ return cryptRSA(pub, C.GO_RSA_PKCS1_OAEP_PADDING, h, label, 0, 0, encryptInit, encrypt, msg)
+}
+
+func (_ rsa) DecryptRSAPKCS1(priv *GoRSA, ciphertext []byte) ([]byte, error) {
+ return cryptRSA(priv, C.GO_RSA_PKCS1_PADDING, nil, nil, 0, 0, decryptInit, decrypt, ciphertext)
+}
+
+func (_ rsa) EncryptRSAPKCS1(pub *GoRSA, msg []byte) ([]byte, error) {
+ return cryptRSA(pub, C.GO_RSA_PKCS1_PADDING, nil, nil, 0, 0, encryptInit, encrypt, msg)
+}
+
+func (_ rsa) DecryptRSANoPadding(priv *GoRSA, ciphertext []byte) ([]byte, error) {
+ return cryptRSA(priv, C.GO_RSA_NO_PADDING, nil, nil, 0, 0, decryptInit, decrypt, ciphertext)
+}
+
+func (_ rsa) EncryptRSANoPadding(pub *GoRSA, msg []byte) ([]byte, error) {
+ return cryptRSA(pub, C.GO_RSA_NO_PADDING, nil, nil, 0, 0, encryptInit, encrypt, msg)
+}
+
+// These dumb wrappers work around the fact that cgo functions cannot be used as values directly.
+
+func decryptInit(ctx *C.GO_EVP_PKEY_CTX) C.int {
+ return C._goboringcrypto_EVP_PKEY_decrypt_init(ctx)
+}
+
+func decrypt(ctx *C.GO_EVP_PKEY_CTX, out *C.uint8_t, outLen *C.size_t, in *C.uint8_t, inLen C.size_t) C.int {
+ return C._goboringcrypto_EVP_PKEY_decrypt(ctx, out, outLen, in, inLen)
+}
+
+func encryptInit(ctx *C.GO_EVP_PKEY_CTX) C.int {
+ return C._goboringcrypto_EVP_PKEY_encrypt_init(ctx)
+}
+
+func encrypt(ctx *C.GO_EVP_PKEY_CTX, out *C.uint8_t, outLen *C.size_t, in *C.uint8_t, inLen C.size_t) C.int {
+ return C._goboringcrypto_EVP_PKEY_encrypt(ctx, out, outLen, in, inLen)
+}
+
+func (_ rsa) SignRSAPSS(key *GoRSA, hashed []byte, h crypto.Hash, saltLen int) ([]byte, error) {
+ var out []byte
+ var outLen C.size_t
+ md := cryptoHashToMD(h)
+ if md == nil {
+ return nil, errors.New("crypto/rsa: unsupported hash function")
+ }
+ out = make([]byte, C._goboringcrypto_RSA_size(key))
+ if C._goboringcrypto_RSA_sign_pss_mgf1(key, &outLen, base(out), C.size_t(len(out)),
+ base(hashed), C.size_t(len(hashed)), md, nil, C.int(saltLen)) == 0 {
+ return nil, fail("RSA_sign_pss_mgf1")
+ }
+ return out[:outLen], nil
+}
+
+func (_ rsa) VerifyRSAPSS(pub *GoRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error {
+ md := cryptoHashToMD(h)
+ if md == nil {
+ return errors.New("crypto/rsa: unsupported hash function")
+ }
+ if C._goboringcrypto_RSA_verify_pss_mgf1(pub, base(hashed), C.size_t(len(hashed)),
+ md, nil, C.int(saltLen), base(sig), C.size_t(len(sig))) == 0 {
+ return fail("RSA_verify_pss_mgf1")
+ }
+ return nil
+}
+
+func (_ rsa) SignRSAPKCS1v15(key *GoRSA, h crypto.Hash, hashed []byte) ([]byte, error) {
+ if h == 0 {
+ // No hashing.
+ var out []byte
+ var outLen C.size_t
+ out = make([]byte, C._goboringcrypto_RSA_size(key))
+ if C._goboringcrypto_RSA_sign_raw(key, &outLen, base(out), C.size_t(len(out)),
+ base(hashed), C.size_t(len(hashed)), C.GO_RSA_PKCS1_PADDING) == 0 {
+ return nil, fail("RSA_sign_raw")
+ }
+ return out[:outLen], nil
+ }
+
+ md := cryptoHashToMD(h)
+ if md == nil {
+ return nil, errors.New("crypto/rsa: unsupported hash function: " + strconv.Itoa(int(h)))
+ }
+ nid := C._goboringcrypto_EVP_MD_type(md)
+ var out []byte
+ var outLen C.uint
+ out = make([]byte, C._goboringcrypto_RSA_size(key))
+ if C._goboringcrypto_RSA_sign(nid, base(hashed), C.uint(len(hashed)),
+ base(out), &outLen, key) == 0 {
+ return nil, fail("RSA_sign")
+ }
+ return out[:outLen], nil
+}
+
+func (_ rsa) VerifyRSAPKCS1v15(key *GoRSA, h crypto.Hash, hashed, sig []byte) error {
+ if h == 0 {
+ var out []byte
+ var outLen C.size_t
+ out = make([]byte, C._goboringcrypto_RSA_size(key))
+ if C._goboringcrypto_RSA_verify_raw(key, &outLen, base(out),
+ C.size_t(len(out)), base(sig), C.size_t(len(sig)), C.GO_RSA_PKCS1_PADDING) == 0 {
+ return fail("RSA_verify")
+ }
+ if subtle.ConstantTimeCompare(hashed, out[:outLen]) != 1 {
+ return fail("RSA_verify")
+ }
+ return nil
+ }
+ md := cryptoHashToMD(h)
+ if md == nil {
+ return errors.New("crypto/rsa: unsupported hash function")
+ }
+ nid := C._goboringcrypto_EVP_MD_type(md)
+ if C._goboringcrypto_RSA_verify(nid, base(hashed), C.size_t(len(hashed)),
+ base(sig), C.size_t(len(sig)), key) == 0 {
+ return fail("RSA_verify")
+ }
+ return nil
+}
diff --git a/src/crypto/internal/boring/boringcrypto/sha.go b/src/crypto/internal/boring/boringcrypto/sha.go
new file mode 100644
index 0000000..7bb39db
--- /dev/null
+++ b/src/crypto/internal/boring/boringcrypto/sha.go
@@ -0,0 +1,482 @@
+// 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 !android
+// +build !cmd_go_bootstrap
+// +build !msan
+
+package boringcrypto
+
+// #include "goboringcrypto.h"
+import "C"
+import (
+ "errors"
+ "hash"
+ "unsafe"
+)
+
+type sha struct{}
+
+// NewSHA1 returns a new SHA1 hash.
+func (_ sha) NewSHA1() hash.Hash {
+ h := new(sha1Hash)
+ h.Reset()
+ return h
+}
+
+type sha1Hash struct {
+ ctx C.GO_SHA_CTX
+ out [20]byte
+}
+
+type sha1Ctx struct {
+ h [5]uint32
+ nl, nh uint32
+ x [64]byte
+ nx uint32
+}
+
+func (h *sha1Hash) Reset() { C._goboringcrypto_SHA1_Init(&h.ctx) }
+func (h *sha1Hash) Size() int { return 20 }
+func (h *sha1Hash) BlockSize() int { return 64 }
+func (h *sha1Hash) Sum(in []byte) []byte { return append(in, h.sum()...) }
+
+func (h *sha1Hash) Write(p []byte) (int, error) {
+ if len(p) > 0 && C._goboringcrypto_SHA1_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 {
+ panic("boringcrypto: SHA1_Update failed")
+ }
+ return len(p), nil
+}
+
+func (h0 *sha1Hash) sum() []byte {
+ h := *h0 // make copy so future Write+Sum is valid
+ if C._goboringcrypto_SHA1_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 {
+ panic("boringcrypto: SHA1_Final failed")
+ }
+ return h.out[:]
+}
+
+const (
+ sha1Magic = "sha\x01"
+ sha1MarshaledSize = len(sha1Magic) + 5*4 + 64 + 8
+)
+
+func (h *sha1Hash) MarshalBinary() ([]byte, error) {
+ d := (*sha1Ctx)(unsafe.Pointer(&h.ctx))
+ b := make([]byte, 0, sha1MarshaledSize)
+ b = append(b, sha1Magic...)
+ b = appendUint32(b, d.h[0])
+ b = appendUint32(b, d.h[1])
+ b = appendUint32(b, d.h[2])
+ b = appendUint32(b, d.h[3])
+ b = appendUint32(b, d.h[4])
+ b = append(b, d.x[:d.nx]...)
+ b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
+ b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29)
+ return b, nil
+}
+
+func (h *sha1Hash) UnmarshalBinary(b []byte) error {
+ if len(b) < len(sha1Magic) || string(b[:len(sha1Magic)]) != sha1Magic {
+ return errors.New("crypto/sha1: invalid hash state identifier")
+ }
+ if len(b) != sha1MarshaledSize {
+ return errors.New("crypto/sha1: invalid hash state size")
+ }
+ d := (*sha1Ctx)(unsafe.Pointer(&h.ctx))
+ b = b[len(sha1Magic):]
+ b, d.h[0] = consumeUint32(b)
+ b, d.h[1] = consumeUint32(b)
+ b, d.h[2] = consumeUint32(b)
+ b, d.h[3] = consumeUint32(b)
+ b, d.h[4] = consumeUint32(b)
+ b = b[copy(d.x[:], b):]
+ b, n := consumeUint64(b)
+ d.nl = uint32(n << 3)
+ d.nh = uint32(n >> 29)
+ d.nx = uint32(n) % 64
+ return nil
+}
+
+// NewSHA224 returns a new SHA224 hash.
+func (_ sha) NewSHA224() hash.Hash {
+ h := new(sha224Hash)
+ h.Reset()
+ return h
+}
+
+type sha224Hash struct {
+ ctx C.GO_SHA256_CTX
+ out [224 / 8]byte
+}
+
+func (h *sha224Hash) Reset() { C._goboringcrypto_SHA224_Init(&h.ctx) }
+func (h *sha224Hash) Size() int { return 224 / 8 }
+func (h *sha224Hash) BlockSize() int { return 64 }
+func (h *sha224Hash) Sum(in []byte) []byte { return append(in, h.sum()...) }
+
+func (h *sha224Hash) Write(p []byte) (int, error) {
+ if len(p) > 0 && C._goboringcrypto_SHA224_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 {
+ panic("boringcrypto: SHA224_Update failed")
+ }
+ return len(p), nil
+}
+
+func (h0 *sha224Hash) sum() []byte {
+ h := *h0 // make copy so future Write+Sum is valid
+ if C._goboringcrypto_SHA224_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 {
+ panic("boringcrypto: SHA224_Final failed")
+ }
+ return h.out[:]
+}
+
+// NewSHA256 returns a new SHA256 hash.
+func (_ sha) NewSHA256() hash.Hash {
+ h := new(sha256Hash)
+ h.Reset()
+ return h
+}
+
+type sha256Hash struct {
+ ctx C.GO_SHA256_CTX
+ out [256 / 8]byte
+}
+
+func (h *sha256Hash) Reset() { C._goboringcrypto_SHA256_Init(&h.ctx) }
+func (h *sha256Hash) Size() int { return 256 / 8 }
+func (h *sha256Hash) BlockSize() int { return 64 }
+func (h *sha256Hash) Sum(in []byte) []byte { return append(in, h.sum()...) }
+
+func (h *sha256Hash) Write(p []byte) (int, error) {
+ if len(p) > 0 && C._goboringcrypto_SHA256_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 {
+ panic("boringcrypto: SHA256_Update failed")
+ }
+ return len(p), nil
+}
+
+func (h0 *sha256Hash) sum() []byte {
+ h := *h0 // make copy so future Write+Sum is valid
+ if C._goboringcrypto_SHA256_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 {
+ panic("boringcrypto: SHA256_Final failed")
+ }
+ return h.out[:]
+}
+
+const (
+ magic224 = "sha\x02"
+ magic256 = "sha\x03"
+ marshaledSize256 = len(magic256) + 8*4 + 64 + 8
+)
+
+type sha256Ctx struct {
+ h [8]uint32
+ nl, nh uint32
+ x [64]byte
+ nx uint32
+}
+
+func (h *sha224Hash) MarshalBinary() ([]byte, error) {
+ d := (*sha256Ctx)(unsafe.Pointer(&h.ctx))
+ b := make([]byte, 0, marshaledSize256)
+ b = append(b, magic224...)
+ b = appendUint32(b, d.h[0])
+ b = appendUint32(b, d.h[1])
+ b = appendUint32(b, d.h[2])
+ b = appendUint32(b, d.h[3])
+ b = appendUint32(b, d.h[4])
+ b = appendUint32(b, d.h[5])
+ b = appendUint32(b, d.h[6])
+ b = appendUint32(b, d.h[7])
+ b = append(b, d.x[:d.nx]...)
+ b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
+ b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29)
+ return b, nil
+}
+
+func (h *sha256Hash) MarshalBinary() ([]byte, error) {
+ d := (*sha256Ctx)(unsafe.Pointer(&h.ctx))
+ b := make([]byte, 0, marshaledSize256)
+ b = append(b, magic256...)
+ b = appendUint32(b, d.h[0])
+ b = appendUint32(b, d.h[1])
+ b = appendUint32(b, d.h[2])
+ b = appendUint32(b, d.h[3])
+ b = appendUint32(b, d.h[4])
+ b = appendUint32(b, d.h[5])
+ b = appendUint32(b, d.h[6])
+ b = appendUint32(b, d.h[7])
+ b = append(b, d.x[:d.nx]...)
+ b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
+ b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29)
+ return b, nil
+}
+
+func (h *sha224Hash) UnmarshalBinary(b []byte) error {
+ if len(b) < len(magic224) || string(b[:len(magic224)]) != magic224 {
+ return errors.New("crypto/sha256: invalid hash state identifier")
+ }
+ if len(b) != marshaledSize256 {
+ return errors.New("crypto/sha256: invalid hash state size")
+ }
+ d := (*sha256Ctx)(unsafe.Pointer(&h.ctx))
+ b = b[len(magic224):]
+ b, d.h[0] = consumeUint32(b)
+ b, d.h[1] = consumeUint32(b)
+ b, d.h[2] = consumeUint32(b)
+ b, d.h[3] = consumeUint32(b)
+ b, d.h[4] = consumeUint32(b)
+ b, d.h[5] = consumeUint32(b)
+ b, d.h[6] = consumeUint32(b)
+ b, d.h[7] = consumeUint32(b)
+ b = b[copy(d.x[:], b):]
+ b, n := consumeUint64(b)
+ d.nl = uint32(n << 3)
+ d.nh = uint32(n >> 29)
+ d.nx = uint32(n) % 64
+ return nil
+}
+
+func (h *sha256Hash) UnmarshalBinary(b []byte) error {
+ if len(b) < len(magic256) || string(b[:len(magic256)]) != magic256 {
+ return errors.New("crypto/sha256: invalid hash state identifier")
+ }
+ if len(b) != marshaledSize256 {
+ return errors.New("crypto/sha256: invalid hash state size")
+ }
+ d := (*sha256Ctx)(unsafe.Pointer(&h.ctx))
+ b = b[len(magic256):]
+ b, d.h[0] = consumeUint32(b)
+ b, d.h[1] = consumeUint32(b)
+ b, d.h[2] = consumeUint32(b)
+ b, d.h[3] = consumeUint32(b)
+ b, d.h[4] = consumeUint32(b)
+ b, d.h[5] = consumeUint32(b)
+ b, d.h[6] = consumeUint32(b)
+ b, d.h[7] = consumeUint32(b)
+ b = b[copy(d.x[:], b):]
+ b, n := consumeUint64(b)
+ d.nl = uint32(n << 3)
+ d.nh = uint32(n >> 29)
+ d.nx = uint32(n) % 64
+ return nil
+}
+
+// NewSHA384 returns a new SHA384 hash.
+func (_ sha) NewSHA384() hash.Hash {
+ h := new(sha384Hash)
+ h.Reset()
+ return h
+}
+
+type sha384Hash struct {
+ ctx C.GO_SHA512_CTX
+ out [384 / 8]byte
+}
+
+func (h *sha384Hash) Reset() { C._goboringcrypto_SHA384_Init(&h.ctx) }
+func (h *sha384Hash) Size() int { return 384 / 8 }
+func (h *sha384Hash) BlockSize() int { return 128 }
+func (h *sha384Hash) Sum(in []byte) []byte { return append(in, h.sum()...) }
+
+func (h *sha384Hash) Write(p []byte) (int, error) {
+ if len(p) > 0 && C._goboringcrypto_SHA384_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 {
+ panic("boringcrypto: SHA384_Update failed")
+ }
+ return len(p), nil
+}
+
+func (h0 *sha384Hash) sum() []byte {
+ h := *h0 // make copy so future Write+Sum is valid
+ if C._goboringcrypto_SHA384_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 {
+ panic("boringcrypto: SHA384_Final failed")
+ }
+ return h.out[:]
+}
+
+// NewSHA512 returns a new SHA512 hash.
+func (_ sha) NewSHA512() hash.Hash {
+ h := new(sha512Hash)
+ h.Reset()
+ return h
+}
+
+type sha512Hash struct {
+ ctx C.GO_SHA512_CTX
+ out [512 / 8]byte
+}
+
+func (h *sha512Hash) Reset() { C._goboringcrypto_SHA512_Init(&h.ctx) }
+func (h *sha512Hash) Size() int { return 512 / 8 }
+func (h *sha512Hash) BlockSize() int { return 128 }
+func (h *sha512Hash) Sum(in []byte) []byte { return append(in, h.sum()...) }
+
+func (h *sha512Hash) Write(p []byte) (int, error) {
+ if len(p) > 0 && C._goboringcrypto_SHA512_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 {
+ panic("boringcrypto: SHA512_Update failed")
+ }
+ return len(p), nil
+}
+
+func (h0 *sha512Hash) sum() []byte {
+ h := *h0 // make copy so future Write+Sum is valid
+ if C._goboringcrypto_SHA512_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 {
+ panic("boringcrypto: SHA512_Final failed")
+ }
+ return h.out[:]
+}
+
+type sha512Ctx struct {
+ h [8]uint64
+ nl, nh uint64
+ x [128]byte
+ nx uint32
+}
+
+const (
+ magic384 = "sha\x04"
+ magic512_224 = "sha\x05"
+ magic512_256 = "sha\x06"
+ magic512 = "sha\x07"
+ marshaledSize512 = len(magic512) + 8*8 + 128 + 8
+)
+
+var zero [128]byte
+
+func (h *sha384Hash) MarshalBinary() ([]byte, error) {
+ d := (*sha512Ctx)(unsafe.Pointer(&h.ctx))
+ b := make([]byte, 0, marshaledSize512)
+ b = append(b, magic384...)
+ b = appendUint64(b, d.h[0])
+ b = appendUint64(b, d.h[1])
+ b = appendUint64(b, d.h[2])
+ b = appendUint64(b, d.h[3])
+ b = appendUint64(b, d.h[4])
+ b = appendUint64(b, d.h[5])
+ b = appendUint64(b, d.h[6])
+ b = appendUint64(b, d.h[7])
+ b = append(b, d.x[:d.nx]...)
+ b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
+ b = appendUint64(b, d.nl>>3|d.nh<<61)
+ return b, nil
+}
+
+func (h *sha512Hash) MarshalBinary() ([]byte, error) {
+ d := (*sha512Ctx)(unsafe.Pointer(&h.ctx))
+ b := make([]byte, 0, marshaledSize512)
+ b = append(b, magic512...)
+ b = appendUint64(b, d.h[0])
+ b = appendUint64(b, d.h[1])
+ b = appendUint64(b, d.h[2])
+ b = appendUint64(b, d.h[3])
+ b = appendUint64(b, d.h[4])
+ b = appendUint64(b, d.h[5])
+ b = appendUint64(b, d.h[6])
+ b = appendUint64(b, d.h[7])
+ b = append(b, d.x[:d.nx]...)
+ b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
+ b = appendUint64(b, d.nl>>3|d.nh<<61)
+ return b, nil
+}
+
+func (h *sha384Hash) UnmarshalBinary(b []byte) error {
+ if len(b) < len(magic512) {
+ return errors.New("crypto/sha512: invalid hash state identifier")
+ }
+ if string(b[:len(magic384)]) != magic384 {
+ return errors.New("crypto/sha512: invalid hash state identifier")
+ }
+ if len(b) != marshaledSize512 {
+ return errors.New("crypto/sha512: invalid hash state size")
+ }
+ d := (*sha512Ctx)(unsafe.Pointer(&h.ctx))
+ b = b[len(magic512):]
+ b, d.h[0] = consumeUint64(b)
+ b, d.h[1] = consumeUint64(b)
+ b, d.h[2] = consumeUint64(b)
+ b, d.h[3] = consumeUint64(b)
+ b, d.h[4] = consumeUint64(b)
+ b, d.h[5] = consumeUint64(b)
+ b, d.h[6] = consumeUint64(b)
+ b, d.h[7] = consumeUint64(b)
+ b = b[copy(d.x[:], b):]
+ b, n := consumeUint64(b)
+ d.nl = n << 3
+ d.nh = n >> 61
+ d.nx = uint32(n) % 128
+ return nil
+}
+
+func (h *sha512Hash) UnmarshalBinary(b []byte) error {
+ if len(b) < len(magic512) {
+ return errors.New("crypto/sha512: invalid hash state identifier")
+ }
+ if string(b[:len(magic512)]) != magic512 {
+ return errors.New("crypto/sha512: invalid hash state identifier")
+ }
+ if len(b) != marshaledSize512 {
+ return errors.New("crypto/sha512: invalid hash state size")
+ }
+ d := (*sha512Ctx)(unsafe.Pointer(&h.ctx))
+ b = b[len(magic512):]
+ b, d.h[0] = consumeUint64(b)
+ b, d.h[1] = consumeUint64(b)
+ b, d.h[2] = consumeUint64(b)
+ b, d.h[3] = consumeUint64(b)
+ b, d.h[4] = consumeUint64(b)
+ b, d.h[5] = consumeUint64(b)
+ b, d.h[6] = consumeUint64(b)
+ b, d.h[7] = consumeUint64(b)
+ b = b[copy(d.x[:], b):]
+ b, n := consumeUint64(b)
+ d.nl = n << 3
+ d.nh = n >> 61
+ d.nx = uint32(n) % 128
+ return nil
+}
+
+func appendUint64(b []byte, x uint64) []byte {
+ var a [8]byte
+ putUint64(a[:], x)
+ return append(b, a[:]...)
+}
+
+func appendUint32(b []byte, x uint32) []byte {
+ var a [4]byte
+ putUint32(a[:], x)
+ return append(b, a[:]...)
+}
+
+func consumeUint64(b []byte) ([]byte, uint64) {
+ _ = b[7]
+ x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
+ uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
+ return b[8:], x
+}
+
+func consumeUint32(b []byte) ([]byte, uint32) {
+ _ = b[3]
+ x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
+ return b[4:], x
+}
+
+func putUint64(x []byte, s uint64) {
+ _ = x[7]
+ x[0] = byte(s >> 56)
+ x[1] = byte(s >> 48)
+ x[2] = byte(s >> 40)
+ x[3] = byte(s >> 32)
+ x[4] = byte(s >> 24)
+ x[5] = byte(s >> 16)
+ x[6] = byte(s >> 8)
+ x[7] = byte(s)
+}
+
+func putUint32(x []byte, s uint32) {
+ _ = x[3]
+ x[0] = byte(s >> 24)
+ x[1] = byte(s >> 16)
+ x[2] = byte(s >> 8)
+ x[3] = byte(s)
+}
diff --git a/src/crypto/internal/boring/ecdsa.go b/src/crypto/internal/boring/ecdsa.go
index 4fcba4b..e898b3d 100644
--- a/src/crypto/internal/boring/ecdsa.go
+++ b/src/crypto/internal/boring/ecdsa.go
@@ -9,54 +9,41 @@

package boring

-// #include "goboringcrypto.h"
import "C"
import (
- "encoding/asn1"
- "errors"
+ "crypto/internal/boring/boringcrypto"
"math/big"
"runtime"
- "unsafe"
)

-type ecdsaSignature struct {
- R, S *big.Int
+type ecdsa interface {
+ NewPublicKeyECDSA(curve string, X, Y *big.Int) (*boringcrypto.GoECKey, error)
+ NewPrivateKeyECDSA(curve string, X, Y *big.Int, D *big.Int) (*boringcrypto.GoECKey, error)
+ SignECDSA(priv *boringcrypto.GoECKey, hash []byte) (r, s *big.Int, err error)
+ SignMarshalECDSA(priv *boringcrypto.GoECKey, hash []byte) ([]byte, error)
+ VerifyECDSA(pub *boringcrypto.GoECKey, hash []byte, r, s *big.Int) bool
+ GenerateKeyECDSA(curve string) (X, Y, D *big.Int, err error)
+ ECKeyFree(*boringcrypto.GoECKey)
}

type PrivateKeyECDSA struct {
- key *C.GO_EC_KEY
+ key *boringcrypto.GoECKey
}

func (k *PrivateKeyECDSA) finalize() {
- C._goboringcrypto_EC_KEY_free(k.key)
+ external.ECKeyFree(k.key)
}

type PublicKeyECDSA struct {
- key *C.GO_EC_KEY
+ key *boringcrypto.GoECKey
}

func (k *PublicKeyECDSA) finalize() {
- C._goboringcrypto_EC_KEY_free(k.key)
-}
-
-var errUnknownCurve = errors.New("boringcrypto: unknown elliptic curve")
-
-func curveNID(curve string) (C.int, error) {
- switch curve {
- case "P-224":
- return C.GO_NID_secp224r1, nil
- case "P-256":
- return C.GO_NID_X9_62_prime256v1, nil
- case "P-384":
- return C.GO_NID_secp384r1, nil
- case "P-521":
- return C.GO_NID_secp521r1, nil
- }
- return 0, errUnknownCurve
+ external.ECKeyFree(k.key)
}

func NewPublicKeyECDSA(curve string, X, Y *big.Int) (*PublicKeyECDSA, error) {
- key, err := newECKey(curve, X, Y)
+ key, err := external.NewPublicKeyECDSA(curve, X, Y)
if err != nil {
return nil, err
}
@@ -69,53 +56,11 @@
return k, nil
}

-func newECKey(curve string, X, Y *big.Int) (*C.GO_EC_KEY, error) {
- nid, err := curveNID(curve)
- if err != nil {
- return nil, err
- }
- key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid)
- if key == nil {
- return nil, fail("EC_KEY_new_by_curve_name")
- }
- group := C._goboringcrypto_EC_KEY_get0_group(key)
- pt := C._goboringcrypto_EC_POINT_new(group)
- if pt == nil {
- C._goboringcrypto_EC_KEY_free(key)
- return nil, fail("EC_POINT_new")
- }
- bx := bigToBN(X)
- by := bigToBN(Y)
- ok := bx != nil && by != nil && C._goboringcrypto_EC_POINT_set_affine_coordinates_GFp(group, pt, bx, by, nil) != 0 &&
- C._goboringcrypto_EC_KEY_set_public_key(key, pt) != 0
- if bx != nil {
- C._goboringcrypto_BN_free(bx)
- }
- if by != nil {
- C._goboringcrypto_BN_free(by)
- }
- C._goboringcrypto_EC_POINT_free(pt)
- if !ok {
- C._goboringcrypto_EC_KEY_free(key)
- return nil, fail("EC_POINT_set_affine_coordinates_GFp")
- }
- return key, nil
-}
-
func NewPrivateKeyECDSA(curve string, X, Y *big.Int, D *big.Int) (*PrivateKeyECDSA, error) {
- key, err := newECKey(curve, X, Y)
+ key, err := external.NewPrivateKeyECDSA(curve, X, Y, D)
if err != nil {
return nil, err
}
- bd := bigToBN(D)
- ok := bd != nil && C._goboringcrypto_EC_KEY_set_private_key(key, bd) != 0
- if bd != nil {
- C._goboringcrypto_BN_free(bd)
- }
- if !ok {
- C._goboringcrypto_EC_KEY_free(key)
- return nil, fail("EC_KEY_set_private_key")
- }
k := &PrivateKeyECDSA{key}
// Note: Because of the finalizer, any time k.key is passed to cgo,
// that call must be followed by a call to runtime.KeepAlive(k),
@@ -126,76 +71,17 @@
}

func SignECDSA(priv *PrivateKeyECDSA, hash []byte) (r, s *big.Int, err error) {
- // We could use ECDSA_do_sign instead but would need to convert
- // the resulting BIGNUMs to *big.Int form. If we're going to do a
- // conversion, converting the ASN.1 form is more convenient and
- // likely not much more expensive.
- sig, err := SignMarshalECDSA(priv, hash)
- if err != nil {
- return nil, nil, err
- }
- var esig ecdsaSignature
- if _, err := asn1.Unmarshal(sig, &esig); err != nil {
- return nil, nil, err
- }
- return esig.R, esig.S, nil
+ return external.SignECDSA(priv.key, hash)
}

func SignMarshalECDSA(priv *PrivateKeyECDSA, hash []byte) ([]byte, error) {
- size := C._goboringcrypto_ECDSA_size(priv.key)
- sig := make([]byte, size)
- var sigLen C.uint
- if C._goboringcrypto_ECDSA_sign(0, base(hash), C.size_t(len(hash)), (*C.uint8_t)(unsafe.Pointer(&sig[0])), &sigLen, priv.key) == 0 {
- return nil, fail("ECDSA_sign")
- }
- runtime.KeepAlive(priv)
- return sig[:sigLen], nil
+ return external.SignMarshalECDSA(priv.key, hash)
}

func VerifyECDSA(pub *PublicKeyECDSA, hash []byte, r, s *big.Int) bool {
- // We could use ECDSA_do_verify instead but would need to convert
- // r and s to BIGNUM form. If we're going to do a conversion, marshaling
- // to ASN.1 is more convenient and likely not much more expensive.
- sig, err := asn1.Marshal(ecdsaSignature{r, s})
- if err != nil {
- return false
- }
- ok := C._goboringcrypto_ECDSA_verify(0, base(hash), C.size_t(len(hash)), (*C.uint8_t)(unsafe.Pointer(&sig[0])), C.size_t(len(sig)), pub.key) != 0
- runtime.KeepAlive(pub)
- return ok
+ return external.VerifyECDSA(pub.key, hash, r, s)
}

func GenerateKeyECDSA(curve string) (X, Y, D *big.Int, err error) {
- nid, err := curveNID(curve)
- if err != nil {
- return nil, nil, nil, err
- }
- key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid)
- if key == nil {
- return nil, nil, nil, fail("EC_KEY_new_by_curve_name")
- }
- defer C._goboringcrypto_EC_KEY_free(key)
- if C._goboringcrypto_EC_KEY_generate_key_fips(key) == 0 {
- return nil, nil, nil, fail("EC_KEY_generate_key_fips")
- }
- group := C._goboringcrypto_EC_KEY_get0_group(key)
- pt := C._goboringcrypto_EC_KEY_get0_public_key(key)
- bd := C._goboringcrypto_EC_KEY_get0_private_key(key)
- if pt == nil || bd == nil {
- return nil, nil, nil, fail("EC_KEY_get0_private_key")
- }
- bx := C._goboringcrypto_BN_new()
- if bx == nil {
- return nil, nil, nil, fail("BN_new")
- }
- defer C._goboringcrypto_BN_free(bx)
- by := C._goboringcrypto_BN_new()
- if by == nil {
- return nil, nil, nil, fail("BN_new")
- }
- defer C._goboringcrypto_BN_free(by)
- if C._goboringcrypto_EC_POINT_get_affine_coordinates_GFp(group, pt, bx, by, nil) == 0 {
- return nil, nil, nil, fail("EC_POINT_get_affine_coordinates_GFp")
- }
- return bnToBig(bx), bnToBig(by), bnToBig(bd), nil
+ return external.GenerateKeyECDSA(curve)
}
diff --git a/src/crypto/internal/boring/hmac.go b/src/crypto/internal/boring/hmac.go
index 01b5844..3c66113 100644
--- a/src/crypto/internal/boring/hmac.go
+++ b/src/crypto/internal/boring/hmac.go
@@ -9,53 +9,12 @@

package boring

-// #include "goboringcrypto.h"
-import "C"
import (
- "crypto"
"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
-}
-
-// cryptoHashToMD converts a crypto.Hash
-// to a BoringCrypto *C.GO_EVP_MD.
-func cryptoHashToMD(ch crypto.Hash) *C.GO_EVP_MD {
- switch ch {
- case crypto.MD5:
- return C._goboringcrypto_EVP_md5()
- case crypto.MD5SHA1:
- return C._goboringcrypto_EVP_md5_sha1()
- case crypto.SHA1:
- return C._goboringcrypto_EVP_sha1()
- case crypto.SHA224:
- return C._goboringcrypto_EVP_sha224()
- case crypto.SHA256:
- return C._goboringcrypto_EVP_sha256()
- case crypto.SHA384:
- return C._goboringcrypto_EVP_sha384()
- case crypto.SHA512:
- return C._goboringcrypto_EVP_sha512()
- }
- return nil
+type hmac interface {
+ NewHMAC(h func() hash.Hash, key []byte) hash.Hash
}

// NewHMAC returns a new HMAC using BoringCrypto.
@@ -63,94 +22,5 @@
// 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
- ctx2 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
- // Note: Because of the finalizer, any time h.ctx is passed to cgo,
- // that call must be followed by a call to runtime.KeepAlive(h),
- // to make sure h is not collected (and finalized) before the cgo
- // call returns.
- runtime.SetFinalizer(h, (*boringHMAC).finalize)
- }
- C._goboringcrypto_HMAC_CTX_init(&h.ctx)
-
- if C._goboringcrypto_HMAC_Init(&h.ctx, unsafe.Pointer(base(h.key)), 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")
- }
- runtime.KeepAlive(h) // Next line will keep h alive too; just making doubly sure.
- h.sum = nil
-}
-
-func (h *boringHMAC) finalize() {
- C._goboringcrypto_HMAC_CTX_cleanup(&h.ctx)
-}
-
-func (h *boringHMAC) Write(p []byte) (int, error) {
- if len(p) > 0 {
- C._goboringcrypto_HMAC_Update(&h.ctx, (*C.uint8_t)(unsafe.Pointer(&p[0])), C.size_t(len(p)))
- }
- runtime.KeepAlive(h)
- 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)
- }
- // Make copy of context because Go hash.Hash mandates
- // that Sum has no effect on the underlying stream.
- // In particular it is OK to Sum, then Write more, then Sum again,
- // and the second Sum acts as if the first didn't happen.
- C._goboringcrypto_HMAC_CTX_init(&h.ctx2)
- if C._goboringcrypto_HMAC_CTX_copy_ex(&h.ctx2, &h.ctx) == 0 {
- panic("boringcrypto: HMAC_CTX_copy_ex failed")
- }
- C._goboringcrypto_HMAC_Final(&h.ctx2, (*C.uint8_t)(unsafe.Pointer(&h.sum[0])), nil)
- C._goboringcrypto_HMAC_CTX_cleanup(&h.ctx2)
- return append(in, h.sum...)
+ return external.NewHMAC(h, key)
}
diff --git a/src/crypto/internal/boring/rand.go b/src/crypto/internal/boring/rand.go
index c3fc27c..642c48b 100644
--- a/src/crypto/internal/boring/rand.go
+++ b/src/crypto/internal/boring/rand.go
@@ -9,19 +9,6 @@

package boring

-// #include "goboringcrypto.h"
-import "C"
-import "unsafe"
+import "crypto/internal/boring/boringcrypto"

-type randReader int
-
-func (randReader) Read(b []byte) (int, error) {
- // Note: RAND_bytes should never fail; the return value exists only for historical reasons.
- // We check it even so.
- if len(b) > 0 && C._goboringcrypto_RAND_bytes((*C.uint8_t)(unsafe.Pointer(&b[0])), C.size_t(len(b))) == 0 {
- return 0, fail("RAND_bytes")
- }
- return len(b), nil
-}
-
-const RandReader = randReader(0)
+const RandReader = boringcrypto.RandReader(0)
diff --git a/src/crypto/internal/boring/rsa.go b/src/crypto/internal/boring/rsa.go
index a10831d..26fb83d 100644
--- a/src/crypto/internal/boring/rsa.go
+++ b/src/crypto/internal/boring/rsa.go
@@ -9,54 +9,45 @@

package boring

-// #include "goboringcrypto.h"
import "C"
import (
"crypto"
- "crypto/subtle"
- "errors"
+ "crypto/internal/boring/boringcrypto"
"hash"
"math/big"
"runtime"
- "strconv"
- "unsafe"
)

+type rsa interface {
+ GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv *big.Int, err error)
+ NewPublicKeyRSA(N, E *big.Int) (*boringcrypto.GoRSA, error)
+ NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv *big.Int) (*boringcrypto.GoRSA, error)
+ DecryptRSAOAEP(h hash.Hash, priv *boringcrypto.GoRSA, ciphertext, label []byte) ([]byte, error)
+ EncryptRSAOAEP(h hash.Hash, pub *boringcrypto.GoRSA, msg, label []byte) ([]byte, error)
+ DecryptRSAPKCS1(priv *boringcrypto.GoRSA, ciphertext []byte) ([]byte, error)
+ EncryptRSAPKCS1(pub *boringcrypto.GoRSA, msg []byte) ([]byte, error)
+ DecryptRSANoPadding(priv *boringcrypto.GoRSA, ciphertext []byte) ([]byte, error)
+ EncryptRSANoPadding(pub *boringcrypto.GoRSA, msg []byte) ([]byte, error)
+ SignRSAPSS(priv *boringcrypto.GoRSA, hashed []byte, h crypto.Hash, saltLen int) ([]byte, error)
+ VerifyRSAPSS(pub *boringcrypto.GoRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error
+ SignRSAPKCS1v15(priv *boringcrypto.GoRSA, h crypto.Hash, hashed []byte) ([]byte, error)
+ VerifyRSAPKCS1v15(pub *boringcrypto.GoRSA, h crypto.Hash, hashed, sig []byte) error
+ RSAFree(key *boringcrypto.GoRSA)
+}
+
func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv *big.Int, err error) {
- bad := func(e error) (N, E, D, P, Q, Dp, Dq, Qinv *big.Int, err error) {
- return nil, nil, nil, nil, nil, nil, nil, nil, e
- }
-
- key := C._goboringcrypto_RSA_new()
- if key == nil {
- return bad(fail("RSA_new"))
- }
- defer C._goboringcrypto_RSA_free(key)
-
- if C._goboringcrypto_RSA_generate_key_fips(key, C.int(bits), nil) == 0 {
- return bad(fail("RSA_generate_key_fips"))
- }
-
- var n, e, d, p, q, dp, dq, qinv *C.GO_BIGNUM
- C._goboringcrypto_RSA_get0_key(key, &n, &e, &d)
- C._goboringcrypto_RSA_get0_factors(key, &p, &q)
- C._goboringcrypto_RSA_get0_crt_params(key, &dp, &dq, &qinv)
- return bnToBig(n), bnToBig(e), bnToBig(d), bnToBig(p), bnToBig(q), bnToBig(dp), bnToBig(dq), bnToBig(qinv), nil
+ return external.GenerateKeyRSA(bits)
}

type PublicKeyRSA struct {
// _key MUST NOT be accessed directly. Instead, use the withKey method.
- _key *C.GO_RSA
+ _key *boringcrypto.GoRSA
}

func NewPublicKeyRSA(N, E *big.Int) (*PublicKeyRSA, error) {
- key := C._goboringcrypto_RSA_new()
- if key == nil {
- return nil, fail("RSA_new")
- }
- if !bigToBn(&key.n, N) ||
- !bigToBn(&key.e, E) {
- return nil, fail("BN_bin2bn")
+ key, err := external.NewPublicKeyRSA(N, E)
+ if err != nil {
+ return nil, err
}
k := &PublicKeyRSA{_key: key}
runtime.SetFinalizer(k, (*PublicKeyRSA).finalize)
@@ -64,287 +55,116 @@
}

func (k *PublicKeyRSA) finalize() {
- C._goboringcrypto_RSA_free(k._key)
+ external.RSAFree(k._key)
}

-func (k *PublicKeyRSA) withKey(f func(*C.GO_RSA) C.int) C.int {
+func (k *PublicKeyRSA) withKey(f func(*boringcrypto.GoRSA)) {
// Because of the finalizer, any time _key is passed to cgo, that call must
// be followed by a call to runtime.KeepAlive, to make sure k is not
// collected (and finalized) before the cgo call returns.
defer runtime.KeepAlive(k)
- return f(k._key)
+ f(k._key)
}

type PrivateKeyRSA struct {
// _key MUST NOT be accessed directly. Instead, use the withKey method.
- _key *C.GO_RSA
+ _key *boringcrypto.GoRSA
+}
+
+func (k *PrivateKeyRSA) finalize() {
+ external.RSAFree(k._key)
+}
+
+func (k *PrivateKeyRSA) withKey(f func(*boringcrypto.GoRSA)) {
+ // Because of the finalizer, any time _key is passed to cgo, that call must
+ // be followed by a call to runtime.KeepAlive, to make sure k is not
+ // collected (and finalized) before the cgo call returns.
+ defer runtime.KeepAlive(k)
+ f(k._key)
}

func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv *big.Int) (*PrivateKeyRSA, error) {
- key := C._goboringcrypto_RSA_new()
- if key == nil {
- return nil, fail("RSA_new")
- }
- if !bigToBn(&key.n, N) ||
- !bigToBn(&key.e, E) ||
- !bigToBn(&key.d, D) ||
- !bigToBn(&key.p, P) ||
- !bigToBn(&key.q, Q) ||
- !bigToBn(&key.dmp1, Dp) ||
- !bigToBn(&key.dmq1, Dq) ||
- !bigToBn(&key.iqmp, Qinv) {
- return nil, fail("BN_bin2bn")
+ key, err := external.NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv)
+ if err != nil {
+ return nil, err
}
k := &PrivateKeyRSA{_key: key}
runtime.SetFinalizer(k, (*PrivateKeyRSA).finalize)
return k, nil
}

-func (k *PrivateKeyRSA) finalize() {
- C._goboringcrypto_RSA_free(k._key)
+func DecryptRSAOAEP(h hash.Hash, priv *PrivateKeyRSA, ciphertext, label []byte) (out []byte, err error) {
+ priv.withKey(func(key *boringcrypto.GoRSA) {
+ out, err = external.DecryptRSAOAEP(h, key, ciphertext, label)
+ })
+ return out, err
}

-func (k *PrivateKeyRSA) withKey(f func(*C.GO_RSA) C.int) C.int {
- // Because of the finalizer, any time _key is passed to cgo, that call must
- // be followed by a call to runtime.KeepAlive, to make sure k is not
- // collected (and finalized) before the cgo call returns.
- defer runtime.KeepAlive(k)
- return f(k._key)
+func EncryptRSAOAEP(h hash.Hash, pub *PublicKeyRSA, msg, label []byte) (out []byte, err error) {
+ pub.withKey(func(key *boringcrypto.GoRSA) {
+ out, err = external.EncryptRSAOAEP(h, key, msg, label)
+ })
+ return out, err
}

-func setupRSA(withKey func(func(*C.GO_RSA) C.int) C.int,
- padding C.int, h hash.Hash, label []byte, saltLen int, ch crypto.Hash,
- init func(*C.GO_EVP_PKEY_CTX) C.int) (pkey *C.GO_EVP_PKEY, ctx *C.GO_EVP_PKEY_CTX, err error) {
- defer func() {
- if err != nil {
- if pkey != nil {
- C._goboringcrypto_EVP_PKEY_free(pkey)
- pkey = nil
- }
- if ctx != nil {
- C._goboringcrypto_EVP_PKEY_CTX_free(ctx)
- ctx = nil
- }
- }
- }()
-
- pkey = C._goboringcrypto_EVP_PKEY_new()
- if pkey == nil {
- return nil, nil, fail("EVP_PKEY_new")
- }
- if withKey(func(key *C.GO_RSA) C.int {
- return C._goboringcrypto_EVP_PKEY_set1_RSA(pkey, key)
- }) == 0 {
- return nil, nil, fail("EVP_PKEY_set1_RSA")
- }
- ctx = C._goboringcrypto_EVP_PKEY_CTX_new(pkey, nil)
- if ctx == nil {
- return nil, nil, fail("EVP_PKEY_CTX_new")
- }
- if init(ctx) == 0 {
- return nil, nil, fail("EVP_PKEY_operation_init")
- }
- if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_padding(ctx, padding) == 0 {
- return nil, nil, fail("EVP_PKEY_CTX_set_rsa_padding")
- }
- if padding == C.GO_RSA_PKCS1_OAEP_PADDING {
- md := hashToMD(h)
- if md == nil {
- return nil, nil, errors.New("crypto/rsa: unsupported hash function")
- }
- if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) == 0 {
- return nil, nil, fail("EVP_PKEY_set_rsa_oaep_md")
- }
- // ctx takes ownership of label, so malloc a copy for BoringCrypto to free.
- clabel := (*C.uint8_t)(C._goboringcrypto_OPENSSL_malloc(C.size_t(len(label))))
- if clabel == nil {
- return nil, nil, fail("OPENSSL_malloc")
- }
- copy((*[1 << 30]byte)(unsafe.Pointer(clabel))[:len(label)], label)
- if C._goboringcrypto_EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, clabel, C.size_t(len(label))) == 0 {
- return nil, nil, fail("EVP_PKEY_CTX_set0_rsa_oaep_label")
- }
- }
- if padding == C.GO_RSA_PKCS1_PSS_PADDING {
- if saltLen != 0 {
- if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, C.int(saltLen)) == 0 {
- return nil, nil, fail("EVP_PKEY_set_rsa_pss_saltlen")
- }
- }
- md := cryptoHashToMD(ch)
- if md == nil {
- return nil, nil, errors.New("crypto/rsa: unsupported hash function")
- }
- if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md) == 0 {
- return nil, nil, fail("EVP_PKEY_set_rsa_mgf1_md")
- }
- }
-
- return pkey, ctx, nil
+func DecryptRSAPKCS1(priv *PrivateKeyRSA, ciphertext []byte) (out []byte, err error) {
+ priv.withKey(func(key *boringcrypto.GoRSA) {
+ out, err = external.DecryptRSAPKCS1(key, ciphertext)
+ })
+ return out, err
}

-func cryptRSA(withKey func(func(*C.GO_RSA) C.int) C.int,
- padding C.int, h hash.Hash, label []byte, saltLen int, ch crypto.Hash,
- init func(*C.GO_EVP_PKEY_CTX) C.int,
- crypt func(*C.GO_EVP_PKEY_CTX, *C.uint8_t, *C.size_t, *C.uint8_t, C.size_t) C.int,
- in []byte) ([]byte, error) {
-
- pkey, ctx, err := setupRSA(withKey, padding, h, label, saltLen, ch, init)
- if err != nil {
- return nil, err
- }
- defer C._goboringcrypto_EVP_PKEY_free(pkey)
- defer C._goboringcrypto_EVP_PKEY_CTX_free(ctx)
-
- var outLen C.size_t
- if crypt(ctx, nil, &outLen, base(in), C.size_t(len(in))) == 0 {
- return nil, fail("EVP_PKEY_decrypt/encrypt")
- }
- out := make([]byte, outLen)
- if crypt(ctx, base(out), &outLen, base(in), C.size_t(len(in))) == 0 {
- return nil, fail("EVP_PKEY_decrypt/encrypt")
- }
- return out[:outLen], nil
+func EncryptRSAPKCS1(pub *PublicKeyRSA, msg []byte) (out []byte, err error) {
+ pub.withKey(func(key *boringcrypto.GoRSA) {
+ out, err = external.EncryptRSAPKCS1(key, msg)
+ })
+ return out, err
}

-func DecryptRSAOAEP(h hash.Hash, priv *PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) {
- return cryptRSA(priv.withKey, C.GO_RSA_PKCS1_OAEP_PADDING, h, label, 0, 0, decryptInit, decrypt, ciphertext)
+func DecryptRSANoPadding(priv *PrivateKeyRSA, ciphertext []byte) (out []byte, err error) {
+ priv.withKey(func(key *boringcrypto.GoRSA) {
+ out, err = external.DecryptRSANoPadding(key, ciphertext)
+ })
+ return out, err
}

-func EncryptRSAOAEP(h hash.Hash, pub *PublicKeyRSA, msg, label []byte) ([]byte, error) {
- return cryptRSA(pub.withKey, C.GO_RSA_PKCS1_OAEP_PADDING, h, label, 0, 0, encryptInit, encrypt, msg)
+func EncryptRSANoPadding(pub *PublicKeyRSA, msg []byte) (out []byte, err error) {
+ pub.withKey(func(key *boringcrypto.GoRSA) {
+ out, err = external.EncryptRSANoPadding(key, msg)
+ })
+ return out, err
}

-func DecryptRSAPKCS1(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) {
- return cryptRSA(priv.withKey, C.GO_RSA_PKCS1_PADDING, nil, nil, 0, 0, decryptInit, decrypt, ciphertext)
-}
-
-func EncryptRSAPKCS1(pub *PublicKeyRSA, msg []byte) ([]byte, error) {
- return cryptRSA(pub.withKey, C.GO_RSA_PKCS1_PADDING, nil, nil, 0, 0, encryptInit, encrypt, msg)
-}
-
-func DecryptRSANoPadding(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) {
- return cryptRSA(priv.withKey, C.GO_RSA_NO_PADDING, nil, nil, 0, 0, decryptInit, decrypt, ciphertext)
-}
-
-func EncryptRSANoPadding(pub *PublicKeyRSA, msg []byte) ([]byte, error) {
- return cryptRSA(pub.withKey, C.GO_RSA_NO_PADDING, nil, nil, 0, 0, encryptInit, encrypt, msg)
-}
-
-// These dumb wrappers work around the fact that cgo functions cannot be used as values directly.
-
-func decryptInit(ctx *C.GO_EVP_PKEY_CTX) C.int {
- return C._goboringcrypto_EVP_PKEY_decrypt_init(ctx)
-}
-
-func decrypt(ctx *C.GO_EVP_PKEY_CTX, out *C.uint8_t, outLen *C.size_t, in *C.uint8_t, inLen C.size_t) C.int {
- return C._goboringcrypto_EVP_PKEY_decrypt(ctx, out, outLen, in, inLen)
-}
-
-func encryptInit(ctx *C.GO_EVP_PKEY_CTX) C.int {
- return C._goboringcrypto_EVP_PKEY_encrypt_init(ctx)
-}
-
-func encrypt(ctx *C.GO_EVP_PKEY_CTX, out *C.uint8_t, outLen *C.size_t, in *C.uint8_t, inLen C.size_t) C.int {
- return C._goboringcrypto_EVP_PKEY_encrypt(ctx, out, outLen, in, inLen)
-}
-
-func SignRSAPSS(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) ([]byte, error) {
- md := cryptoHashToMD(h)
- if md == nil {
- return nil, errors.New("crypto/rsa: unsupported hash function")
- }
+func SignRSAPSS(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) (out []byte, err error) {
if saltLen == 0 {
saltLen = -1
}
- var out []byte
- var outLen C.size_t
- if priv.withKey(func(key *C.GO_RSA) C.int {
- out = make([]byte, C._goboringcrypto_RSA_size(key))
- return C._goboringcrypto_RSA_sign_pss_mgf1(key, &outLen, base(out), C.size_t(len(out)),
- base(hashed), C.size_t(len(hashed)), md, nil, C.int(saltLen))
- }) == 0 {
- return nil, fail("RSA_sign_pss_mgf1")
- }
-
- return out[:outLen], nil
+ priv.withKey(func(key *boringcrypto.GoRSA) {
+ out, err = external.SignRSAPSS(key, hashed, h, saltLen)
+ })
+ return out, err
}

-func VerifyRSAPSS(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error {
- md := cryptoHashToMD(h)
- if md == nil {
- return errors.New("crypto/rsa: unsupported hash function")
- }
+func VerifyRSAPSS(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) (err error) {
if saltLen == 0 {
saltLen = -2 // auto-recover
}
- if pub.withKey(func(key *C.GO_RSA) C.int {
- return C._goboringcrypto_RSA_verify_pss_mgf1(key, base(hashed), C.size_t(len(hashed)),
- md, nil, C.int(saltLen), base(sig), C.size_t(len(sig)))
- }) == 0 {
- return fail("RSA_verify_pss_mgf1")
- }
- return nil
+ pub.withKey(func(key *boringcrypto.GoRSA) {
+ err = external.VerifyRSAPSS(key, h, hashed, sig, saltLen)
+ })
+ return err
}

-func SignRSAPKCS1v15(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) {
- if h == 0 {
- // No hashing.
- var out []byte
- var outLen C.size_t
- if priv.withKey(func(key *C.GO_RSA) C.int {
- out = make([]byte, C._goboringcrypto_RSA_size(key))
- return C._goboringcrypto_RSA_sign_raw(key, &outLen, base(out), C.size_t(len(out)),
- base(hashed), C.size_t(len(hashed)), C.GO_RSA_PKCS1_PADDING)
- }) == 0 {
- return nil, fail("RSA_sign_raw")
- }
- return out[:outLen], nil
- }
-
- md := cryptoHashToMD(h)
- if md == nil {
- return nil, errors.New("crypto/rsa: unsupported hash function: " + strconv.Itoa(int(h)))
- }
- nid := C._goboringcrypto_EVP_MD_type(md)
- var out []byte
- var outLen C.uint
- if priv.withKey(func(key *C.GO_RSA) C.int {
- out = make([]byte, C._goboringcrypto_RSA_size(key))
- return C._goboringcrypto_RSA_sign(nid, base(hashed), C.uint(len(hashed)),
- base(out), &outLen, key)
- }) == 0 {
- return nil, fail("RSA_sign")
- }
- return out[:outLen], nil
+func SignRSAPKCS1v15(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte) (out []byte, err error) {
+ priv.withKey(func(key *boringcrypto.GoRSA) {
+ out, err = external.SignRSAPKCS1v15(key, h, hashed)
+ })
+ return out, err
}

-func VerifyRSAPKCS1v15(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error {
- if h == 0 {
- var out []byte
- var outLen C.size_t
- if pub.withKey(func(key *C.GO_RSA) C.int {
- out = make([]byte, C._goboringcrypto_RSA_size(key))
- return C._goboringcrypto_RSA_verify_raw(key, &outLen, base(out),
- C.size_t(len(out)), base(sig), C.size_t(len(sig)), C.GO_RSA_PKCS1_PADDING)
- }) == 0 {
- return fail("RSA_verify")
- }
- if subtle.ConstantTimeCompare(hashed, out[:outLen]) != 1 {
- return fail("RSA_verify")
- }
- return nil
- }
- md := cryptoHashToMD(h)
- if md == nil {
- return errors.New("crypto/rsa: unsupported hash function")
- }
- nid := C._goboringcrypto_EVP_MD_type(md)
- if pub.withKey(func(key *C.GO_RSA) C.int {
- return C._goboringcrypto_RSA_verify(nid, base(hashed), C.size_t(len(hashed)),
- base(sig), C.size_t(len(sig)), key)
- }) == 0 {
- return fail("RSA_verify")
- }
- return nil
+func VerifyRSAPKCS1v15(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte) (err error) {
+ pub.withKey(func(key *boringcrypto.GoRSA) {
+ err = external.VerifyRSAPKCS1v15(key, h, hashed, sig)
+ })
+ return err
}
diff --git a/src/crypto/internal/boring/sha.go b/src/crypto/internal/boring/sha.go
index 5ca158c..732da21 100644
--- a/src/crypto/internal/boring/sha.go
+++ b/src/crypto/internal/boring/sha.go
@@ -9,472 +9,39 @@

package boring

-// #include "goboringcrypto.h"
-import "C"
import (
- "errors"
"hash"
- "unsafe"
)

+type sha interface {
+ NewSHA1() hash.Hash
+ NewSHA224() hash.Hash
+ NewSHA256() hash.Hash
+ NewSHA384() hash.Hash
+ NewSHA512() hash.Hash
+}
+
// NewSHA1 returns a new SHA1 hash.
func NewSHA1() hash.Hash {
- h := new(sha1Hash)
- h.Reset()
- return h
-}
-
-type sha1Hash struct {
- ctx C.GO_SHA_CTX
- out [20]byte
-}
-
-type sha1Ctx struct {
- h [5]uint32
- nl, nh uint32
- x [64]byte
- nx uint32
-}
-
-func (h *sha1Hash) Reset() { C._goboringcrypto_SHA1_Init(&h.ctx) }
-func (h *sha1Hash) Size() int { return 20 }
-func (h *sha1Hash) BlockSize() int { return 64 }
-func (h *sha1Hash) Sum(in []byte) []byte { return append(in, h.sum()...) }
-
-func (h *sha1Hash) Write(p []byte) (int, error) {
- if len(p) > 0 && C._goboringcrypto_SHA1_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 {
- panic("boringcrypto: SHA1_Update failed")
- }
- return len(p), nil
-}
-
-func (h0 *sha1Hash) sum() []byte {
- h := *h0 // make copy so future Write+Sum is valid
- if C._goboringcrypto_SHA1_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 {
- panic("boringcrypto: SHA1_Final failed")
- }
- return h.out[:]
-}
-
-const (
- sha1Magic = "sha\x01"
- sha1MarshaledSize = len(sha1Magic) + 5*4 + 64 + 8
-)
-
-func (h *sha1Hash) MarshalBinary() ([]byte, error) {
- d := (*sha1Ctx)(unsafe.Pointer(&h.ctx))
- b := make([]byte, 0, sha1MarshaledSize)
- b = append(b, sha1Magic...)
- b = appendUint32(b, d.h[0])
- b = appendUint32(b, d.h[1])
- b = appendUint32(b, d.h[2])
- b = appendUint32(b, d.h[3])
- b = appendUint32(b, d.h[4])
- b = append(b, d.x[:d.nx]...)
- b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
- b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29)
- return b, nil
-}
-
-func (h *sha1Hash) UnmarshalBinary(b []byte) error {
- if len(b) < len(sha1Magic) || string(b[:len(sha1Magic)]) != sha1Magic {
- return errors.New("crypto/sha1: invalid hash state identifier")
- }
- if len(b) != sha1MarshaledSize {
- return errors.New("crypto/sha1: invalid hash state size")
- }
- d := (*sha1Ctx)(unsafe.Pointer(&h.ctx))
- b = b[len(sha1Magic):]
- b, d.h[0] = consumeUint32(b)
- b, d.h[1] = consumeUint32(b)
- b, d.h[2] = consumeUint32(b)
- b, d.h[3] = consumeUint32(b)
- b, d.h[4] = consumeUint32(b)
- b = b[copy(d.x[:], b):]
- b, n := consumeUint64(b)
- d.nl = uint32(n << 3)
- d.nh = uint32(n >> 29)
- d.nx = uint32(n) % 64
- return nil
+ return external.NewSHA1()
}

// NewSHA224 returns a new SHA224 hash.
func NewSHA224() hash.Hash {
- h := new(sha224Hash)
- h.Reset()
- return h
-}
-
-type sha224Hash struct {
- ctx C.GO_SHA256_CTX
- out [224 / 8]byte
-}
-
-func (h *sha224Hash) Reset() { C._goboringcrypto_SHA224_Init(&h.ctx) }
-func (h *sha224Hash) Size() int { return 224 / 8 }
-func (h *sha224Hash) BlockSize() int { return 64 }
-func (h *sha224Hash) Sum(in []byte) []byte { return append(in, h.sum()...) }
-
-func (h *sha224Hash) Write(p []byte) (int, error) {
- if len(p) > 0 && C._goboringcrypto_SHA224_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 {
- panic("boringcrypto: SHA224_Update failed")
- }
- return len(p), nil
-}
-
-func (h0 *sha224Hash) sum() []byte {
- h := *h0 // make copy so future Write+Sum is valid
- if C._goboringcrypto_SHA224_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 {
- panic("boringcrypto: SHA224_Final failed")
- }
- return h.out[:]
+ return external.NewSHA224()
}

// NewSHA256 returns a new SHA256 hash.
func NewSHA256() hash.Hash {
- h := new(sha256Hash)
- h.Reset()
- return h
-}
-
-type sha256Hash struct {
- ctx C.GO_SHA256_CTX
- out [256 / 8]byte
-}
-
-func (h *sha256Hash) Reset() { C._goboringcrypto_SHA256_Init(&h.ctx) }
-func (h *sha256Hash) Size() int { return 256 / 8 }
-func (h *sha256Hash) BlockSize() int { return 64 }
-func (h *sha256Hash) Sum(in []byte) []byte { return append(in, h.sum()...) }
-
-func (h *sha256Hash) Write(p []byte) (int, error) {
- if len(p) > 0 && C._goboringcrypto_SHA256_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 {
- panic("boringcrypto: SHA256_Update failed")
- }
- return len(p), nil
-}
-
-func (h0 *sha256Hash) sum() []byte {
- h := *h0 // make copy so future Write+Sum is valid
- if C._goboringcrypto_SHA256_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 {
- panic("boringcrypto: SHA256_Final failed")
- }
- return h.out[:]
-}
-
-const (
- magic224 = "sha\x02"
- magic256 = "sha\x03"
- marshaledSize256 = len(magic256) + 8*4 + 64 + 8
-)
-
-type sha256Ctx struct {
- h [8]uint32
- nl, nh uint32
- x [64]byte
- nx uint32
-}
-
-func (h *sha224Hash) MarshalBinary() ([]byte, error) {
- d := (*sha256Ctx)(unsafe.Pointer(&h.ctx))
- b := make([]byte, 0, marshaledSize256)
- b = append(b, magic224...)
- b = appendUint32(b, d.h[0])
- b = appendUint32(b, d.h[1])
- b = appendUint32(b, d.h[2])
- b = appendUint32(b, d.h[3])
- b = appendUint32(b, d.h[4])
- b = appendUint32(b, d.h[5])
- b = appendUint32(b, d.h[6])
- b = appendUint32(b, d.h[7])
- b = append(b, d.x[:d.nx]...)
- b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
- b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29)
- return b, nil
-}
-
-func (h *sha256Hash) MarshalBinary() ([]byte, error) {
- d := (*sha256Ctx)(unsafe.Pointer(&h.ctx))
- b := make([]byte, 0, marshaledSize256)
- b = append(b, magic256...)
- b = appendUint32(b, d.h[0])
- b = appendUint32(b, d.h[1])
- b = appendUint32(b, d.h[2])
- b = appendUint32(b, d.h[3])
- b = appendUint32(b, d.h[4])
- b = appendUint32(b, d.h[5])
- b = appendUint32(b, d.h[6])
- b = appendUint32(b, d.h[7])
- b = append(b, d.x[:d.nx]...)
- b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
- b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29)
- return b, nil
-}
-
-func (h *sha224Hash) UnmarshalBinary(b []byte) error {
- if len(b) < len(magic224) || string(b[:len(magic224)]) != magic224 {
- return errors.New("crypto/sha256: invalid hash state identifier")
- }
- if len(b) != marshaledSize256 {
- return errors.New("crypto/sha256: invalid hash state size")
- }
- d := (*sha256Ctx)(unsafe.Pointer(&h.ctx))
- b = b[len(magic224):]
- b, d.h[0] = consumeUint32(b)
- b, d.h[1] = consumeUint32(b)
- b, d.h[2] = consumeUint32(b)
- b, d.h[3] = consumeUint32(b)
- b, d.h[4] = consumeUint32(b)
- b, d.h[5] = consumeUint32(b)
- b, d.h[6] = consumeUint32(b)
- b, d.h[7] = consumeUint32(b)
- b = b[copy(d.x[:], b):]
- b, n := consumeUint64(b)
- d.nl = uint32(n << 3)
- d.nh = uint32(n >> 29)
- d.nx = uint32(n) % 64
- return nil
-}
-
-func (h *sha256Hash) UnmarshalBinary(b []byte) error {
- if len(b) < len(magic256) || string(b[:len(magic256)]) != magic256 {
- return errors.New("crypto/sha256: invalid hash state identifier")
- }
- if len(b) != marshaledSize256 {
- return errors.New("crypto/sha256: invalid hash state size")
- }
- d := (*sha256Ctx)(unsafe.Pointer(&h.ctx))
- b = b[len(magic256):]
- b, d.h[0] = consumeUint32(b)
- b, d.h[1] = consumeUint32(b)
- b, d.h[2] = consumeUint32(b)
- b, d.h[3] = consumeUint32(b)
- b, d.h[4] = consumeUint32(b)
- b, d.h[5] = consumeUint32(b)
- b, d.h[6] = consumeUint32(b)
- b, d.h[7] = consumeUint32(b)
- b = b[copy(d.x[:], b):]
- b, n := consumeUint64(b)
- d.nl = uint32(n << 3)
- d.nh = uint32(n >> 29)
- d.nx = uint32(n) % 64
- return nil
+ return external.NewSHA256()
}

// NewSHA384 returns a new SHA384 hash.
func NewSHA384() hash.Hash {
- h := new(sha384Hash)
- h.Reset()
- return h
-}
-
-type sha384Hash struct {
- ctx C.GO_SHA512_CTX
- out [384 / 8]byte
-}
-
-func (h *sha384Hash) Reset() { C._goboringcrypto_SHA384_Init(&h.ctx) }
-func (h *sha384Hash) Size() int { return 384 / 8 }
-func (h *sha384Hash) BlockSize() int { return 128 }
-func (h *sha384Hash) Sum(in []byte) []byte { return append(in, h.sum()...) }
-
-func (h *sha384Hash) Write(p []byte) (int, error) {
- if len(p) > 0 && C._goboringcrypto_SHA384_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 {
- panic("boringcrypto: SHA384_Update failed")
- }
- return len(p), nil
-}
-
-func (h0 *sha384Hash) sum() []byte {
- h := *h0 // make copy so future Write+Sum is valid
- if C._goboringcrypto_SHA384_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 {
- panic("boringcrypto: SHA384_Final failed")
- }
- return h.out[:]
+ return external.NewSHA384()
}

// NewSHA512 returns a new SHA512 hash.
func NewSHA512() hash.Hash {
- h := new(sha512Hash)
- h.Reset()
- return h
-}
-
-type sha512Hash struct {
- ctx C.GO_SHA512_CTX
- out [512 / 8]byte
-}
-
-func (h *sha512Hash) Reset() { C._goboringcrypto_SHA512_Init(&h.ctx) }
-func (h *sha512Hash) Size() int { return 512 / 8 }
-func (h *sha512Hash) BlockSize() int { return 128 }
-func (h *sha512Hash) Sum(in []byte) []byte { return append(in, h.sum()...) }
-
-func (h *sha512Hash) Write(p []byte) (int, error) {
- if len(p) > 0 && C._goboringcrypto_SHA512_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 {
- panic("boringcrypto: SHA512_Update failed")
- }
- return len(p), nil
-}
-
-func (h0 *sha512Hash) sum() []byte {
- h := *h0 // make copy so future Write+Sum is valid
- if C._goboringcrypto_SHA512_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 {
- panic("boringcrypto: SHA512_Final failed")
- }
- return h.out[:]
-}
-
-type sha512Ctx struct {
- h [8]uint64
- nl, nh uint64
- x [128]byte
- nx uint32
-}
-
-const (
- magic384 = "sha\x04"
- magic512_224 = "sha\x05"
- magic512_256 = "sha\x06"
- magic512 = "sha\x07"
- marshaledSize512 = len(magic512) + 8*8 + 128 + 8
-)
-
-var zero [128]byte
-
-func (h *sha384Hash) MarshalBinary() ([]byte, error) {
- d := (*sha512Ctx)(unsafe.Pointer(&h.ctx))
- b := make([]byte, 0, marshaledSize512)
- b = append(b, magic384...)
- b = appendUint64(b, d.h[0])
- b = appendUint64(b, d.h[1])
- b = appendUint64(b, d.h[2])
- b = appendUint64(b, d.h[3])
- b = appendUint64(b, d.h[4])
- b = appendUint64(b, d.h[5])
- b = appendUint64(b, d.h[6])
- b = appendUint64(b, d.h[7])
- b = append(b, d.x[:d.nx]...)
- b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
- b = appendUint64(b, d.nl>>3|d.nh<<61)
- return b, nil
-}
-
-func (h *sha512Hash) MarshalBinary() ([]byte, error) {
- d := (*sha512Ctx)(unsafe.Pointer(&h.ctx))
- b := make([]byte, 0, marshaledSize512)
- b = append(b, magic512...)
- b = appendUint64(b, d.h[0])
- b = appendUint64(b, d.h[1])
- b = appendUint64(b, d.h[2])
- b = appendUint64(b, d.h[3])
- b = appendUint64(b, d.h[4])
- b = appendUint64(b, d.h[5])
- b = appendUint64(b, d.h[6])
- b = appendUint64(b, d.h[7])
- b = append(b, d.x[:d.nx]...)
- b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
- b = appendUint64(b, d.nl>>3|d.nh<<61)
- return b, nil
-}
-
-func (h *sha384Hash) UnmarshalBinary(b []byte) error {
- if len(b) < len(magic512) {
- return errors.New("crypto/sha512: invalid hash state identifier")
- }
- if string(b[:len(magic384)]) != magic384 {
- return errors.New("crypto/sha512: invalid hash state identifier")
- }
- if len(b) != marshaledSize512 {
- return errors.New("crypto/sha512: invalid hash state size")
- }
- d := (*sha512Ctx)(unsafe.Pointer(&h.ctx))
- b = b[len(magic512):]
- b, d.h[0] = consumeUint64(b)
- b, d.h[1] = consumeUint64(b)
- b, d.h[2] = consumeUint64(b)
- b, d.h[3] = consumeUint64(b)
- b, d.h[4] = consumeUint64(b)
- b, d.h[5] = consumeUint64(b)
- b, d.h[6] = consumeUint64(b)
- b, d.h[7] = consumeUint64(b)
- b = b[copy(d.x[:], b):]
- b, n := consumeUint64(b)
- d.nl = n << 3
- d.nh = n >> 61
- d.nx = uint32(n) % 128
- return nil
-}
-
-func (h *sha512Hash) UnmarshalBinary(b []byte) error {
- if len(b) < len(magic512) {
- return errors.New("crypto/sha512: invalid hash state identifier")
- }
- if string(b[:len(magic512)]) != magic512 {
- return errors.New("crypto/sha512: invalid hash state identifier")
- }
- if len(b) != marshaledSize512 {
- return errors.New("crypto/sha512: invalid hash state size")
- }
- d := (*sha512Ctx)(unsafe.Pointer(&h.ctx))
- b = b[len(magic512):]
- b, d.h[0] = consumeUint64(b)
- b, d.h[1] = consumeUint64(b)
- b, d.h[2] = consumeUint64(b)
- b, d.h[3] = consumeUint64(b)
- b, d.h[4] = consumeUint64(b)
- b, d.h[5] = consumeUint64(b)
- b, d.h[6] = consumeUint64(b)
- b, d.h[7] = consumeUint64(b)
- b = b[copy(d.x[:], b):]
- b, n := consumeUint64(b)
- d.nl = n << 3
- d.nh = n >> 61
- d.nx = uint32(n) % 128
- return nil
-}
-
-func appendUint64(b []byte, x uint64) []byte {
- var a [8]byte
- putUint64(a[:], x)
- return append(b, a[:]...)
-}
-
-func appendUint32(b []byte, x uint32) []byte {
- var a [4]byte
- putUint32(a[:], x)
- return append(b, a[:]...)
-}
-
-func consumeUint64(b []byte) ([]byte, uint64) {
- _ = b[7]
- x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
- uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
- return b[8:], x
-}
-
-func consumeUint32(b []byte) ([]byte, uint32) {
- _ = b[3]
- x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
- return b[4:], x
-}
-
-func putUint64(x []byte, s uint64) {
- _ = x[7]
- x[0] = byte(s >> 56)
- x[1] = byte(s >> 48)
- x[2] = byte(s >> 40)
- x[3] = byte(s >> 32)
- x[4] = byte(s >> 24)
- x[5] = byte(s >> 16)
- x[6] = byte(s >> 8)
- x[7] = byte(s)
-}
-
-func putUint32(x []byte, s uint32) {
- _ = x[3]
- x[0] = byte(s >> 24)
- x[1] = byte(s >> 16)
- x[2] = byte(s >> 8)
- x[3] = byte(s)
+ return external.NewSHA512()
}

To view, visit change 333049. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: dev.boringcrypto
Gerrit-Change-Id: I50e43d25c308065f14082f1a702b2a183295d7bf
Gerrit-Change-Number: 333049
Gerrit-PatchSet: 1
Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
Gerrit-CC: Derek Parker <parker...@gmail.com>
Gerrit-MessageType: newchange

Derek Parker (Gerrit)

unread,
Sep 13, 2021, 5:39:13 PM9/13/21
to Gerrit Bot, goph...@pubsubhelper.golang.org, Katie Hockman, Roland Shoemaker, Filippo Valsorda, golang-co...@googlegroups.com

Attention is currently required from: Filippo Valsorda.

View Change

1 comment:

  • Patchset:

    • Patch Set #1:

      Hello, this patch has been uploaded to Gerrit for just over 2 months now with no review feedback. I've tried @'ing folks in the GitHub PR, I've manually added reviewers here, and I've also posted to the golang-dev mailing list asking for a review on this. Can I please have someone take a look at this?

To view, visit change 333049. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: dev.boringcrypto
Gerrit-Change-Id: I50e43d25c308065f14082f1a702b2a183295d7bf
Gerrit-Change-Number: 333049
Gerrit-PatchSet: 1
Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
Gerrit-Reviewer: Filippo Valsorda <fil...@golang.org>
Gerrit-CC: Derek Parker <parker...@gmail.com>
Gerrit-CC: Katie Hockman <ka...@golang.org>
Gerrit-CC: Roland Shoemaker <rol...@golang.org>
Gerrit-Attention: Filippo Valsorda <fil...@golang.org>
Gerrit-Comment-Date: Mon, 13 Sep 2021 21:39:08 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Gerrit-MessageType: comment

Derek Parker (Gerrit)

unread,
Aug 8, 2025, 3:24:24 PM8/8/25
to Gerrit Bot, goph...@pubsubhelper.golang.org, Roland Shoemaker, golang-co...@googlegroups.com
Attention needed from Filippo Valsorda

Derek Parker added 1 comment

Patchset-level comments
File-level comment, Patchset 1 (Latest):
Derek Parker . resolved

Is there a way to abandon this change so it no longer shows on my dashboard?

Open in Gerrit

Related details

Attention is currently required from:
  • Filippo Valsorda
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: go
Gerrit-Branch: dev.boringcrypto
Gerrit-Change-Id: I50e43d25c308065f14082f1a702b2a183295d7bf
Gerrit-Change-Number: 333049
Gerrit-PatchSet: 1
Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
Gerrit-Reviewer: Filippo Valsorda <fil...@golang.org>
Gerrit-CC: Derek Parker <parker...@gmail.com>
Gerrit-CC: Katie Hockman <ka...@golang.org>
Gerrit-CC: Roland Shoemaker <rol...@golang.org>
Gerrit-Attention: Filippo Valsorda <fil...@golang.org>
Gerrit-Comment-Date: Fri, 08 Aug 2025 19:24:19 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
unsatisfied_requirement
satisfied_requirement
open
diffy

Ian Lance Taylor (Gerrit)

unread,
Aug 8, 2025, 3:41:02 PM8/8/25
to Gerrit Bot, Derek Parker, goph...@pubsubhelper.golang.org, Ian Lance Taylor, Roland Shoemaker, golang-co...@googlegroups.com
Attention needed from Derek Parker and Filippo Valsorda

Ian Lance Taylor added 1 comment

Patchset-level comments
Derek Parker . resolved

Is there a way to abandon this change so it no longer shows on my dashboard?

Ian Lance Taylor

Click the "abandon" button. As the author of the change, I think you should see that.

Open in Gerrit

Related details

Attention is currently required from:
  • Derek Parker
  • Filippo Valsorda
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: go
Gerrit-Branch: dev.boringcrypto
Gerrit-Change-Id: I50e43d25c308065f14082f1a702b2a183295d7bf
Gerrit-Change-Number: 333049
Gerrit-PatchSet: 1
Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
Gerrit-Reviewer: Filippo Valsorda <fil...@golang.org>
Gerrit-CC: Derek Parker <parker...@gmail.com>
Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
Gerrit-CC: Katie Hockman <ka...@golang.org>
Gerrit-CC: Roland Shoemaker <rol...@golang.org>
Gerrit-Attention: Derek Parker <parker...@gmail.com>
Gerrit-Attention: Filippo Valsorda <fil...@golang.org>
Gerrit-Comment-Date: Fri, 08 Aug 2025 19:40:57 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Comment-In-Reply-To: Derek Parker <parker...@gmail.com>
unsatisfied_requirement
satisfied_requirement
open
diffy

Derek Parker (Gerrit)

unread,
Aug 11, 2025, 12:48:24 PM8/11/25
to Gerrit Bot, goph...@pubsubhelper.golang.org, Ian Lance Taylor, Roland Shoemaker, golang-co...@googlegroups.com
Attention needed from Filippo Valsorda

Derek Parker added 1 comment

Patchset-level comments
Derek Parker . resolved

I don't think I'm able to as GerritBot imported this from github (this was opened before I started using the `git codereview` flow).

Open in Gerrit

Related details

Attention is currently required from:
  • Filippo Valsorda
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: go
Gerrit-Branch: dev.boringcrypto
Gerrit-Change-Id: I50e43d25c308065f14082f1a702b2a183295d7bf
Gerrit-Change-Number: 333049
Gerrit-PatchSet: 1
Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
Gerrit-Reviewer: Filippo Valsorda <fil...@golang.org>
Gerrit-CC: Derek Parker <parker...@gmail.com>
Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
Gerrit-CC: Katie Hockman <ka...@golang.org>
Gerrit-CC: Roland Shoemaker <rol...@golang.org>
Gerrit-Attention: Filippo Valsorda <fil...@golang.org>
Gerrit-Comment-Date: Mon, 11 Aug 2025 16:48:19 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
unsatisfied_requirement
satisfied_requirement
open
diffy

t hepudds (Gerrit)

unread,
Aug 11, 2025, 12:53:36 PM8/11/25
to Gerrit Bot, Derek Parker, goph...@pubsubhelper.golang.org, Ian Lance Taylor, Roland Shoemaker, golang-co...@googlegroups.com

t hepudds abandoned this change

Related details

Attention set is empty
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: abandon
unsatisfied_requirement
satisfied_requirement
open
diffy

t hepudds (Gerrit)

unread,
Aug 11, 2025, 12:55:37 PM8/11/25
to Gerrit Bot, Derek Parker, goph...@pubsubhelper.golang.org, Ian Lance Taylor, Roland Shoemaker, golang-co...@googlegroups.com

t hepudds added 1 comment

Patchset-level comments
Derek Parker . resolved

I don't think I'm able to as GerritBot imported this from github (this was opened before I started using the `git codereview` flow).

t hepudds

Hi Derek, I think closing the GitHub PR should work, which will then cause the Gerrit CL to be closed as well a short while later, though I have not tried that myself.

To keep it simple, though, I hit 'Abandon' here in Gerrit just now.

Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: go
Gerrit-Branch: dev.boringcrypto
Gerrit-Change-Id: I50e43d25c308065f14082f1a702b2a183295d7bf
Gerrit-Change-Number: 333049
Gerrit-PatchSet: 1
Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
Gerrit-Reviewer: Filippo Valsorda <fil...@golang.org>
Gerrit-CC: Derek Parker <parker...@gmail.com>
Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
Gerrit-CC: Katie Hockman <ka...@golang.org>
Gerrit-CC: Roland Shoemaker <rol...@golang.org>
Gerrit-CC: t hepudds <thepud...@gmail.com>
Gerrit-Comment-Date: Mon, 11 Aug 2025 16:55:33 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Comment-In-Reply-To: Derek Parker <parker...@gmail.com>
unsatisfied_requirement
satisfied_requirement
open
diffy

Derek Parker (Gerrit)

unread,
Aug 11, 2025, 1:06:23 PM8/11/25
to Gerrit Bot, goph...@pubsubhelper.golang.org, t hepudds, Ian Lance Taylor, Roland Shoemaker, golang-co...@googlegroups.com

Derek Parker added 1 comment

Patchset-level comments
Derek Parker . resolved

I don't think I'm able to as GerritBot imported this from github (this was opened before I started using the `git codereview` flow).

t hepudds

Hi Derek, I think closing the GitHub PR should work, which will then cause the Gerrit CL to be closed as well a short while later, though I have not tried that myself.

To keep it simple, though, I hit 'Abandon' here in Gerrit just now.

Derek Parker

Typically yes, however for some reason that wasn't the case for this one as the Github PR was closed a year ago yesterday.

Thanks for updating this CL as abandoned though, I appreciate it! I didn't have the button in my UI I think because Gerrit imported this.

Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: go
Gerrit-Branch: dev.boringcrypto
Gerrit-Change-Id: I50e43d25c308065f14082f1a702b2a183295d7bf
Gerrit-Change-Number: 333049
Gerrit-PatchSet: 1
Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
Gerrit-Reviewer: Filippo Valsorda <fil...@golang.org>
Gerrit-CC: Derek Parker <parker...@gmail.com>
Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
Gerrit-CC: Katie Hockman <ka...@golang.org>
Gerrit-CC: Roland Shoemaker <rol...@golang.org>
Gerrit-CC: t hepudds <thepud...@gmail.com>
Gerrit-Comment-Date: Mon, 11 Aug 2025 17:06:15 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Comment-In-Reply-To: Derek Parker <parker...@gmail.com>
Comment-In-Reply-To: t hepudds <thepud...@gmail.com>
unsatisfied_requirement
satisfied_requirement
open
diffy

t hepudds (Gerrit)

unread,
Aug 11, 2025, 1:55:08 PM8/11/25
to Gerrit Bot, Derek Parker, goph...@pubsubhelper.golang.org, Ian Lance Taylor, Roland Shoemaker, golang-co...@googlegroups.com

t hepudds added 1 comment

Patchset-level comments
Derek Parker . resolved

I don't think I'm able to as GerritBot imported this from github (this was opened before I started using the `git codereview` flow).

t hepudds

Hi Derek, I think closing the GitHub PR should work, which will then cause the Gerrit CL to be closed as well a short while later, though I have not tried that myself.

To keep it simple, though, I hit 'Abandon' here in Gerrit just now.

Derek Parker

Typically yes, however for some reason that wasn't the case for this one as the Github PR was closed a year ago yesterday.

Thanks for updating this CL as abandoned though, I appreciate it! I didn't have the button in my UI I think because Gerrit imported this.

t hepudds

Hmm, interesting. I think I have seen it work for closing a PR to trigger the CL to then be automatically abandoned, though as I said, I've never tried myself.

Maybe unlucky timing of a restart by GerritBot interfered in that particular case, or something like that? (That said, I thought GerritBot generally tries to resilient in the face of restarts.)

I guess if you have seen that on another PR or see it in the future, feel free to file an issue or comment back here (or maybe there already is an issue).

Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: go
Gerrit-Branch: dev.boringcrypto
Gerrit-Change-Id: I50e43d25c308065f14082f1a702b2a183295d7bf
Gerrit-Change-Number: 333049
Gerrit-PatchSet: 1
Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
Gerrit-Reviewer: Filippo Valsorda <fil...@golang.org>
Gerrit-CC: Derek Parker <parker...@gmail.com>
Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
Gerrit-CC: Katie Hockman <ka...@golang.org>
Gerrit-CC: Roland Shoemaker <rol...@golang.org>
Gerrit-CC: t hepudds <thepud...@gmail.com>
Gerrit-Comment-Date: Mon, 11 Aug 2025 17:55:02 +0000
unsatisfied_requirement
satisfied_requirement
open
diffy
Reply all
Reply to author
Forward
0 new messages