Source file src/crypto/internal/boring/aes.go

     1  // Copyright 2017 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build boringcrypto && linux && (amd64 || arm64) && !android && !msan
     6  
     7  package boring
     8  
     9  /*
    10  
    11  #include "goboringcrypto.h"
    12  
    13  // These wrappers allocate out_len on the C stack, and check that it matches the expected
    14  // value, to avoid having to pass a pointer from Go, which would escape to the heap.
    15  
    16  int EVP_AEAD_CTX_seal_wrapper(const GO_EVP_AEAD_CTX *ctx, uint8_t *out,
    17  							  size_t exp_out_len,
    18  							  const uint8_t *nonce, size_t nonce_len,
    19  							  const uint8_t *in, size_t in_len,
    20  							  const uint8_t *ad, size_t ad_len) {
    21  	size_t out_len;
    22  	int ok = _goboringcrypto_EVP_AEAD_CTX_seal(ctx, out, &out_len, exp_out_len,
    23  		nonce, nonce_len, in, in_len, ad, ad_len);
    24  	if (out_len != exp_out_len) {
    25  		return 0;
    26  	}
    27  	return ok;
    28  };
    29  
    30  int EVP_AEAD_CTX_open_wrapper(const GO_EVP_AEAD_CTX *ctx, uint8_t *out,
    31  							  size_t exp_out_len,
    32  							  const uint8_t *nonce, size_t nonce_len,
    33  							  const uint8_t *in, size_t in_len,
    34  							  const uint8_t *ad, size_t ad_len) {
    35  	size_t out_len;
    36  	int ok = _goboringcrypto_EVP_AEAD_CTX_open(ctx, out, &out_len, exp_out_len,
    37  		nonce, nonce_len, in, in_len, ad, ad_len);
    38  	if (out_len != exp_out_len) {
    39  		return 0;
    40  	}
    41  	return ok;
    42  };
    43  
    44  */
    45  import "C"
    46  import (
    47  	"bytes"
    48  	"crypto/cipher"
    49  	"errors"
    50  	"runtime"
    51  	"strconv"
    52  	"unsafe"
    53  )
    54  
    55  type aesKeySizeError int
    56  
    57  func (k aesKeySizeError) Error() string {
    58  	return "crypto/aes: invalid key size " + strconv.Itoa(int(k))
    59  }
    60  
    61  const aesBlockSize = 16
    62  
    63  type aesCipher struct {
    64  	key []byte
    65  	enc C.GO_AES_KEY
    66  	dec C.GO_AES_KEY
    67  }
    68  
    69  type extraModes interface {
    70  	// Copied out of crypto/aes/modes.go.
    71  	NewCBCEncrypter(iv []byte) cipher.BlockMode
    72  	NewCBCDecrypter(iv []byte) cipher.BlockMode
    73  	NewCTR(iv []byte) cipher.Stream
    74  	NewGCM(nonceSize, tagSize int) (cipher.AEAD, error)
    75  }
    76  
    77  var _ extraModes = (*aesCipher)(nil)
    78  
    79  func NewAESCipher(key []byte) (cipher.Block, error) {
    80  	c := &aesCipher{key: bytes.Clone(key)}
    81  	// Note: 0 is success, contradicting the usual BoringCrypto convention.
    82  	if C._goboringcrypto_AES_set_decrypt_key((*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.uint(8*len(c.key)), &c.dec) != 0 ||
    83  		C._goboringcrypto_AES_set_encrypt_key((*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.uint(8*len(c.key)), &c.enc) != 0 {
    84  		return nil, aesKeySizeError(len(key))
    85  	}
    86  	return c, nil
    87  }
    88  
    89  func (c *aesCipher) BlockSize() int { return aesBlockSize }
    90  
    91  func (c *aesCipher) Encrypt(dst, src []byte) {
    92  	if inexactOverlap(dst, src) {
    93  		panic("crypto/cipher: invalid buffer overlap")
    94  	}
    95  	if len(src) < aesBlockSize {
    96  		panic("crypto/aes: input not full block")
    97  	}
    98  	if len(dst) < aesBlockSize {
    99  		panic("crypto/aes: output not full block")
   100  	}
   101  	C._goboringcrypto_AES_encrypt(
   102  		(*C.uint8_t)(unsafe.Pointer(&src[0])),
   103  		(*C.uint8_t)(unsafe.Pointer(&dst[0])),
   104  		&c.enc)
   105  }
   106  
   107  func (c *aesCipher) Decrypt(dst, src []byte) {
   108  	if inexactOverlap(dst, src) {
   109  		panic("crypto/cipher: invalid buffer overlap")
   110  	}
   111  	if len(src) < aesBlockSize {
   112  		panic("crypto/aes: input not full block")
   113  	}
   114  	if len(dst) < aesBlockSize {
   115  		panic("crypto/aes: output not full block")
   116  	}
   117  	C._goboringcrypto_AES_decrypt(
   118  		(*C.uint8_t)(unsafe.Pointer(&src[0])),
   119  		(*C.uint8_t)(unsafe.Pointer(&dst[0])),
   120  		&c.dec)
   121  }
   122  
   123  type aesCBC struct {
   124  	key  *C.GO_AES_KEY
   125  	mode C.int
   126  	iv   [aesBlockSize]byte
   127  }
   128  
   129  func (x *aesCBC) BlockSize() int { return aesBlockSize }
   130  
   131  func (x *aesCBC) CryptBlocks(dst, src []byte) {
   132  	if inexactOverlap(dst, src) {
   133  		panic("crypto/cipher: invalid buffer overlap")
   134  	}
   135  	if len(src)%aesBlockSize != 0 {
   136  		panic("crypto/cipher: input not full blocks")
   137  	}
   138  	if len(dst) < len(src) {
   139  		panic("crypto/cipher: output smaller than input")
   140  	}
   141  	if len(src) > 0 {
   142  		C._goboringcrypto_AES_cbc_encrypt(
   143  			(*C.uint8_t)(unsafe.Pointer(&src[0])),
   144  			(*C.uint8_t)(unsafe.Pointer(&dst[0])),
   145  			C.size_t(len(src)), x.key,
   146  			(*C.uint8_t)(unsafe.Pointer(&x.iv[0])), x.mode)
   147  	}
   148  }
   149  
   150  func (x *aesCBC) SetIV(iv []byte) {
   151  	if len(iv) != aesBlockSize {
   152  		panic("cipher: incorrect length IV")
   153  	}
   154  	copy(x.iv[:], iv)
   155  }
   156  
   157  func (c *aesCipher) NewCBCEncrypter(iv []byte) cipher.BlockMode {
   158  	x := &aesCBC{key: &c.enc, mode: C.GO_AES_ENCRYPT}
   159  	copy(x.iv[:], iv)
   160  	return x
   161  }
   162  
   163  func (c *aesCipher) NewCBCDecrypter(iv []byte) cipher.BlockMode {
   164  	x := &aesCBC{key: &c.dec, mode: C.GO_AES_DECRYPT}
   165  	copy(x.iv[:], iv)
   166  	return x
   167  }
   168  
   169  type aesCTR struct {
   170  	key        *C.GO_AES_KEY
   171  	iv         [aesBlockSize]byte
   172  	num        C.uint
   173  	ecount_buf [16]C.uint8_t
   174  }
   175  
   176  func (x *aesCTR) XORKeyStream(dst, src []byte) {
   177  	if inexactOverlap(dst, src) {
   178  		panic("crypto/cipher: invalid buffer overlap")
   179  	}
   180  	if len(dst) < len(src) {
   181  		panic("crypto/cipher: output smaller than input")
   182  	}
   183  	if len(src) == 0 {
   184  		return
   185  	}
   186  	C._goboringcrypto_AES_ctr128_encrypt(
   187  		(*C.uint8_t)(unsafe.Pointer(&src[0])),
   188  		(*C.uint8_t)(unsafe.Pointer(&dst[0])),
   189  		C.size_t(len(src)), x.key, (*C.uint8_t)(unsafe.Pointer(&x.iv[0])),
   190  		&x.ecount_buf[0], &x.num)
   191  }
   192  
   193  func (c *aesCipher) NewCTR(iv []byte) cipher.Stream {
   194  	x := &aesCTR{key: &c.enc}
   195  	copy(x.iv[:], iv)
   196  	return x
   197  }
   198  
   199  type aesGCM struct {
   200  	ctx  C.GO_EVP_AEAD_CTX
   201  	aead *C.GO_EVP_AEAD
   202  }
   203  
   204  const (
   205  	gcmBlockSize         = 16
   206  	gcmTagSize           = 16
   207  	gcmStandardNonceSize = 12
   208  )
   209  
   210  type aesNonceSizeError int
   211  
   212  func (n aesNonceSizeError) Error() string {
   213  	return "crypto/aes: invalid GCM nonce size " + strconv.Itoa(int(n))
   214  }
   215  
   216  type noGCM struct {
   217  	cipher.Block
   218  }
   219  
   220  func (c *aesCipher) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
   221  	if nonceSize != gcmStandardNonceSize && tagSize != gcmTagSize {
   222  		return nil, errors.New("crypto/aes: GCM tag and nonce sizes can't be non-standard at the same time")
   223  	}
   224  	// Fall back to standard library for GCM with non-standard nonce or tag size.
   225  	if nonceSize != gcmStandardNonceSize {
   226  		return cipher.NewGCMWithNonceSize(&noGCM{c}, nonceSize)
   227  	}
   228  	if tagSize != gcmTagSize {
   229  		return cipher.NewGCMWithTagSize(&noGCM{c}, tagSize)
   230  	}
   231  	return c.newGCM(0)
   232  }
   233  
   234  const (
   235  	VersionTLS12 = 0x0303
   236  	VersionTLS13 = 0x0304
   237  )
   238  
   239  func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) {
   240  	return c.(*aesCipher).newGCM(VersionTLS12)
   241  }
   242  
   243  func NewGCMTLS13(c cipher.Block) (cipher.AEAD, error) {
   244  	return c.(*aesCipher).newGCM(VersionTLS13)
   245  }
   246  
   247  func (c *aesCipher) newGCM(tlsVersion uint16) (cipher.AEAD, error) {
   248  	var aead *C.GO_EVP_AEAD
   249  	switch len(c.key) * 8 {
   250  	case 128:
   251  		switch tlsVersion {
   252  		case VersionTLS12:
   253  			aead = C._goboringcrypto_EVP_aead_aes_128_gcm_tls12()
   254  		case VersionTLS13:
   255  			aead = C._goboringcrypto_EVP_aead_aes_128_gcm_tls13()
   256  		default:
   257  			aead = C._goboringcrypto_EVP_aead_aes_128_gcm()
   258  		}
   259  	case 256:
   260  		switch tlsVersion {
   261  		case VersionTLS12:
   262  			aead = C._goboringcrypto_EVP_aead_aes_256_gcm_tls12()
   263  		case VersionTLS13:
   264  			aead = C._goboringcrypto_EVP_aead_aes_256_gcm_tls13()
   265  		default:
   266  			aead = C._goboringcrypto_EVP_aead_aes_256_gcm()
   267  		}
   268  	default:
   269  		// Fall back to standard library for GCM with non-standard key size.
   270  		return cipher.NewGCMWithNonceSize(&noGCM{c}, gcmStandardNonceSize)
   271  	}
   272  
   273  	g := &aesGCM{aead: aead}
   274  	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 {
   275  		return nil, fail("EVP_AEAD_CTX_init")
   276  	}
   277  	// Note: Because of the finalizer, any time g.ctx is passed to cgo,
   278  	// that call must be followed by a call to runtime.KeepAlive(g),
   279  	// to make sure g is not collected (and finalized) before the cgo
   280  	// call returns.
   281  	runtime.SetFinalizer(g, (*aesGCM).finalize)
   282  	if g.NonceSize() != gcmStandardNonceSize {
   283  		panic("boringcrypto: internal confusion about nonce size")
   284  	}
   285  	if g.Overhead() != gcmTagSize {
   286  		panic("boringcrypto: internal confusion about tag size")
   287  	}
   288  
   289  	return g, nil
   290  }
   291  
   292  func (g *aesGCM) finalize() {
   293  	C._goboringcrypto_EVP_AEAD_CTX_cleanup(&g.ctx)
   294  }
   295  
   296  func (g *aesGCM) NonceSize() int {
   297  	return int(C._goboringcrypto_EVP_AEAD_nonce_length(g.aead))
   298  }
   299  
   300  func (g *aesGCM) Overhead() int {
   301  	return int(C._goboringcrypto_EVP_AEAD_max_overhead(g.aead))
   302  }
   303  
   304  // base returns the address of the underlying array in b,
   305  // being careful not to panic when b has zero length.
   306  func base(b []byte) *C.uint8_t {
   307  	if len(b) == 0 {
   308  		return nil
   309  	}
   310  	return (*C.uint8_t)(unsafe.Pointer(&b[0]))
   311  }
   312  
   313  func (g *aesGCM) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
   314  	if len(nonce) != gcmStandardNonceSize {
   315  		panic("cipher: incorrect nonce length given to GCM")
   316  	}
   317  	if uint64(len(plaintext)) > ((1<<32)-2)*aesBlockSize || len(plaintext)+gcmTagSize < len(plaintext) {
   318  		panic("cipher: message too large for GCM")
   319  	}
   320  	if len(dst)+len(plaintext)+gcmTagSize < len(dst) {
   321  		panic("cipher: message too large for buffer")
   322  	}
   323  
   324  	// Make room in dst to append plaintext+overhead.
   325  	n := len(dst)
   326  	for cap(dst) < n+len(plaintext)+gcmTagSize {
   327  		dst = append(dst[:cap(dst)], 0)
   328  	}
   329  	dst = dst[:n+len(plaintext)+gcmTagSize]
   330  
   331  	// Check delayed until now to make sure len(dst) is accurate.
   332  	if inexactOverlap(dst[n:], plaintext) {
   333  		panic("cipher: invalid buffer overlap")
   334  	}
   335  
   336  	outLen := C.size_t(len(plaintext) + gcmTagSize)
   337  	ok := C.EVP_AEAD_CTX_seal_wrapper(
   338  		&g.ctx,
   339  		(*C.uint8_t)(unsafe.Pointer(&dst[n])), outLen,
   340  		base(nonce), C.size_t(len(nonce)),
   341  		base(plaintext), C.size_t(len(plaintext)),
   342  		base(additionalData), C.size_t(len(additionalData)))
   343  	runtime.KeepAlive(g)
   344  	if ok == 0 {
   345  		panic(fail("EVP_AEAD_CTX_seal"))
   346  	}
   347  	return dst[:n+int(outLen)]
   348  }
   349  
   350  var errOpen = errors.New("cipher: message authentication failed")
   351  
   352  func (g *aesGCM) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
   353  	if len(nonce) != gcmStandardNonceSize {
   354  		panic("cipher: incorrect nonce length given to GCM")
   355  	}
   356  	if len(ciphertext) < gcmTagSize {
   357  		return nil, errOpen
   358  	}
   359  	if uint64(len(ciphertext)) > ((1<<32)-2)*aesBlockSize+gcmTagSize {
   360  		return nil, errOpen
   361  	}
   362  
   363  	// Make room in dst to append ciphertext without tag.
   364  	n := len(dst)
   365  	for cap(dst) < n+len(ciphertext)-gcmTagSize {
   366  		dst = append(dst[:cap(dst)], 0)
   367  	}
   368  	dst = dst[:n+len(ciphertext)-gcmTagSize]
   369  
   370  	// Check delayed until now to make sure len(dst) is accurate.
   371  	if inexactOverlap(dst[n:], ciphertext) {
   372  		panic("cipher: invalid buffer overlap")
   373  	}
   374  
   375  	outLen := C.size_t(len(ciphertext) - gcmTagSize)
   376  	ok := C.EVP_AEAD_CTX_open_wrapper(
   377  		&g.ctx,
   378  		base(dst[n:]), outLen,
   379  		base(nonce), C.size_t(len(nonce)),
   380  		base(ciphertext), C.size_t(len(ciphertext)),
   381  		base(additionalData), C.size_t(len(additionalData)))
   382  	runtime.KeepAlive(g)
   383  	if ok == 0 {
   384  		return nil, errOpen
   385  	}
   386  	return dst[:n+int(outLen)], nil
   387  }
   388  
   389  func anyOverlap(x, y []byte) bool {
   390  	return len(x) > 0 && len(y) > 0 &&
   391  		uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
   392  		uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
   393  }
   394  
   395  func inexactOverlap(x, y []byte) bool {
   396  	if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
   397  		return false
   398  	}
   399  	return anyOverlap(x, y)
   400  }
   401  

View as plain text