mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.boringcrypto] crypto/aes: use BoringCrypto
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>
This commit is contained in:
parent
74e33c43e9
commit
8d05ec9e58
5 changed files with 313 additions and 2 deletions
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
|
|
|||
295
src/crypto/internal/boring/aes.go
Normal file
295
src/crypto/internal/boring/aes.go
Normal file
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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") }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue