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 7package 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 16int 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 30int 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*/ 45import "C" 46import ( 47 "bytes" 48 "crypto/cipher" 49 "errors" 50 "runtime" 51 "strconv" 52 "unsafe" 53) 54 55type aesKeySizeError int 56 57func (k aesKeySizeError) Error() string { 58 return "crypto/aes: invalid key size " + strconv.Itoa(int(k)) 59} 60 61const aesBlockSize = 16 62 63type aesCipher struct { 64 key []byte 65 enc C.GO_AES_KEY 66 dec C.GO_AES_KEY 67} 68 69type 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 77var _ extraModes = (*aesCipher)(nil) 78 79func 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 89func (c *aesCipher) BlockSize() int { return aesBlockSize } 90 91func (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 107func (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 123type aesCBC struct { 124 key *C.GO_AES_KEY 125 mode C.int 126 iv [aesBlockSize]byte 127} 128 129func (x *aesCBC) BlockSize() int { return aesBlockSize } 130 131func (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 150func (x *aesCBC) SetIV(iv []byte) { 151 if len(iv) != aesBlockSize { 152 panic("cipher: incorrect length IV") 153 } 154 copy(x.iv[:], iv) 155} 156 157func (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 163func (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 169type 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 176func (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 193func (c *aesCipher) NewCTR(iv []byte) cipher.Stream { 194 x := &aesCTR{key: &c.enc} 195 copy(x.iv[:], iv) 196 return x 197} 198 199type aesGCM struct { 200 ctx C.GO_EVP_AEAD_CTX 201 aead *C.GO_EVP_AEAD 202} 203 204const ( 205 gcmBlockSize = 16 206 gcmTagSize = 16 207 gcmStandardNonceSize = 12 208) 209 210type aesNonceSizeError int 211 212func (n aesNonceSizeError) Error() string { 213 return "crypto/aes: invalid GCM nonce size " + strconv.Itoa(int(n)) 214} 215 216type noGCM struct { 217 cipher.Block 218} 219 220func (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(false) 232} 233 234func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) { 235 return c.(*aesCipher).newGCM(true) 236} 237 238func (c *aesCipher) newGCM(tls bool) (cipher.AEAD, error) { 239 var aead *C.GO_EVP_AEAD 240 switch len(c.key) * 8 { 241 case 128: 242 if tls { 243 aead = C._goboringcrypto_EVP_aead_aes_128_gcm_tls12() 244 } else { 245 aead = C._goboringcrypto_EVP_aead_aes_128_gcm() 246 } 247 case 256: 248 if tls { 249 aead = C._goboringcrypto_EVP_aead_aes_256_gcm_tls12() 250 } else { 251 aead = C._goboringcrypto_EVP_aead_aes_256_gcm() 252 } 253 default: 254 // Fall back to standard library for GCM with non-standard key size. 255 return cipher.NewGCMWithNonceSize(&noGCM{c}, gcmStandardNonceSize) 256 } 257 258 g := &aesGCM{aead: aead} 259 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 { 260 return nil, fail("EVP_AEAD_CTX_init") 261 } 262 // Note: Because of the finalizer, any time g.ctx is passed to cgo, 263 // that call must be followed by a call to runtime.KeepAlive(g), 264 // to make sure g is not collected (and finalized) before the cgo 265 // call returns. 266 runtime.SetFinalizer(g, (*aesGCM).finalize) 267 if g.NonceSize() != gcmStandardNonceSize { 268 panic("boringcrypto: internal confusion about nonce size") 269 } 270 if g.Overhead() != gcmTagSize { 271 panic("boringcrypto: internal confusion about tag size") 272 } 273 274 return g, nil 275} 276 277func (g *aesGCM) finalize() { 278 C._goboringcrypto_EVP_AEAD_CTX_cleanup(&g.ctx) 279} 280 281func (g *aesGCM) NonceSize() int { 282 return int(C._goboringcrypto_EVP_AEAD_nonce_length(g.aead)) 283} 284 285func (g *aesGCM) Overhead() int { 286 return int(C._goboringcrypto_EVP_AEAD_max_overhead(g.aead)) 287} 288 289// base returns the address of the underlying array in b, 290// being careful not to panic when b has zero length. 291func base(b []byte) *C.uint8_t { 292 if len(b) == 0 { 293 return nil 294 } 295 return (*C.uint8_t)(unsafe.Pointer(&b[0])) 296} 297 298func (g *aesGCM) Seal(dst, nonce, plaintext, additionalData []byte) []byte { 299 if len(nonce) != gcmStandardNonceSize { 300 panic("cipher: incorrect nonce length given to GCM") 301 } 302 if uint64(len(plaintext)) > ((1<<32)-2)*aesBlockSize || len(plaintext)+gcmTagSize < len(plaintext) { 303 panic("cipher: message too large for GCM") 304 } 305 if len(dst)+len(plaintext)+gcmTagSize < len(dst) { 306 panic("cipher: message too large for buffer") 307 } 308 309 // Make room in dst to append plaintext+overhead. 310 n := len(dst) 311 for cap(dst) < n+len(plaintext)+gcmTagSize { 312 dst = append(dst[:cap(dst)], 0) 313 } 314 dst = dst[:n+len(plaintext)+gcmTagSize] 315 316 // Check delayed until now to make sure len(dst) is accurate. 317 if inexactOverlap(dst[n:], plaintext) { 318 panic("cipher: invalid buffer overlap") 319 } 320 321 outLen := C.size_t(len(plaintext) + gcmTagSize) 322 ok := C.EVP_AEAD_CTX_seal_wrapper( 323 &g.ctx, 324 (*C.uint8_t)(unsafe.Pointer(&dst[n])), outLen, 325 base(nonce), C.size_t(len(nonce)), 326 base(plaintext), C.size_t(len(plaintext)), 327 base(additionalData), C.size_t(len(additionalData))) 328 runtime.KeepAlive(g) 329 if ok == 0 { 330 panic(fail("EVP_AEAD_CTX_seal")) 331 } 332 return dst[:n+int(outLen)] 333} 334 335var errOpen = errors.New("cipher: message authentication failed") 336 337func (g *aesGCM) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) { 338 if len(nonce) != gcmStandardNonceSize { 339 panic("cipher: incorrect nonce length given to GCM") 340 } 341 if len(ciphertext) < gcmTagSize { 342 return nil, errOpen 343 } 344 if uint64(len(ciphertext)) > ((1<<32)-2)*aesBlockSize+gcmTagSize { 345 return nil, errOpen 346 } 347 348 // Make room in dst to append ciphertext without tag. 349 n := len(dst) 350 for cap(dst) < n+len(ciphertext)-gcmTagSize { 351 dst = append(dst[:cap(dst)], 0) 352 } 353 dst = dst[:n+len(ciphertext)-gcmTagSize] 354 355 // Check delayed until now to make sure len(dst) is accurate. 356 if inexactOverlap(dst[n:], ciphertext) { 357 panic("cipher: invalid buffer overlap") 358 } 359 360 outLen := C.size_t(len(ciphertext) - gcmTagSize) 361 ok := C.EVP_AEAD_CTX_open_wrapper( 362 &g.ctx, 363 base(dst[n:]), outLen, 364 base(nonce), C.size_t(len(nonce)), 365 base(ciphertext), C.size_t(len(ciphertext)), 366 base(additionalData), C.size_t(len(additionalData))) 367 runtime.KeepAlive(g) 368 if ok == 0 { 369 return nil, errOpen 370 } 371 return dst[:n+int(outLen)], nil 372} 373 374func anyOverlap(x, y []byte) bool { 375 return len(x) > 0 && len(y) > 0 && 376 uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) && 377 uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1])) 378} 379 380func inexactOverlap(x, y []byte) bool { 381 if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { 382 return false 383 } 384 return anyOverlap(x, y) 385} 386