github.com/slackhq/nebula@v1.9.0/noiseutil/boring.go (about)

     1  //go:build boringcrypto
     2  // +build boringcrypto
     3  
     4  package noiseutil
     5  
     6  import (
     7  	"crypto/aes"
     8  	"crypto/cipher"
     9  	"encoding/binary"
    10  
    11  	// unsafe needed for go:linkname
    12  	_ "unsafe"
    13  
    14  	"github.com/flynn/noise"
    15  )
    16  
    17  // EncryptLockNeeded indicates if calls to Encrypt need a lock
    18  // This is true for boringcrypto because the Seal function verifies that the
    19  // nonce is strictly increasing.
    20  const EncryptLockNeeded = true
    21  
    22  // NewGCMTLS is no longer exposed in go1.19+, so we need to link it in
    23  // See: https://github.com/golang/go/issues/56326
    24  //
    25  // NewGCMTLS is the internal method used with boringcrypto that provices a
    26  // validated mode of AES-GCM which enforces the nonce is strictly
    27  // monotonically increasing.  This is the TLS 1.2 specification for nonce
    28  // generation (which also matches the method used by the Noise Protocol)
    29  //
    30  // - https://github.com/golang/go/blob/go1.19/src/crypto/tls/cipher_suites.go#L520-L522
    31  // - https://github.com/golang/go/blob/go1.19/src/crypto/internal/boring/aes.go#L235-L237
    32  // - https://github.com/golang/go/blob/go1.19/src/crypto/internal/boring/aes.go#L250
    33  // - https://github.com/google/boringssl/blob/ae223d6138807a13006342edfeef32e813246b39/include/openssl/aead.h#L379-L381
    34  // - https://github.com/google/boringssl/blob/ae223d6138807a13006342edfeef32e813246b39/crypto/fipsmodule/cipher/e_aes.c#L1082-L1093
    35  //
    36  //go:linkname newGCMTLS crypto/internal/boring.NewGCMTLS
    37  func newGCMTLS(c cipher.Block) (cipher.AEAD, error)
    38  
    39  type cipherFn struct {
    40  	fn   func([32]byte) noise.Cipher
    41  	name string
    42  }
    43  
    44  func (c cipherFn) Cipher(k [32]byte) noise.Cipher { return c.fn(k) }
    45  func (c cipherFn) CipherName() string             { return c.name }
    46  
    47  // CipherAESGCM is the AES256-GCM AEAD cipher (using NewGCMTLS when GoBoring is present)
    48  var CipherAESGCM noise.CipherFunc = cipherFn{cipherAESGCMBoring, "AESGCM"}
    49  
    50  func cipherAESGCMBoring(k [32]byte) noise.Cipher {
    51  	c, err := aes.NewCipher(k[:])
    52  	if err != nil {
    53  		panic(err)
    54  	}
    55  	gcm, err := newGCMTLS(c)
    56  	if err != nil {
    57  		panic(err)
    58  	}
    59  	return aeadCipher{
    60  		gcm,
    61  		func(n uint64) []byte {
    62  			var nonce [12]byte
    63  			binary.BigEndian.PutUint64(nonce[4:], n)
    64  			return nonce[:]
    65  		},
    66  	}
    67  }
    68  
    69  type aeadCipher struct {
    70  	cipher.AEAD
    71  	nonce func(uint64) []byte
    72  }
    73  
    74  func (c aeadCipher) Encrypt(out []byte, n uint64, ad, plaintext []byte) []byte {
    75  	return c.Seal(out, c.nonce(n), plaintext, ad)
    76  }
    77  
    78  func (c aeadCipher) Decrypt(out []byte, n uint64, ad, ciphertext []byte) ([]byte, error) {
    79  	return c.Open(out, c.nonce(n), ciphertext, ad)
    80  }