diff options
Diffstat (limited to 'libgo/go/crypto/cipher/gcm.go')
-rw-r--r-- | libgo/go/crypto/cipher/gcm.go | 39 |
1 files changed, 32 insertions, 7 deletions
diff --git a/libgo/go/crypto/cipher/gcm.go b/libgo/go/crypto/cipher/gcm.go index bbdf9f5d3df..3868d7123a1 100644 --- a/libgo/go/crypto/cipher/gcm.go +++ b/libgo/go/crypto/cipher/gcm.go @@ -10,14 +10,15 @@ import ( ) // AEAD is a cipher mode providing authenticated encryption with associated -// data. +// data. For a description of the methodology, see +// https://en.wikipedia.org/wiki/Authenticated_encryption type AEAD interface { // NonceSize returns the size of the nonce that must be passed to Seal // and Open. NonceSize() int // Overhead returns the maximum difference between the lengths of a - // plaintext and ciphertext. + // plaintext and its ciphertext. Overhead() int // Seal encrypts and authenticates plaintext, authenticates the @@ -25,8 +26,9 @@ type AEAD interface { // slice. The nonce must be NonceSize() bytes long and unique for all // time, for a given key. // - // The plaintext and dst may alias exactly or not at all. - Seal(dst, nonce, plaintext, data []byte) []byte + // The plaintext and dst may alias exactly or not at all. To reuse + // plaintext's storage for the encrypted output, use plaintext[:0] as dst. + Seal(dst, nonce, plaintext, additionalData []byte) []byte // Open decrypts and authenticates ciphertext, authenticates the // additional data and, if successful, appends the resulting plaintext @@ -34,8 +36,19 @@ type AEAD interface { // bytes long and both it and the additional data must match the // value passed to Seal. // - // The ciphertext and dst may alias exactly or not at all. - Open(dst, nonce, ciphertext, data []byte) ([]byte, error) + // The ciphertext and dst may alias exactly or not at all. To reuse + // ciphertext's storage for the decrypted output, use ciphertext[:0] as dst. + // + // Even if the function fails, the contents of dst, up to its capacity, + // may be overwritten. + Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) +} + +// gcmAble is an interface implemented by ciphers that have a specific optimized +// implementation of GCM, like crypto/aes. NewGCM will check for this interface +// and return the specific AEAD if found. +type gcmAble interface { + NewGCM(int) (AEAD, error) } // gcmFieldElement represents a value in GF(2¹²⁸). In order to reflect the GCM @@ -72,6 +85,10 @@ func NewGCM(cipher Block) (AEAD, error) { // cryptosystem that uses non-standard nonce lengths. All other users should use // NewGCM, which is faster and more resistant to misuse. func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) { + if cipher, ok := cipher.(gcmAble); ok { + return cipher.NewGCM(size) + } + if cipher.BlockSize() != gcmBlockSize { return nil, errors.New("cipher: NewGCM requires 128-bit block cipher") } @@ -154,11 +171,19 @@ func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { var expectedTag [gcmTagSize]byte g.auth(expectedTag[:], ciphertext, data, &tagMask) + ret, out := sliceForAppend(dst, len(ciphertext)) + if subtle.ConstantTimeCompare(expectedTag[:], tag) != 1 { + // The AESNI code decrypts and authenticates concurrently, and + // so overwrites dst in the event of a tag mismatch. That + // behaviour is mimicked here in order to be consistent across + // platforms. + for i := range out { + out[i] = 0 + } return nil, errOpen } - ret, out := sliceForAppend(dst, len(ciphertext)) g.counterCrypt(out, ciphertext, &counter) return ret, nil |