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 "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
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
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
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
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
278
279
280
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
305
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
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
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
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
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