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