1
2
3
4
5
6
7 package boring
8
9
45 import "C"
46 import (
47 "bytes"
48 "crypto/cipher"
49 "errors"
50 "runtime"
51 "slices"
52 "strconv"
53 "unsafe"
54 )
55
56 type aesKeySizeError int
57
58 func (k aesKeySizeError) Error() string {
59 return "crypto/aes: invalid key size " + strconv.Itoa(int(k))
60 }
61
62 const aesBlockSize = 16
63
64 type aesCipher struct {
65 key []byte
66 enc C.GO_AES_KEY
67 dec C.GO_AES_KEY
68 }
69
70 type extraModes interface {
71
72 NewCBCEncrypter(iv []byte) cipher.BlockMode
73 NewCBCDecrypter(iv []byte) cipher.BlockMode
74 NewCTR(iv []byte) cipher.Stream
75 NewGCM(nonceSize, tagSize int) (cipher.AEAD, error)
76 }
77
78 var _ extraModes = (*aesCipher)(nil)
79
80 func NewAESCipher(key []byte) (cipher.Block, error) {
81 c := &aesCipher{key: bytes.Clone(key)}
82
83 if C._goboringcrypto_AES_set_decrypt_key((*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.uint(8*len(c.key)), &c.dec) != 0 ||
84 C._goboringcrypto_AES_set_encrypt_key((*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.uint(8*len(c.key)), &c.enc) != 0 {
85 return nil, aesKeySizeError(len(key))
86 }
87 return c, nil
88 }
89
90 func (c *aesCipher) BlockSize() int { return aesBlockSize }
91
92 func (c *aesCipher) Encrypt(dst, src []byte) {
93 if inexactOverlap(dst, src) {
94 panic("crypto/cipher: invalid buffer overlap")
95 }
96 if len(src) < aesBlockSize {
97 panic("crypto/aes: input not full block")
98 }
99 if len(dst) < aesBlockSize {
100 panic("crypto/aes: output not full block")
101 }
102 C._goboringcrypto_AES_encrypt(
103 (*C.uint8_t)(unsafe.Pointer(&src[0])),
104 (*C.uint8_t)(unsafe.Pointer(&dst[0])),
105 &c.enc)
106 }
107
108 func (c *aesCipher) Decrypt(dst, src []byte) {
109 if inexactOverlap(dst, src) {
110 panic("crypto/cipher: invalid buffer overlap")
111 }
112 if len(src) < aesBlockSize {
113 panic("crypto/aes: input not full block")
114 }
115 if len(dst) < aesBlockSize {
116 panic("crypto/aes: output not full block")
117 }
118 C._goboringcrypto_AES_decrypt(
119 (*C.uint8_t)(unsafe.Pointer(&src[0])),
120 (*C.uint8_t)(unsafe.Pointer(&dst[0])),
121 &c.dec)
122 }
123
124 type aesCBC struct {
125 key *C.GO_AES_KEY
126 mode C.int
127 iv [aesBlockSize]byte
128 }
129
130 func (x *aesCBC) BlockSize() int { return aesBlockSize }
131
132 func (x *aesCBC) CryptBlocks(dst, src []byte) {
133 if inexactOverlap(dst, src) {
134 panic("crypto/cipher: invalid buffer overlap")
135 }
136 if len(src)%aesBlockSize != 0 {
137 panic("crypto/cipher: input not full blocks")
138 }
139 if len(dst) < len(src) {
140 panic("crypto/cipher: output smaller than input")
141 }
142 if len(src) > 0 {
143 C._goboringcrypto_AES_cbc_encrypt(
144 (*C.uint8_t)(unsafe.Pointer(&src[0])),
145 (*C.uint8_t)(unsafe.Pointer(&dst[0])),
146 C.size_t(len(src)), x.key,
147 (*C.uint8_t)(unsafe.Pointer(&x.iv[0])), x.mode)
148 }
149 }
150
151 func (x *aesCBC) SetIV(iv []byte) {
152 if len(iv) != aesBlockSize {
153 panic("cipher: incorrect length IV")
154 }
155 copy(x.iv[:], iv)
156 }
157
158 func (c *aesCipher) NewCBCEncrypter(iv []byte) cipher.BlockMode {
159 x := &aesCBC{key: &c.enc, mode: C.GO_AES_ENCRYPT}
160 copy(x.iv[:], iv)
161 return x
162 }
163
164 func (c *aesCipher) NewCBCDecrypter(iv []byte) cipher.BlockMode {
165 x := &aesCBC{key: &c.dec, mode: C.GO_AES_DECRYPT}
166 copy(x.iv[:], iv)
167 return x
168 }
169
170 type aesCTR struct {
171 key *C.GO_AES_KEY
172 iv [aesBlockSize]byte
173 num C.uint
174 ecount_buf [16]C.uint8_t
175 }
176
177 func (x *aesCTR) XORKeyStream(dst, src []byte) {
178 if inexactOverlap(dst, src) {
179 panic("crypto/cipher: invalid buffer overlap")
180 }
181 if len(dst) < len(src) {
182 panic("crypto/cipher: output smaller than input")
183 }
184 if len(src) == 0 {
185 return
186 }
187 C._goboringcrypto_AES_ctr128_encrypt(
188 (*C.uint8_t)(unsafe.Pointer(&src[0])),
189 (*C.uint8_t)(unsafe.Pointer(&dst[0])),
190 C.size_t(len(src)), x.key, (*C.uint8_t)(unsafe.Pointer(&x.iv[0])),
191 &x.ecount_buf[0], &x.num)
192 }
193
194 func (c *aesCipher) NewCTR(iv []byte) cipher.Stream {
195 x := &aesCTR{key: &c.enc}
196 copy(x.iv[:], iv)
197 return x
198 }
199
200 type aesGCM struct {
201 ctx C.GO_EVP_AEAD_CTX
202 aead *C.GO_EVP_AEAD
203 }
204
205 const (
206 gcmBlockSize = 16
207 gcmTagSize = 16
208 gcmStandardNonceSize = 12
209 )
210
211 type aesNonceSizeError int
212
213 func (n aesNonceSizeError) Error() string {
214 return "crypto/aes: invalid GCM nonce size " + strconv.Itoa(int(n))
215 }
216
217 type noGCM struct {
218 cipher.Block
219 }
220
221 func (c *aesCipher) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
222 if nonceSize != gcmStandardNonceSize && tagSize != gcmTagSize {
223 return nil, errors.New("crypto/aes: GCM tag and nonce sizes can't be non-standard at the same time")
224 }
225
226 if nonceSize != gcmStandardNonceSize {
227 return cipher.NewGCMWithNonceSize(&noGCM{c}, nonceSize)
228 }
229 if tagSize != gcmTagSize {
230 return cipher.NewGCMWithTagSize(&noGCM{c}, tagSize)
231 }
232 return c.newGCM(0)
233 }
234
235 const (
236 VersionTLS12 = 0x0303
237 VersionTLS13 = 0x0304
238 )
239
240 func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) {
241 return c.(*aesCipher).newGCM(VersionTLS12)
242 }
243
244 func NewGCMTLS13(c cipher.Block) (cipher.AEAD, error) {
245 return c.(*aesCipher).newGCM(VersionTLS13)
246 }
247
248 func (c *aesCipher) newGCM(tlsVersion uint16) (cipher.AEAD, error) {
249 var aead *C.GO_EVP_AEAD
250 switch len(c.key) * 8 {
251 case 128:
252 switch tlsVersion {
253 case VersionTLS12:
254 aead = C._goboringcrypto_EVP_aead_aes_128_gcm_tls12()
255 case VersionTLS13:
256 aead = C._goboringcrypto_EVP_aead_aes_128_gcm_tls13()
257 default:
258 aead = C._goboringcrypto_EVP_aead_aes_128_gcm()
259 }
260 case 256:
261 switch tlsVersion {
262 case VersionTLS12:
263 aead = C._goboringcrypto_EVP_aead_aes_256_gcm_tls12()
264 case VersionTLS13:
265 aead = C._goboringcrypto_EVP_aead_aes_256_gcm_tls13()
266 default:
267 aead = C._goboringcrypto_EVP_aead_aes_256_gcm()
268 }
269 default:
270
271 return cipher.NewGCMWithNonceSize(&noGCM{c}, gcmStandardNonceSize)
272 }
273
274 g := &aesGCM{aead: aead}
275 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 {
276 return nil, fail("EVP_AEAD_CTX_init")
277 }
278
279
280
281
282 runtime.SetFinalizer(g, (*aesGCM).finalize)
283 if g.NonceSize() != gcmStandardNonceSize {
284 panic("boringcrypto: internal confusion about nonce size")
285 }
286 if g.Overhead() != gcmTagSize {
287 panic("boringcrypto: internal confusion about tag size")
288 }
289
290 return g, nil
291 }
292
293 func (g *aesGCM) finalize() {
294 C._goboringcrypto_EVP_AEAD_CTX_cleanup(&g.ctx)
295 }
296
297 func (g *aesGCM) NonceSize() int {
298 return int(C._goboringcrypto_EVP_AEAD_nonce_length(g.aead))
299 }
300
301 func (g *aesGCM) Overhead() int {
302 return int(C._goboringcrypto_EVP_AEAD_max_overhead(g.aead))
303 }
304
305
306
307 func base(b []byte) *C.uint8_t {
308 if len(b) == 0 {
309 return nil
310 }
311 return (*C.uint8_t)(unsafe.Pointer(&b[0]))
312 }
313
314 func (g *aesGCM) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
315 if len(nonce) != gcmStandardNonceSize {
316 panic("cipher: incorrect nonce length given to GCM")
317 }
318 if uint64(len(plaintext)) > ((1<<32)-2)*aesBlockSize || len(plaintext)+gcmTagSize < len(plaintext) {
319 panic("cipher: message too large for GCM")
320 }
321 if len(dst)+len(plaintext)+gcmTagSize < len(dst) {
322 panic("cipher: message too large for buffer")
323 }
324
325
326 n := len(dst)
327 dst = slices.Grow(dst, len(plaintext)+gcmTagSize)
328 dst = dst[:n+len(plaintext)+gcmTagSize]
329
330
331 if inexactOverlap(dst[n:], plaintext) {
332 panic("cipher: invalid buffer overlap")
333 }
334
335 outLen := C.size_t(len(plaintext) + gcmTagSize)
336 ok := C.EVP_AEAD_CTX_seal_wrapper(
337 &g.ctx,
338 (*C.uint8_t)(unsafe.Pointer(&dst[n])), outLen,
339 base(nonce), C.size_t(len(nonce)),
340 base(plaintext), C.size_t(len(plaintext)),
341 base(additionalData), C.size_t(len(additionalData)))
342 runtime.KeepAlive(g)
343 if ok == 0 {
344 panic(fail("EVP_AEAD_CTX_seal"))
345 }
346 return dst[:n+int(outLen)]
347 }
348
349 var errOpen = errors.New("cipher: message authentication failed")
350
351 func (g *aesGCM) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
352 if len(nonce) != gcmStandardNonceSize {
353 panic("cipher: incorrect nonce length given to GCM")
354 }
355 if len(ciphertext) < gcmTagSize {
356 return nil, errOpen
357 }
358 if uint64(len(ciphertext)) > ((1<<32)-2)*aesBlockSize+gcmTagSize {
359 return nil, errOpen
360 }
361
362
363 n := len(dst)
364 for cap(dst) < n+len(ciphertext)-gcmTagSize {
365 dst = append(dst[:cap(dst)], 0)
366 }
367 dst = dst[:n+len(ciphertext)-gcmTagSize]
368
369
370 if inexactOverlap(dst[n:], ciphertext) {
371 panic("cipher: invalid buffer overlap")
372 }
373
374 outLen := C.size_t(len(ciphertext) - gcmTagSize)
375 ok := C.EVP_AEAD_CTX_open_wrapper(
376 &g.ctx,
377 base(dst[n:]), outLen,
378 base(nonce), C.size_t(len(nonce)),
379 base(ciphertext), C.size_t(len(ciphertext)),
380 base(additionalData), C.size_t(len(additionalData)))
381 runtime.KeepAlive(g)
382 if ok == 0 {
383 return nil, errOpen
384 }
385 return dst[:n+int(outLen)], nil
386 }
387
388 func anyOverlap(x, y []byte) bool {
389 return len(x) > 0 && len(y) > 0 &&
390 uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
391 uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
392 }
393
394 func inexactOverlap(x, y []byte) bool {
395 if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
396 return false
397 }
398 return anyOverlap(x, y)
399 }
400
View as plain text