aes.mx raw

   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