summaryrefslogtreecommitdiff
path: root/libgo/go/crypto/cipher/gcm.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/crypto/cipher/gcm.go')
-rw-r--r--libgo/go/crypto/cipher/gcm.go39
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