%PDF- %PDF-
Direktori : /data/old/usr/lib/golang/src/crypto/internal/boring/ |
Current File : //data/old/usr/lib/golang/src/crypto/internal/boring/aes.go |
// 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. //go:build linux && !android && !cmd_go_bootstrap && !msan && !no_openssl && !static // +build linux,!android,!cmd_go_bootstrap,!msan,!no_openssl,!static 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_ctx *C.EVP_CIPHER_CTX dec_ctx *C.EVP_CIPHER_CTX cipher *C.EVP_CIPHER } 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(nonceSize, tagSize int) (cipher.AEAD, error) // Invented for BoringCrypto. NewGCMTLS() (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) switch len(c.key) * 8 { case 128: c.cipher = C._goboringcrypto_EVP_aes_128_ecb() case 192: c.cipher = C._goboringcrypto_EVP_aes_192_ecb() case 256: c.cipher = C._goboringcrypto_EVP_aes_256_ecb() default: return nil, errors.New("crypto/cipher: Invalid key size") } runtime.SetFinalizer(c, (*aesCipher).finalize) return c, nil } func (c *aesCipher) finalize() { if c.enc_ctx != nil { C._goboringcrypto_EVP_CIPHER_CTX_free(c.enc_ctx) } if c.dec_ctx != nil { C._goboringcrypto_EVP_CIPHER_CTX_free(c.dec_ctx) } } func (c *aesCipher) BlockSize() int { return aesBlockSize } func (c *aesCipher) Encrypt(dst, src []byte) { if inexactOverlap(dst, src) { panic("crypto/cipher: invalid buffer overlap") } if len(src) < aesBlockSize { panic("crypto/aes: input not full block") } if len(dst) < aesBlockSize { panic("crypto/aes: output not full block") } if c.enc_ctx == nil { c.enc_ctx = C._goboringcrypto_EVP_CIPHER_CTX_new() if c.enc_ctx == nil { panic("cipher: unable to create EVP cipher ctx") } k := (*C.uchar)(unsafe.Pointer(&c.key[0])) if C.int(1) != C._goboringcrypto_EVP_CipherInit_ex(c.enc_ctx, c.cipher, nil, k, nil, C.GO_AES_ENCRYPT) { panic("cipher: unable to initialize EVP cipher ctx") } } outlen := C.int(0) C._goboringcrypto_EVP_CipherUpdate(c.enc_ctx, (*C.uchar)(unsafe.Pointer(&dst[0])), &outlen, (*C.uchar)(unsafe.Pointer(&src[0])), C.int(aesBlockSize)) runtime.KeepAlive(c) } func (c *aesCipher) Decrypt(dst, src []byte) { if inexactOverlap(dst, src) { panic("crypto/cipher: invalid buffer overlap") } if len(src) < aesBlockSize { panic("crypto/aes: input not full block") } if len(dst) < aesBlockSize { panic("crypto/aes: output not full block") } if c.dec_ctx == nil { c.dec_ctx = C._goboringcrypto_EVP_CIPHER_CTX_new() if c.dec_ctx == nil { panic("cipher: unable to create EVP cipher ctx") } k := (*C.uchar)(unsafe.Pointer(&c.key[0])) if C.int(1) != C._goboringcrypto_EVP_CipherInit_ex(c.dec_ctx, c.cipher, nil, k, nil, C.GO_AES_DECRYPT) { panic("cipher: unable to initialize EVP cipher ctx") } } // Workaround - padding detection is broken but we don't need it // since we check for full blocks if C._goboringcrypto_EVP_CIPHER_CTX_set_padding(c.dec_ctx, 0) != 1 { panic("crypto/cipher: could not disable cipher padding") } outlen := C.int(0) C._goboringcrypto_EVP_CipherUpdate(c.dec_ctx, (*C.uchar)(unsafe.Pointer(&dst[0])), &outlen, (*C.uchar)(unsafe.Pointer(&src[0])), C.int(aesBlockSize)) runtime.KeepAlive(c) } type aesCBC struct { key []byte mode C.int iv [aesBlockSize]byte ctx *C.EVP_CIPHER_CTX } func (x *aesCBC) BlockSize() int { return aesBlockSize } func (x *aesCBC) CryptBlocks(dst, src []byte) { if inexactOverlap(dst, src) { panic("crypto/cipher: invalid buffer overlap") } 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 { outlen := C.int(0) // Workaround - padding detection is broken but we don't need it // since we check for full blocks if C._goboringcrypto_EVP_CIPHER_CTX_set_padding(x.ctx, 0) != 1 { panic("crypto/cipher: could not disable cipher padding") } if C._goboringcrypto_EVP_CipherUpdate( x.ctx, base(dst), &outlen, base(src), C.int(len(src)), ) != 1 { panic("crypto/cipher: CipherUpdate failed") } runtime.KeepAlive(x) } } func (x *aesCBC) SetIV(iv []byte) { if len(iv) != aesBlockSize { panic("cipher: incorrect length IV") } copy(x.iv[:], iv) if C.int(1) != C._goboringcrypto_EVP_CipherInit_ex(x.ctx, nil, nil, nil, (*C.uchar)(unsafe.Pointer(&x.iv[0])), -1) { panic("cipher: unable to initialize EVP cipher ctx") } } func (c *aesCipher) NewCBCEncrypter(iv []byte) cipher.BlockMode { x := &aesCBC{key: c.key, mode: C.GO_AES_ENCRYPT} copy(x.iv[:], iv) x.ctx = C._goboringcrypto_EVP_CIPHER_CTX_new() if x.ctx == nil { panic("cipher: unable to create EVP cipher ctx") } k := (*C.uchar)(unsafe.Pointer(&x.key[0])) vec := (*C.uchar)(unsafe.Pointer(&x.iv[0])) var cipher *C.EVP_CIPHER switch len(c.key) * 8 { case 128: cipher = C._goboringcrypto_EVP_aes_128_cbc() case 192: cipher = C._goboringcrypto_EVP_aes_192_cbc() case 256: cipher = C._goboringcrypto_EVP_aes_256_cbc() default: panic("crypto/boring: unsupported key length") } if C.int(1) != C._goboringcrypto_EVP_CipherInit_ex(x.ctx, cipher, nil, k, vec, x.mode) { panic("cipher: unable to initialize EVP cipher ctx") } runtime.SetFinalizer(x, (*aesCBC).finalize) return x } func (c *aesCBC) finalize() { C._goboringcrypto_EVP_CIPHER_CTX_free(c.ctx) } func (c *aesCipher) NewCBCDecrypter(iv []byte) cipher.BlockMode { x := &aesCBC{key: c.key, mode: C.GO_AES_DECRYPT} copy(x.iv[:], iv) x.ctx = C._goboringcrypto_EVP_CIPHER_CTX_new() if x.ctx == nil { panic("cipher: unable to create EVP cipher ctx") } k := (*C.uchar)(unsafe.Pointer(&x.key[0])) vec := (*C.uchar)(unsafe.Pointer(&x.iv[0])) var cipher *C.EVP_CIPHER switch len(c.key) * 8 { case 128: cipher = C._goboringcrypto_EVP_aes_128_cbc() case 192: cipher = C._goboringcrypto_EVP_aes_192_cbc() case 256: cipher = C._goboringcrypto_EVP_aes_256_cbc() default: panic("crypto/boring: unsupported key length") } if C.int(1) != C._goboringcrypto_EVP_CipherInit_ex(x.ctx, cipher, nil, k, vec, x.mode) { panic("cipher: unable to initialize EVP cipher ctx") } if C.int(1) != C._goboringcrypto_EVP_CIPHER_CTX_set_padding(x.ctx, 0) { panic("cipher: unable to set padding") } runtime.SetFinalizer(x, (*aesCBC).finalize) return x } type aesCTR struct { key []byte iv [aesBlockSize]byte ctx *C.EVP_CIPHER_CTX num C.uint ecount_buf [16]C.uint8_t } func (x *aesCTR) XORKeyStream(dst, src []byte) { if inexactOverlap(dst, src) { panic("crypto/cipher: invalid buffer overlap") } if len(dst) < len(src) { panic("crypto/cipher: output smaller than input") } if len(src) == 0 { return } C._goboringcrypto_EVP_AES_ctr128_enc( x.ctx, (*C.uint8_t)(unsafe.Pointer(&src[0])), (*C.uint8_t)(unsafe.Pointer(&dst[0])), C.size_t(len(src))) runtime.KeepAlive(x) } func (c *aesCipher) NewCTR(iv []byte) cipher.Stream { x := &aesCTR{key: c.key} copy(x.iv[:], iv) x.ctx = C._goboringcrypto_EVP_CIPHER_CTX_new() if x.ctx == nil { panic("cipher: unable to create EVP cipher ctx") } k := (*C.uchar)(unsafe.Pointer(&x.key[0])) vec := (*C.uchar)(unsafe.Pointer(&x.iv[0])) switch len(c.key) * 8 { case 128: if C.int(1) != C._goboringcrypto_EVP_EncryptInit_ex(x.ctx, C._goboringcrypto_EVP_aes_128_ctr(), nil, k, vec) { panic("cipher: unable to initialize EVP cipher ctx") } case 192: if C.int(1) != C._goboringcrypto_EVP_EncryptInit_ex(x.ctx, C._goboringcrypto_EVP_aes_192_ctr(), nil, k, vec) { panic("cipher: unable to initialize EVP cipher ctx") } case 256: if C.int(1) != C._goboringcrypto_EVP_EncryptInit_ex(x.ctx, C._goboringcrypto_EVP_aes_256_ctr(), nil, k, vec) { panic("cipher: unable to initialize EVP cipher ctx") } } runtime.SetFinalizer(x, (*aesCTR).finalize) return x } func (c *aesCTR) finalize() { C._goboringcrypto_EVP_CIPHER_CTX_free(c.ctx) } type aesGCM struct { key []byte tls bool } 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, tagSize int) (cipher.AEAD, error) { if nonceSize != gcmStandardNonceSize { return nil, errors.New("crypto/aes: GCM nonce size can't be non-standard") } if tagSize != gcmTagSize { return nil, errors.New("crypto/aes: GCM tag size can't be non-standard") } return c.newGCM(false) } func (c *aesCipher) NewGCMTLS() (cipher.AEAD, error) { return c.newGCM(true) } func (c *aesCipher) newGCM(tls bool) (cipher.AEAD, error) { keyLen := len(c.key) * 8 if keyLen != 128 && keyLen != 256 { // Return error for GCM with non-standard key size. return nil, fail("GCM invoked with non-standard key size") } g := &aesGCM{key: c.key, tls: tls} if g.NonceSize() != gcmStandardNonceSize { panic("boringcrypto: internal confusion about nonce size") } if g.Overhead() != gcmTagSize { panic("boringcrypto: internal confusion about tag size") } return g, nil } func (g *aesGCM) NonceSize() int { return gcmStandardNonceSize } func (g *aesGCM) Overhead() int { return gcmTagSize } // 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] // Check delayed until now to make sure len(dst) is accurate. if inexactOverlap(dst[n:], plaintext) { panic("cipher: invalid buffer overlap") } var ciphertextLen C.size_t if ok := C._goboringcrypto_EVP_CIPHER_CTX_seal( (*C.uint8_t)(unsafe.Pointer(&dst[n])), base(nonce), base(additionalData), C.size_t(len(additionalData)), base(plaintext), C.size_t(len(plaintext)), &ciphertextLen, base(g.key), C.int(len(g.key)*8)); ok != 1 { panic("boringcrypto: EVP_CIPHER_CTX_seal fail") } runtime.KeepAlive(g) if ciphertextLen != C.size_t(len(plaintext)+gcmTagSize) { panic("boringcrypto: [seal] internal confusion about GCM tag size") } return dst[:n+int(ciphertextLen)] } 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] // Check delayed until now to make sure len(dst) is accurate. if inexactOverlap(dst[n:], ciphertext) { panic("cipher: invalid buffer overlap") } tag := ciphertext[len(ciphertext)-gcmTagSize:] var outLen C.size_t ok := C._goboringcrypto_EVP_CIPHER_CTX_open( base(ciphertext), C.int(len(ciphertext)-gcmTagSize), base(additionalData), C.int(len(additionalData)), base(tag), base(g.key), C.int(len(g.key)*8), base(nonce), C.int(len(nonce)), base(dst[n:]), &outLen) runtime.KeepAlive(g) if ok == 0 { // Zero output buffer on error. for i := range dst { dst[i] = 0 } return nil, errOpen } if outLen != C.size_t(len(ciphertext)-gcmTagSize) { panic("boringcrypto: [open] internal confusion about GCM tag size") } return dst[:n+int(outLen)], nil } func anyOverlap(x, y []byte) bool { return len(x) > 0 && len(y) > 0 && uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) && uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1])) } func inexactOverlap(x, y []byte) bool { if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { return false } return anyOverlap(x, y) }