]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.boringcrypto] crypto/aes: use BoringCrypto
authorRuss Cox <rsc@golang.org>
Thu, 3 Aug 2017 15:08:27 +0000 (11:08 -0400)
committerRuss Cox <rsc@golang.org>
Thu, 17 Aug 2017 19:38:05 +0000 (19:38 +0000)
Change-Id: If83fdeac31f65aba818bbc7edd2f215b16814021
Reviewed-on: https://go-review.googlesource.com/55476
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
src/crypto/aes/cipher.go
src/crypto/aes/cipher_amd64.go
src/crypto/internal/boring/aes.go [new file with mode: 0644]
src/crypto/internal/boring/notboring.go
src/crypto/tls/cipher_suites.go

index c5a8e91d009b790da6d790edc04e26e175dcb736..fbd01a8f408241a55d9361fea81599297e30bd0d 100644 (file)
@@ -6,6 +6,7 @@ package aes
 
 import (
        "crypto/cipher"
+       "crypto/internal/boring"
        "strconv"
 )
 
@@ -36,6 +37,9 @@ func NewCipher(key []byte) (cipher.Block, error) {
        case 16, 24, 32:
                break
        }
+       if boring.Enabled {
+               return boring.NewAESCipher(key)
+       }
        return newCipher(key)
 }
 
index 43de3bdffdd2be57f0d4db20b0a8b904d2618dc0..fcdebabb33b48c0444d813fc08f3cab5d6cd895f 100644 (file)
@@ -6,6 +6,7 @@ package aes
 
 import (
        "crypto/cipher"
+       "crypto/internal/boring"
        "crypto/internal/cipherhw"
 )
 
@@ -46,6 +47,7 @@ func newCipher(key []byte) (cipher.Block, error) {
 func (c *aesCipherAsm) BlockSize() int { return BlockSize }
 
 func (c *aesCipherAsm) Encrypt(dst, src []byte) {
+       boring.Unreachable()
        if len(src) < BlockSize {
                panic("crypto/aes: input not full block")
        }
@@ -56,6 +58,7 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) {
 }
 
 func (c *aesCipherAsm) Decrypt(dst, src []byte) {
+       boring.Unreachable()
        if len(src) < BlockSize {
                panic("crypto/aes: input not full block")
        }
diff --git a/src/crypto/internal/boring/aes.go b/src/crypto/internal/boring/aes.go
new file mode 100644 (file)
index 0000000..8b55564
--- /dev/null
@@ -0,0 +1,295 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux,amd64
+// +build !cmd_go_bootstrap
+
+package boring
+
+// #include "goboringcrypto.h"
+import "C"
+import (
+       "crypto/cipher"
+       "errors"
+       "runtime"
+       "strconv"
+       "unsafe"
+)
+
+type aesKeySizeError int
+
+func (k aesKeySizeError) Error() string {
+       return "crypto/aes: invalid key size " + strconv.Itoa(int(k))
+}
+
+const aesBlockSize = 16
+
+type aesCipher struct {
+       key []byte
+       enc C.GO_AES_KEY
+       dec C.GO_AES_KEY
+}
+
+type extraModes interface {
+       // Copied out of crypto/aes/modes.go.
+       NewCBCEncrypter(iv []byte) cipher.BlockMode
+       NewCBCDecrypter(iv []byte) cipher.BlockMode
+       NewCTR(iv []byte) cipher.Stream
+       NewGCM(size int) (cipher.AEAD, error)
+}
+
+var _ extraModes = (*aesCipher)(nil)
+
+func NewAESCipher(key []byte) (cipher.Block, error) {
+       c := &aesCipher{key: make([]byte, len(key))}
+       copy(c.key, key)
+       // Note: 0 is success, contradicting the usual BoringCrypto convention.
+       if C._goboringcrypto_AES_set_decrypt_key((*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.uint(8*len(c.key)), &c.dec) != 0 ||
+               C._goboringcrypto_AES_set_encrypt_key((*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.uint(8*len(c.key)), &c.enc) != 0 {
+               return nil, aesKeySizeError(len(key))
+       }
+       return c, nil
+}
+
+func (c *aesCipher) BlockSize() int { return aesBlockSize }
+
+func (c *aesCipher) Encrypt(dst, src []byte) {
+       if len(src) < aesBlockSize {
+               panic("crypto/aes: input not full block")
+       }
+       if len(dst) < aesBlockSize {
+               panic("crypto/aes: output not full block")
+       }
+       C._goboringcrypto_AES_encrypt(
+               (*C.uint8_t)(unsafe.Pointer(&src[0])),
+               (*C.uint8_t)(unsafe.Pointer(&dst[0])),
+               &c.enc)
+}
+
+func (c *aesCipher) Decrypt(dst, src []byte) {
+       if len(src) < aesBlockSize {
+               panic("crypto/aes: input not full block")
+       }
+       if len(dst) < aesBlockSize {
+               panic("crypto/aes: output not full block")
+       }
+       C._goboringcrypto_AES_decrypt(
+               (*C.uint8_t)(unsafe.Pointer(&src[0])),
+               (*C.uint8_t)(unsafe.Pointer(&dst[0])),
+               &c.dec)
+}
+
+type aesCBC struct {
+       key  *C.GO_AES_KEY
+       mode C.int
+       iv   [aesBlockSize]byte
+}
+
+func (x *aesCBC) BlockSize() int { return aesBlockSize }
+
+func (x *aesCBC) CryptBlocks(dst, src []byte) {
+       if len(src)%aesBlockSize != 0 {
+               panic("crypto/cipher: input not full blocks")
+       }
+       if len(dst) < len(src) {
+               panic("crypto/cipher: output smaller than input")
+       }
+       if len(src) > 0 {
+               C._goboringcrypto_AES_cbc_encrypt(
+                       (*C.uint8_t)(unsafe.Pointer(&src[0])),
+                       (*C.uint8_t)(unsafe.Pointer(&dst[0])),
+                       C.size_t(len(src)), x.key,
+                       (*C.uint8_t)(unsafe.Pointer(&x.iv[0])), x.mode)
+       }
+}
+
+func (x *aesCBC) SetIV(iv []byte) {
+       if len(iv) != aesBlockSize {
+               panic("cipher: incorrect length IV")
+       }
+       copy(x.iv[:], iv)
+}
+
+func (c *aesCipher) NewCBCEncrypter(iv []byte) cipher.BlockMode {
+       x := &aesCBC{key: &c.enc, mode: C.GO_AES_ENCRYPT}
+       copy(x.iv[:], iv)
+       return x
+}
+
+func (c *aesCipher) NewCBCDecrypter(iv []byte) cipher.BlockMode {
+       x := &aesCBC{key: &c.dec, mode: C.GO_AES_DECRYPT}
+       copy(x.iv[:], iv)
+       return x
+}
+
+type aesCTR struct {
+       key        *C.GO_AES_KEY
+       iv         [aesBlockSize]byte
+       num        C.uint
+       ecount_buf [16]C.uint8_t
+}
+
+func (x *aesCTR) XORKeyStream(dst, src []byte) {
+       if len(dst) < len(src) {
+               panic("crypto/cipher: output smaller than input")
+       }
+       if len(src) == 0 {
+               return
+       }
+       C._goboringcrypto_AES_ctr128_encrypt(
+               (*C.uint8_t)(unsafe.Pointer(&src[0])),
+               (*C.uint8_t)(unsafe.Pointer(&dst[0])),
+               C.size_t(len(src)), x.key, (*C.uint8_t)(unsafe.Pointer(&x.iv[0])),
+               &x.ecount_buf[0], &x.num)
+}
+
+func (c *aesCipher) NewCTR(iv []byte) cipher.Stream {
+       x := &aesCTR{key: &c.enc}
+       copy(x.iv[:], iv)
+       return x
+}
+
+type aesGCM struct {
+       ctx  C.GO_EVP_AEAD_CTX
+       aead *C.GO_EVP_AEAD
+}
+
+const (
+       gcmBlockSize         = 16
+       gcmTagSize           = 16
+       gcmStandardNonceSize = 12
+)
+
+type aesNonceSizeError int
+
+func (n aesNonceSizeError) Error() string {
+       return "crypto/aes: invalid GCM nonce size " + strconv.Itoa(int(n))
+}
+
+type noGCM struct {
+       cipher.Block
+}
+
+func (c *aesCipher) NewGCM(nonceSize int) (cipher.AEAD, error) {
+       if nonceSize != gcmStandardNonceSize {
+               // Fall back to standard library for GCM with non-standard nonce size.
+               return cipher.NewGCMWithNonceSize(&noGCM{c}, nonceSize)
+       }
+
+       var aead *C.GO_EVP_AEAD
+       switch len(c.key) * 8 {
+       case 128:
+               aead = C._goboringcrypto_EVP_aead_aes_128_gcm()
+       case 256:
+               aead = C._goboringcrypto_EVP_aead_aes_256_gcm()
+       default:
+               // Fall back to standard library for GCM with non-standard key size.
+               return cipher.NewGCMWithNonceSize(&noGCM{c}, nonceSize)
+       }
+
+       g := &aesGCM{aead: aead}
+       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 {
+               return nil, fail("EVP_AEAD_CTX_init")
+       }
+       runtime.SetFinalizer(g, (*aesGCM).finalize)
+       if g.NonceSize() != nonceSize {
+               panic("boringcrypto: internal confusion about nonce size")
+       }
+       if g.Overhead() != gcmTagSize {
+               panic("boringcrypto: internal confusion about tag size")
+       }
+
+       return g, nil
+}
+
+func (g *aesGCM) finalize() {
+       C._goboringcrypto_EVP_AEAD_CTX_cleanup(&g.ctx)
+}
+
+func (g *aesGCM) NonceSize() int {
+       return int(C._goboringcrypto_EVP_AEAD_nonce_length(g.aead))
+}
+
+func (g *aesGCM) Overhead() int {
+       return int(C._goboringcrypto_EVP_AEAD_max_overhead(g.aead))
+}
+
+// base returns the address of the underlying array in b,
+// being careful not to panic when b has zero length.
+func base(b []byte) *C.uint8_t {
+       if len(b) == 0 {
+               return nil
+       }
+       return (*C.uint8_t)(unsafe.Pointer(&b[0]))
+}
+
+func (g *aesGCM) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
+       if len(nonce) != gcmStandardNonceSize {
+               panic("cipher: incorrect nonce length given to GCM")
+       }
+       if uint64(len(plaintext)) > ((1<<32)-2)*aesBlockSize || len(plaintext)+gcmTagSize < len(plaintext) {
+               panic("cipher: message too large for GCM")
+       }
+       if len(dst)+len(plaintext)+gcmTagSize < len(dst) {
+               panic("cipher: message too large for buffer")
+       }
+
+       // Make room in dst to append plaintext+overhead.
+       n := len(dst)
+       for cap(dst) < n+len(plaintext)+gcmTagSize {
+               dst = append(dst[:cap(dst)], 0)
+       }
+       dst = dst[:n+len(plaintext)+gcmTagSize]
+
+       var outLen C.size_t
+       ok := C._goboringcrypto_EVP_AEAD_CTX_seal(
+               &g.ctx,
+               (*C.uint8_t)(unsafe.Pointer(&dst[n])), &outLen, C.size_t(len(plaintext)+gcmTagSize),
+               base(nonce), C.size_t(len(nonce)),
+               base(plaintext), C.size_t(len(plaintext)),
+               base(additionalData), C.size_t(len(additionalData)))
+       if ok == 0 {
+               panic(fail("EVP_AEAD_CTX_seal"))
+       }
+       if outLen != C.size_t(len(plaintext)+gcmTagSize) {
+               panic("boringcrypto: internal confusion about GCM tag size")
+       }
+       return dst[:n+int(outLen)]
+}
+
+var errOpen = errors.New("cipher: message authentication failed")
+
+func (g *aesGCM) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+       if len(nonce) != gcmStandardNonceSize {
+               panic("cipher: incorrect nonce length given to GCM")
+       }
+       if len(ciphertext) < gcmTagSize {
+               return nil, errOpen
+       }
+       if uint64(len(ciphertext)) > ((1<<32)-2)*aesBlockSize+gcmTagSize {
+               return nil, errOpen
+       }
+
+       // Make room in dst to append ciphertext without tag.
+       n := len(dst)
+       for cap(dst) < n+len(ciphertext)-gcmTagSize {
+               dst = append(dst[:cap(dst)], 0)
+       }
+       dst = dst[:n+len(ciphertext)-gcmTagSize]
+
+       var outLen C.size_t
+       ok := C._goboringcrypto_EVP_AEAD_CTX_open(
+               &g.ctx,
+               base(dst[n:]), &outLen, C.size_t(len(ciphertext)-gcmTagSize),
+               base(nonce), C.size_t(len(nonce)),
+               base(ciphertext), C.size_t(len(ciphertext)),
+               base(additionalData), C.size_t(len(additionalData)))
+       if ok == 0 {
+               return nil, errOpen
+       }
+       if outLen != C.size_t(len(ciphertext)-gcmTagSize) {
+               panic("boringcrypto: internal confusion about GCM tag size")
+       }
+       return dst[:n+int(outLen)], nil
+}
index 727247bc619765a9dc41f7b13bd1542cb2f8e3d4..5cf12bc4b093904c14a3920f811de3cec9688667 100644 (file)
@@ -6,7 +6,10 @@
 
 package boring
 
-import "hash"
+import (
+       "crypto/cipher"
+       "hash"
+)
 
 const available = false
 
@@ -31,3 +34,5 @@ func NewSHA384() hash.Hash { panic("boringcrypto: not available") }
 func NewSHA512() hash.Hash { panic("boringcrypto: not available") }
 
 func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { panic("boringcrypto: not available") }
+
+func NewAESCipher(key []byte) (cipher.Block, error) { panic("boringcrypto: not available") }
index 2aeaf668e4aae55e8fbdd21553a3422730d0d221..d39c6d3b66e1dfaddca186e6fcb5dc314c175952 100644 (file)
@@ -136,7 +136,11 @@ func macSHA1(version uint16, key []byte) macFunction {
                copy(mac.key, key)
                return mac
        }
-       return tls10MAC{hmac.New(newConstantTimeHash(sha1.New), key)}
+       h := sha1.New
+       if !boring.Enabled {
+               h = newConstantTimeHash(h)
+       }
+       return tls10MAC{hmac.New(h, key)}
 }
 
 // macSHA256 returns a SHA-256 based MAC. These are only supported in TLS 1.2