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(false)
232 }
233
234 func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) {
235 return c.(*aesCipher).newGCM(true)
236 }
237
238 func (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
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
263
264
265
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
277 func (g *aesGCM) finalize() {
278 C._goboringcrypto_EVP_AEAD_CTX_cleanup(&g.ctx)
279 }
280
281 func (g *aesGCM) NonceSize() int {
282 return int(C._goboringcrypto_EVP_AEAD_nonce_length(g.aead))
283 }
284
285 func (g *aesGCM) Overhead() int {
286 return int(C._goboringcrypto_EVP_AEAD_max_overhead(g.aead))
287 }
288
289
290
291 func 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
298 func (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
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
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
335 var errOpen = errors.New("cipher: message authentication failed")
336
337 func (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
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
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
374 func 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
380 func 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
View as plain text