]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/internal/boring: use noescape and nocallback cgo directives
authorqmuntal <quimmuntal@gmail.com>
Fri, 1 Sep 2023 07:26:56 +0000 (09:26 +0200)
committerQuim Muntal <quimmuntal@gmail.com>
Mon, 23 Oct 2023 19:41:39 +0000 (19:41 +0000)
The new noescape and nocallback directives can be used instead of the C
wrapper functions that are there just to avoid some parameters being
escaped to the heap.

This CL also helps demonstrate the use of the new directives in real
code.

I've added some benchmarks to demonstrate that this CL doesn't
introduce new heap allocations when using boringcrypto:

```
goos: linux
goarch: amd64
pkg: crypto/aes
cpu: AMD EPYC 7763 64-Core Processor
BenchmarkGCMSeal-32      8378692        143.3 ns/op  111.65 MB/s        0 B/op        0 allocs/op
BenchmarkGCMOpen-32      8383038        142.7 ns/op  112.11 MB/s        0 B/op        0 allocs/op
```

Change-Id: Ifd775484eb9a105afc5c3d4e75a6c6655cbadc53
Reviewed-on: https://go-review.googlesource.com/c/go/+/525035
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
Run-TryBot: Quim Muntal <quimmuntal@gmail.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/crypto/cipher/gcm_test.go
src/crypto/internal/boring/aes.go

index 3556146ea69d321dbdb66c0054c5fbf18cbaee06..7b9d1852d72f72d82702509f4bf74ee8f12502bb 100644 (file)
@@ -654,3 +654,39 @@ func TestGCMAsm(t *testing.T) {
                }
        }
 }
+
+func BenchmarkGCMSeal(b *testing.B) {
+       key, _ := hex.DecodeString("ab72c77b97cb5fe9a382d9fe81ffdbed")
+       nonce, _ := hex.DecodeString("54cc7dc2c37ec006bcc6d1db")
+       plaintext, _ := hex.DecodeString("f1cc3818e421876bb6b8bbd6c9")
+
+       aes, _ := aes.NewCipher(key)
+       aesgcm, _ := cipher.NewGCM(aes)
+
+       ciphertext := make([]byte, 32)
+       b.SetBytes(int64(len(plaintext)))
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               _ = aesgcm.Seal(ciphertext[:0], nonce, plaintext, nil)
+       }
+}
+
+func BenchmarkGCMOpen(b *testing.B) {
+       key, _ := hex.DecodeString("ab72c77b97cb5fe9a382d9fe81ffdbed")
+       nonce, _ := hex.DecodeString("54cc7dc2c37ec006bcc6d1db")
+       plaintext, _ := hex.DecodeString("f1cc3818e421876bb6b8bbd6c9")
+
+       aes, _ := aes.NewCipher(key)
+       aesgcm, _ := cipher.NewGCM(aes)
+
+       ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil)
+
+       b.SetBytes(int64(len(ciphertext)))
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               _, err := aesgcm.Open(plaintext[:0], nonce, ciphertext, nil)
+               if err != nil {
+                       b.Fatal(err)
+               }
+       }
+}
index 8819f576f4f4c5bdd3f26079fe54f9b6a8a62f1f..9520bb0c176bf9baecda0ed5d513891038d80ed8 100644 (file)
@@ -7,40 +7,11 @@
 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;
-};
-
+#cgo noescape _goboringcrypto_EVP_AEAD_CTX_seal
+#cgo nocallback _goboringcrypto_EVP_AEAD_CTX_seal
+#cgo noescape _goboringcrypto_EVP_AEAD_CTX_open
+#cgo nocallback _goboringcrypto_EVP_AEAD_CTX_open
 */
 import "C"
 import (
@@ -318,15 +289,16 @@ func (g *aesGCM) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
                panic("cipher: invalid buffer overlap")
        }
 
-       outLen := C.size_t(len(plaintext) + gcmTagSize)
-       ok := C.EVP_AEAD_CTX_seal_wrapper(
+       var outLen C.size_t
+       expOutLen := C.size_t(len(plaintext) + gcmTagSize)
+       ok := C._goboringcrypto_EVP_AEAD_CTX_seal(
                &g.ctx,
-               (*C.uint8_t)(unsafe.Pointer(&dst[n])), outLen,
+               (*C.uint8_t)(unsafe.Pointer(&dst[n])), &outLen, expOutLen,
                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 {
+       if ok == 0 || outLen != expOutLen {
                panic(fail("EVP_AEAD_CTX_seal"))
        }
        return dst[:n+int(outLen)]
@@ -357,15 +329,16 @@ func (g *aesGCM) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, er
                panic("cipher: invalid buffer overlap")
        }
 
-       outLen := C.size_t(len(ciphertext) - gcmTagSize)
-       ok := C.EVP_AEAD_CTX_open_wrapper(
+       var outLen C.size_t
+       expOutLen := C.size_t(len(ciphertext) - gcmTagSize)
+       ok := C._goboringcrypto_EVP_AEAD_CTX_open(
                &g.ctx,
-               base(dst[n:]), outLen,
+               base(dst[n:]), &outLen, expOutLen,
                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 {
+       if ok == 0 || outLen != expOutLen {
                return nil, errOpen
        }
        return dst[:n+int(outLen)], nil