From 75d15a2082b9a9fcf30344062a6bfb8f4f51d79e Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Thu, 26 Apr 2018 17:35:01 -0400 Subject: [PATCH] crypto: panic on illegal input and output overlap Normalized all panic checks and added inexact aliasing panics across Stream, Block, BlockMode and AEAD implementations. Also, tweaked the aliasing docs of cipher.AEAD, as they did not account for the append nature of the API. Fixes #21624 Change-Id: I075c4415f59b3c06e3099bd9f76de6d12af086bf Reviewed-on: https://go-review.googlesource.com/109697 Run-TryBot: Filippo Valsorda TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/crypto/aes/aes_gcm.go | 15 ++- src/crypto/aes/cbc_s390x.go | 4 + src/crypto/aes/cipher.go | 7 + src/crypto/aes/cipher_amd64.go | 7 + src/crypto/aes/cipher_arm64.go | 7 + src/crypto/aes/cipher_ppc64le.go | 7 + src/crypto/aes/cipher_s390x.go | 7 + src/crypto/aes/ctr_s390x.go | 9 +- src/crypto/aes/gcm_s390x.go | 29 +++-- src/crypto/cipher/cbc.go | 8 ++ src/crypto/cipher/cfb.go | 8 ++ src/crypto/cipher/ctr.go | 8 ++ src/crypto/cipher/gcm.go | 23 ++-- src/crypto/cipher/ofb.go | 8 ++ src/crypto/des/cipher.go | 47 ++++++- src/crypto/internal/subtle/aliasing.go | 34 +++++ .../internal/subtle/aliasing_appengine.go | 37 ++++++ src/crypto/internal/subtle/aliasing_test.go | 50 ++++++++ src/crypto/rc4/rc4.go | 8 +- src/crypto/rc4/rc4_asm.go | 10 +- src/go/build/deps_test.go | 120 +++++++++--------- 21 files changed, 366 insertions(+), 87 deletions(-) create mode 100644 src/crypto/internal/subtle/aliasing.go create mode 100644 src/crypto/internal/subtle/aliasing_appengine.go create mode 100644 src/crypto/internal/subtle/aliasing_test.go diff --git a/src/crypto/aes/aes_gcm.go b/src/crypto/aes/aes_gcm.go index c1cacdb752..13ae2fcb82 100644 --- a/src/crypto/aes/aes_gcm.go +++ b/src/crypto/aes/aes_gcm.go @@ -8,6 +8,7 @@ package aes import ( "crypto/cipher" + subtleoverlap "crypto/internal/subtle" "crypto/subtle" "errors" ) @@ -99,10 +100,10 @@ func sliceForAppend(in []byte, n int) (head, tail []byte) { // details. func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { if len(nonce) != g.nonceSize { - panic("cipher: incorrect nonce length given to GCM") + panic("crypto/cipher: incorrect nonce length given to GCM") } if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize { - panic("cipher: message too large for GCM") + panic("crypto/cipher: message too large for GCM") } var counter, tagMask [gcmBlockSize]byte @@ -123,6 +124,9 @@ func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { gcmAesData(&g.productTable, data, &tagOut) ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize) + if subtleoverlap.InexactOverlap(out[:len(plaintext)], plaintext) { + panic("crypto/cipher: invalid buffer overlap") + } if len(plaintext) > 0 { gcmAesEnc(&g.productTable, out, plaintext, &counter, &tagOut, g.ks) } @@ -136,12 +140,12 @@ func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { // for details. func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { if len(nonce) != g.nonceSize { - panic("cipher: incorrect nonce length given to GCM") + panic("crypto/cipher: incorrect nonce length given to GCM") } // Sanity check to prevent the authentication from always succeeding if an implementation // leaves tagSize uninitialized, for example. if g.tagSize < gcmMinimumTagSize { - panic("cipher: incorrect GCM tag size") + panic("crypto/cipher: incorrect GCM tag size") } if len(ciphertext) < g.tagSize { @@ -173,6 +177,9 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { gcmAesData(&g.productTable, data, &expectedTag) ret, out := sliceForAppend(dst, len(ciphertext)) + if subtleoverlap.InexactOverlap(out, ciphertext) { + panic("crypto/cipher: invalid buffer overlap") + } if len(ciphertext) > 0 { gcmAesDec(&g.productTable, out, ciphertext, &counter, &expectedTag, g.ks) } diff --git a/src/crypto/aes/cbc_s390x.go b/src/crypto/aes/cbc_s390x.go index 739e1febc3..28a6b1d546 100644 --- a/src/crypto/aes/cbc_s390x.go +++ b/src/crypto/aes/cbc_s390x.go @@ -6,6 +6,7 @@ package aes import ( "crypto/cipher" + "crypto/internal/subtle" ) // Assert that aesCipherAsm implements the cbcEncAble and cbcDecAble interfaces. @@ -48,6 +49,9 @@ func (x *cbc) CryptBlocks(dst, src []byte) { if len(dst) < len(src) { panic("crypto/cipher: output smaller than input") } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("crypto/cipher: invalid buffer overlap") + } if len(src) > 0 { cryptBlocksChain(x.c, &x.iv[0], &x.b.key[0], &dst[0], &src[0], len(src)) } diff --git a/src/crypto/aes/cipher.go b/src/crypto/aes/cipher.go index c5a8e91d00..bb93fbb36e 100644 --- a/src/crypto/aes/cipher.go +++ b/src/crypto/aes/cipher.go @@ -6,6 +6,7 @@ package aes import ( "crypto/cipher" + "crypto/internal/subtle" "strconv" ) @@ -57,6 +58,9 @@ func (c *aesCipher) Encrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } encryptBlockGo(c.enc, dst, src) } @@ -67,5 +71,8 @@ func (c *aesCipher) Decrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } decryptBlockGo(c.dec, dst, src) } diff --git a/src/crypto/aes/cipher_amd64.go b/src/crypto/aes/cipher_amd64.go index 4b3b877cd7..b12d9b46a2 100644 --- a/src/crypto/aes/cipher_amd64.go +++ b/src/crypto/aes/cipher_amd64.go @@ -6,6 +6,7 @@ package aes import ( "crypto/cipher" + "crypto/internal/subtle" "internal/cpu" ) @@ -52,6 +53,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } encryptBlockAsm(len(c.enc)/4-1, &c.enc[0], &dst[0], &src[0]) } @@ -62,6 +66,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } decryptBlockAsm(len(c.dec)/4-1, &c.dec[0], &dst[0], &src[0]) } diff --git a/src/crypto/aes/cipher_arm64.go b/src/crypto/aes/cipher_arm64.go index c8027eec8b..a03547841f 100644 --- a/src/crypto/aes/cipher_arm64.go +++ b/src/crypto/aes/cipher_arm64.go @@ -6,6 +6,7 @@ package aes import ( "crypto/cipher" + "crypto/internal/subtle" "internal/cpu" "math/bits" ) @@ -40,6 +41,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } encryptBlockAsm(len(c.enc)/4-1, &c.enc[0], &dst[0], &src[0]) } @@ -50,6 +54,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } decryptBlockAsm(len(c.dec)/4-1, &c.dec[0], &dst[0], &src[0]) } diff --git a/src/crypto/aes/cipher_ppc64le.go b/src/crypto/aes/cipher_ppc64le.go index 110f61f57c..b788ea7d47 100644 --- a/src/crypto/aes/cipher_ppc64le.go +++ b/src/crypto/aes/cipher_ppc64le.go @@ -6,6 +6,7 @@ package aes import ( "crypto/cipher" + "crypto/internal/subtle" ) // defined in asm_ppc64le.s @@ -54,6 +55,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } encryptBlockAsm(&dst[0], &src[0], &c.enc[0]) } @@ -64,6 +68,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } decryptBlockAsm(&dst[0], &src[0], &c.dec[0]) } diff --git a/src/crypto/aes/cipher_s390x.go b/src/crypto/aes/cipher_s390x.go index 82f6f8f335..65b6b2fc1b 100644 --- a/src/crypto/aes/cipher_s390x.go +++ b/src/crypto/aes/cipher_s390x.go @@ -6,6 +6,7 @@ package aes import ( "crypto/cipher" + "crypto/internal/subtle" "internal/cpu" ) @@ -67,6 +68,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } cryptBlocks(c.function, &c.key[0], &dst[0], &src[0], BlockSize) } @@ -77,6 +81,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } // The decrypt function code is equal to the function code + 128. cryptBlocks(c.function+128, &c.key[0], &dst[0], &src[0], BlockSize) } diff --git a/src/crypto/aes/ctr_s390x.go b/src/crypto/aes/ctr_s390x.go index 8078aa6802..8fa85a3ae8 100644 --- a/src/crypto/aes/ctr_s390x.go +++ b/src/crypto/aes/ctr_s390x.go @@ -6,6 +6,7 @@ package aes import ( "crypto/cipher" + "crypto/internal/subtle" "unsafe" ) @@ -64,9 +65,11 @@ func (c *aesctr) refill() { } func (c *aesctr) XORKeyStream(dst, src []byte) { - if len(src) > 0 { - // Assert len(dst) >= len(src) - _ = dst[len(src)-1] + if len(dst) < len(src) { + panic("crypto/cipher: output smaller than input") + } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("crypto/cipher: invalid buffer overlap") } for len(src) > 0 { if len(c.buffer) == 0 { diff --git a/src/crypto/aes/gcm_s390x.go b/src/crypto/aes/gcm_s390x.go index ca06ae52ac..d154ddbaa0 100644 --- a/src/crypto/aes/gcm_s390x.go +++ b/src/crypto/aes/gcm_s390x.go @@ -6,6 +6,7 @@ package aes import ( "crypto/cipher" + subtleoverlap "crypto/internal/subtle" "crypto/subtle" "errors" "internal/cpu" @@ -220,13 +221,16 @@ func (g *gcmAsm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSi // details. func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { if len(nonce) != g.nonceSize { - panic("cipher: incorrect nonce length given to GCM") + panic("crypto/cipher: incorrect nonce length given to GCM") } if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize { - panic("cipher: message too large for GCM") + panic("crypto/cipher: message too large for GCM") } ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize) + if subtleoverlap.InexactOverlap(out[:len(plaintext)], plaintext) { + panic("crypto/cipher: invalid buffer overlap") + } counter := g.deriveCounter(nonce) @@ -246,12 +250,12 @@ func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { // for details. func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { if len(nonce) != g.nonceSize { - panic("cipher: incorrect nonce length given to GCM") + panic("crypto/cipher: incorrect nonce length given to GCM") } // Sanity check to prevent the authentication from always succeeding if an implementation // leaves tagSize uninitialized, for example. if g.tagSize < gcmMinimumTagSize { - panic("cipher: incorrect GCM tag size") + panic("crypto/cipher: incorrect GCM tag size") } if len(ciphertext) < g.tagSize { return nil, errOpen @@ -273,6 +277,9 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { g.auth(expectedTag[:], ciphertext, data, &tagMask) ret, out := sliceForAppend(dst, len(ciphertext)) + if subtleoverlap.InexactOverlap(out, ciphertext) { + panic("crypto/cipher: invalid buffer overlap") + } if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 { // The AESNI code decrypts and authenticates concurrently, and @@ -314,13 +321,16 @@ func kmaGCM(fn code, key, dst, src, aad []byte, tag *[16]byte, cnt *gcmCount) // details. func (g *gcmKMA) Seal(dst, nonce, plaintext, data []byte) []byte { if len(nonce) != g.nonceSize { - panic("cipher: incorrect nonce length given to GCM") + panic("crypto/cipher: incorrect nonce length given to GCM") } if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize { - panic("cipher: message too large for GCM") + panic("crypto/cipher: message too large for GCM") } ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize) + if subtleoverlap.InexactOverlap(out[:len(plaintext)], plaintext) { + panic("crypto/cipher: invalid buffer overlap") + } counter := g.deriveCounter(nonce) fc := g.block.function | kmaLAAD | kmaLPC @@ -336,7 +346,7 @@ func (g *gcmKMA) Seal(dst, nonce, plaintext, data []byte) []byte { // for details. func (g *gcmKMA) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { if len(nonce) != g.nonceSize { - panic("cipher: incorrect nonce length given to GCM") + panic("crypto/cipher: incorrect nonce length given to GCM") } if len(ciphertext) < g.tagSize { return nil, errOpen @@ -348,9 +358,12 @@ func (g *gcmKMA) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { tag := ciphertext[len(ciphertext)-g.tagSize:] ciphertext = ciphertext[:len(ciphertext)-g.tagSize] ret, out := sliceForAppend(dst, len(ciphertext)) + if subtleoverlap.InexactOverlap(out, ciphertext) { + panic("crypto/cipher: invalid buffer overlap") + } if g.tagSize < gcmMinimumTagSize { - panic("cipher: incorrect GCM tag size") + panic("crypto/cipher: incorrect GCM tag size") } counter := g.deriveCounter(nonce) diff --git a/src/crypto/cipher/cbc.go b/src/crypto/cipher/cbc.go index 0367d5971a..0d07192e29 100644 --- a/src/crypto/cipher/cbc.go +++ b/src/crypto/cipher/cbc.go @@ -11,6 +11,8 @@ package cipher +import "crypto/internal/subtle" + type cbc struct { b Block blockSize int @@ -59,6 +61,9 @@ func (x *cbcEncrypter) CryptBlocks(dst, src []byte) { if len(dst) < len(src) { panic("crypto/cipher: output smaller than input") } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("crypto/cipher: invalid buffer overlap") + } iv := x.iv @@ -116,6 +121,9 @@ func (x *cbcDecrypter) CryptBlocks(dst, src []byte) { if len(dst) < len(src) { panic("crypto/cipher: output smaller than input") } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("crypto/cipher: invalid buffer overlap") + } if len(src) == 0 { return } diff --git a/src/crypto/cipher/cfb.go b/src/crypto/cipher/cfb.go index 9b4eebf5b4..80c9bc24ea 100644 --- a/src/crypto/cipher/cfb.go +++ b/src/crypto/cipher/cfb.go @@ -6,6 +6,8 @@ package cipher +import "crypto/internal/subtle" + type cfb struct { b Block next []byte @@ -16,6 +18,12 @@ type cfb struct { } func (x *cfb) XORKeyStream(dst, src []byte) { + if len(dst) < len(src) { + panic("crypto/cipher: output smaller than input") + } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("crypto/cipher: invalid buffer overlap") + } for len(src) > 0 { if x.outUsed == len(x.out) { x.b.Encrypt(x.out, x.next) diff --git a/src/crypto/cipher/ctr.go b/src/crypto/cipher/ctr.go index 75f46cfe51..cba028d2a4 100644 --- a/src/crypto/cipher/ctr.go +++ b/src/crypto/cipher/ctr.go @@ -12,6 +12,8 @@ package cipher +import "crypto/internal/subtle" + type ctr struct { b Block ctr []byte @@ -71,6 +73,12 @@ func (x *ctr) refill() { } func (x *ctr) XORKeyStream(dst, src []byte) { + if len(dst) < len(src) { + panic("crypto/cipher: output smaller than input") + } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("crypto/cipher: invalid buffer overlap") + } for len(src) > 0 { if x.outUsed >= len(x.out)-x.b.BlockSize() { x.refill() diff --git a/src/crypto/cipher/gcm.go b/src/crypto/cipher/gcm.go index 28f8b2093e..6321e9e82d 100644 --- a/src/crypto/cipher/gcm.go +++ b/src/crypto/cipher/gcm.go @@ -5,6 +5,7 @@ package cipher import ( + subtleoverlap "crypto/internal/subtle" "crypto/subtle" "errors" ) @@ -26,8 +27,8 @@ type AEAD interface { // slice. The nonce must be NonceSize() bytes long and unique for all // time, for a given key. // - // The plaintext and dst must overlap exactly or not at all. To reuse - // plaintext's storage for the encrypted output, use plaintext[:0] as dst. + // To reuse plaintext's storage for the encrypted output, use plaintext[:0] + // as dst. Otherwise, the remaining capacity of dst must not overlap plaintext. Seal(dst, nonce, plaintext, additionalData []byte) []byte // Open decrypts and authenticates ciphertext, authenticates the @@ -36,8 +37,8 @@ type AEAD interface { // bytes long and both it and the additional data must match the // value passed to Seal. // - // The ciphertext and dst must overlap exactly or not at all. To reuse - // ciphertext's storage for the decrypted output, use ciphertext[:0] as dst. + // To reuse ciphertext's storage for the decrypted output, use ciphertext[:0] + // as dst. Otherwise, the remaining capacity of dst must not overlap plaintext. // // Even if the function fails, the contents of dst, up to its capacity, // may be overwritten. @@ -159,13 +160,16 @@ func (g *gcm) Overhead() int { func (g *gcm) Seal(dst, nonce, plaintext, data []byte) []byte { if len(nonce) != g.nonceSize { - panic("cipher: incorrect nonce length given to GCM") + panic("crypto/cipher: incorrect nonce length given to GCM") } if uint64(len(plaintext)) > ((1<<32)-2)*uint64(g.cipher.BlockSize()) { - panic("cipher: message too large for GCM") + panic("crypto/cipher: message too large for GCM") } ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize) + if subtleoverlap.InexactOverlap(out, plaintext) { + panic("crypto/cipher: invalid buffer overlap") + } var counter, tagMask [gcmBlockSize]byte g.deriveCounter(&counter, nonce) @@ -186,12 +190,12 @@ var errOpen = errors.New("cipher: message authentication failed") func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { if len(nonce) != g.nonceSize { - panic("cipher: incorrect nonce length given to GCM") + panic("crypto/cipher: incorrect nonce length given to GCM") } // Sanity check to prevent the authentication from always succeeding if an implementation // leaves tagSize uninitialized, for example. if g.tagSize < gcmMinimumTagSize { - panic("cipher: incorrect GCM tag size") + panic("crypto/cipher: incorrect GCM tag size") } if len(ciphertext) < g.tagSize { @@ -214,6 +218,9 @@ func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { g.auth(expectedTag[:], ciphertext, data, &tagMask) ret, out := sliceForAppend(dst, len(ciphertext)) + if subtleoverlap.InexactOverlap(out, ciphertext) { + panic("crypto/cipher: invalid buffer overlap") + } if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 { // The AESNI code decrypts and authenticates concurrently, and diff --git a/src/crypto/cipher/ofb.go b/src/crypto/cipher/ofb.go index 7b35f8995c..fc47724865 100644 --- a/src/crypto/cipher/ofb.go +++ b/src/crypto/cipher/ofb.go @@ -6,6 +6,8 @@ package cipher +import "crypto/internal/subtle" + type ofb struct { b Block cipher []byte @@ -54,6 +56,12 @@ func (x *ofb) refill() { } func (x *ofb) XORKeyStream(dst, src []byte) { + if len(dst) < len(src) { + panic("crypto/cipher: output smaller than input") + } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("crypto/cipher: invalid buffer overlap") + } for len(src) > 0 { if x.outUsed >= len(x.out)-x.b.BlockSize() { x.refill() diff --git a/src/crypto/des/cipher.go b/src/crypto/des/cipher.go index 46af5b0f02..9e6779c216 100644 --- a/src/crypto/des/cipher.go +++ b/src/crypto/des/cipher.go @@ -6,6 +6,7 @@ package des import ( "crypto/cipher" + "crypto/internal/subtle" "encoding/binary" "strconv" ) @@ -37,9 +38,31 @@ func NewCipher(key []byte) (cipher.Block, error) { func (c *desCipher) BlockSize() int { return BlockSize } -func (c *desCipher) Encrypt(dst, src []byte) { encryptBlock(c.subkeys[:], dst, src) } +func (c *desCipher) Encrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/des: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/des: output not full block") + } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/des: invalid buffer overlap") + } + encryptBlock(c.subkeys[:], dst, src) +} -func (c *desCipher) Decrypt(dst, src []byte) { decryptBlock(c.subkeys[:], dst, src) } +func (c *desCipher) Decrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/des: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/des: output not full block") + } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/des: invalid buffer overlap") + } + decryptBlock(c.subkeys[:], dst, src) +} // A tripleDESCipher is an instance of TripleDES encryption. type tripleDESCipher struct { @@ -62,6 +85,16 @@ func NewTripleDESCipher(key []byte) (cipher.Block, error) { func (c *tripleDESCipher) BlockSize() int { return BlockSize } func (c *tripleDESCipher) Encrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/des: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/des: output not full block") + } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/des: invalid buffer overlap") + } + b := binary.BigEndian.Uint64(src) b = permuteInitialBlock(b) left, right := uint32(b>>32), uint32(b) @@ -87,6 +120,16 @@ func (c *tripleDESCipher) Encrypt(dst, src []byte) { } func (c *tripleDESCipher) Decrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/des: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/des: output not full block") + } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/des: invalid buffer overlap") + } + b := binary.BigEndian.Uint64(src) b = permuteInitialBlock(b) left, right := uint32(b>>32), uint32(b) diff --git a/src/crypto/internal/subtle/aliasing.go b/src/crypto/internal/subtle/aliasing.go new file mode 100644 index 0000000000..812ce3c655 --- /dev/null +++ b/src/crypto/internal/subtle/aliasing.go @@ -0,0 +1,34 @@ +// Copyright 2018 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 !appengine + +// Package subtle implements functions that are often useful in cryptographic +// code but require careful thought to use correctly. +// +// This is a mirror of golang.org/x/crypto/internal/subtle. +package subtle // import "crypto/internal/subtle" + +import "unsafe" + +// AnyOverlap reports whether x and y share memory at any (not necessarily +// corresponding) index. The memory beyond the slice length is ignored. +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])) +} + +// InexactOverlap reports whether x and y share memory at any non-corresponding +// index. The memory beyond the slice length is ignored. Note that x and y can +// have different lengths and still not have any inexact overlap. +// +// InexactOverlap can be used to implement the requirements of the crypto/cipher +// AEAD, Block, BlockMode and Stream interfaces. +func InexactOverlap(x, y []byte) bool { + if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { + return false + } + return AnyOverlap(x, y) +} diff --git a/src/crypto/internal/subtle/aliasing_appengine.go b/src/crypto/internal/subtle/aliasing_appengine.go new file mode 100644 index 0000000000..844f901d18 --- /dev/null +++ b/src/crypto/internal/subtle/aliasing_appengine.go @@ -0,0 +1,37 @@ +// Copyright 2018 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 appengine + +// Package subtle implements functions that are often useful in cryptographic +// code but require careful thought to use correctly. +// +// This is a mirror of golang.org/x/crypto/internal/subtle. +package subtle // import "crypto/internal/subtle" + +// This is the Google App Engine standard variant based on reflect +// because the unsafe package and cgo are disallowed. + +import "reflect" + +// AnyOverlap reports whether x and y share memory at any (not necessarily +// corresponding) index. The memory beyond the slice length is ignored. +func AnyOverlap(x, y []byte) bool { + return len(x) > 0 && len(y) > 0 && + reflect.ValueOf(&x[0]).Pointer() <= reflect.ValueOf(&y[len(y)-1]).Pointer() && + reflect.ValueOf(&y[0]).Pointer() <= reflect.ValueOf(&x[len(x)-1]).Pointer() +} + +// InexactOverlap reports whether x and y share memory at any non-corresponding +// index. The memory beyond the slice length is ignored. Note that x and y can +// have different lengths and still not have any inexact overlap. +// +// InexactOverlap can be used to implement the requirements of the crypto/cipher +// AEAD, Block, BlockMode and Stream interfaces. +func InexactOverlap(x, y []byte) bool { + if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { + return false + } + return AnyOverlap(x, y) +} diff --git a/src/crypto/internal/subtle/aliasing_test.go b/src/crypto/internal/subtle/aliasing_test.go new file mode 100644 index 0000000000..f1e7238481 --- /dev/null +++ b/src/crypto/internal/subtle/aliasing_test.go @@ -0,0 +1,50 @@ +// Copyright 2018 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. + +package subtle_test + +import ( + "testing" + + "crypto/internal/subtle" +) + +var a, b [100]byte + +var aliasingTests = []struct { + x, y []byte + anyOverlap, inexactOverlap bool +}{ + {a[:], b[:], false, false}, + {a[:], b[:0], false, false}, + {a[:], b[:50], false, false}, + {a[40:50], a[50:60], false, false}, + {a[40:50], a[60:70], false, false}, + {a[:51], a[50:], true, true}, + {a[:], a[:], true, false}, + {a[:50], a[:60], true, false}, + {a[:], nil, false, false}, + {nil, nil, false, false}, + {a[:], a[:0], false, false}, + {a[:10], a[:10:20], true, false}, + {a[:10], a[5:10:20], true, true}, +} + +func testAliasing(t *testing.T, i int, x, y []byte, anyOverlap, inexactOverlap bool) { + any := subtle.AnyOverlap(x, y) + if any != anyOverlap { + t.Errorf("%d: wrong AnyOverlap result, expected %v, got %v", i, anyOverlap, any) + } + inexact := subtle.InexactOverlap(x, y) + if inexact != inexactOverlap { + t.Errorf("%d: wrong InexactOverlap result, expected %v, got %v", i, inexactOverlap, any) + } +} + +func TestAliasing(t *testing.T) { + for i, tt := range aliasingTests { + testAliasing(t, i, tt.x, tt.y, tt.anyOverlap, tt.inexactOverlap) + testAliasing(t, i, tt.y, tt.x, tt.anyOverlap, tt.inexactOverlap) + } +} diff --git a/src/crypto/rc4/rc4.go b/src/crypto/rc4/rc4.go index cf08ba7f8c..c445bb078f 100644 --- a/src/crypto/rc4/rc4.go +++ b/src/crypto/rc4/rc4.go @@ -9,7 +9,10 @@ // applications. package rc4 -import "strconv" +import ( + "crypto/internal/subtle" + "strconv" +) // A Cipher is an instance of RC4 using a particular key. type Cipher struct { @@ -60,6 +63,9 @@ func (c *Cipher) xorKeyStreamGeneric(dst, src []byte) { if len(src) == 0 { return } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("crypto/rc4: invalid buffer overlap") + } i, j := c.i, c.j _ = dst[len(src)-1] dst = dst[:len(src)] // eliminate bounds check from loop diff --git a/src/crypto/rc4/rc4_asm.go b/src/crypto/rc4/rc4_asm.go index 7e5f8b2fa4..fc79e7ffc7 100644 --- a/src/crypto/rc4/rc4_asm.go +++ b/src/crypto/rc4/rc4_asm.go @@ -6,6 +6,8 @@ package rc4 +import "crypto/internal/subtle" + func xorKeyStream(dst, src *byte, n int, state *[256]uint32, i, j *uint8) // XORKeyStream sets dst to the result of XORing src with the key stream. @@ -14,7 +16,11 @@ func (c *Cipher) XORKeyStream(dst, src []byte) { if len(src) == 0 { return } - // Assert len(dst) >= len(src) - _ = dst[len(src)-1] + if len(dst) < len(src) { + panic("crypto/cipher: output smaller than input") + } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("crypto/cipher: invalid buffer overlap") + } xorKeyStream(&dst[0], &src[0], len(src), &c.s, &c.i, &c.j) } diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 663d5246f8..508ed8ac30 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -99,27 +99,29 @@ var pkgDeps = map[string][]string{ // L3 adds reflection and some basic utility packages // and interface definitions, but nothing that makes // system calls. - "crypto": {"L2", "hash"}, // interfaces - "crypto/cipher": {"L2", "crypto/subtle"}, - "crypto/subtle": {}, - "encoding/base32": {"L2"}, - "encoding/base64": {"L2", "encoding/binary"}, - "encoding/binary": {"L2", "reflect"}, - "hash": {"L2"}, // interfaces - "hash/adler32": {"L2", "hash"}, - "hash/crc32": {"L2", "hash"}, - "hash/crc64": {"L2", "hash"}, - "hash/fnv": {"L2", "hash"}, - "image": {"L2", "image/color"}, // interfaces - "image/color": {"L2"}, // interfaces - "image/color/palette": {"L2", "image/color"}, - "reflect": {"L2"}, - "sort": {"reflect"}, + "crypto": {"L2", "hash"}, // interfaces + "crypto/cipher": {"L2", "crypto/subtle", "crypto/internal/subtle"}, + "crypto/internal/subtle": {"unsafe", "reflect"}, // reflect behind a appengine tag + "crypto/subtle": {}, + "encoding/base32": {"L2"}, + "encoding/base64": {"L2", "encoding/binary"}, + "encoding/binary": {"L2", "reflect"}, + "hash": {"L2"}, // interfaces + "hash/adler32": {"L2", "hash"}, + "hash/crc32": {"L2", "hash"}, + "hash/crc64": {"L2", "hash"}, + "hash/fnv": {"L2", "hash"}, + "image": {"L2", "image/color"}, // interfaces + "image/color": {"L2"}, // interfaces + "image/color/palette": {"L2", "image/color"}, + "reflect": {"L2"}, + "sort": {"reflect"}, "L3": { "L2", "crypto", "crypto/cipher", + "crypto/internal/subtle", "crypto/subtle", "encoding/base32", "encoding/base64", @@ -229,49 +231,49 @@ var pkgDeps = map[string][]string{ "go/types": {"L4", "GOPARSER", "container/heap", "go/constant"}, // One of a kind. - "archive/tar": {"L4", "OS", "syscall", "os/user"}, - "archive/zip": {"L4", "OS", "compress/flate"}, - "container/heap": {"sort"}, - "compress/bzip2": {"L4"}, - "compress/flate": {"L4"}, - "compress/gzip": {"L4", "compress/flate"}, - "compress/lzw": {"L4"}, - "compress/zlib": {"L4", "compress/flate"}, - "context": {"errors", "fmt", "reflect", "sync", "time"}, - "database/sql": {"L4", "container/list", "context", "database/sql/driver", "database/sql/internal"}, - "database/sql/driver": {"L4", "context", "time", "database/sql/internal"}, - "debug/dwarf": {"L4"}, - "debug/elf": {"L4", "OS", "debug/dwarf", "compress/zlib"}, - "debug/gosym": {"L4"}, - "debug/macho": {"L4", "OS", "debug/dwarf"}, - "debug/pe": {"L4", "OS", "debug/dwarf"}, - "debug/plan9obj": {"L4", "OS"}, - "encoding": {"L4"}, - "encoding/ascii85": {"L4"}, - "encoding/asn1": {"L4", "math/big"}, - "encoding/csv": {"L4"}, - "encoding/gob": {"L4", "OS", "encoding"}, - "encoding/hex": {"L4"}, - "encoding/json": {"L4", "encoding"}, - "encoding/pem": {"L4"}, - "encoding/xml": {"L4", "encoding"}, - "flag": {"L4", "OS"}, - "go/build": {"L4", "OS", "GOPARSER"}, - "html": {"L4"}, - "image/draw": {"L4", "image/internal/imageutil"}, - "image/gif": {"L4", "compress/lzw", "image/color/palette", "image/draw"}, - "image/internal/imageutil": {"L4"}, - "image/jpeg": {"L4", "image/internal/imageutil"}, - "image/png": {"L4", "compress/zlib"}, - "index/suffixarray": {"L4", "regexp"}, - "internal/singleflight": {"sync"}, - "internal/trace": {"L4", "OS"}, - "math/big": {"L4"}, - "mime": {"L4", "OS", "syscall", "internal/syscall/windows/registry"}, - "mime/quotedprintable": {"L4"}, - "net/internal/socktest": {"L4", "OS", "syscall", "internal/syscall/windows"}, - "net/url": {"L4"}, - "plugin": {"L0", "OS", "CGO"}, + "archive/tar": {"L4", "OS", "syscall", "os/user"}, + "archive/zip": {"L4", "OS", "compress/flate"}, + "container/heap": {"sort"}, + "compress/bzip2": {"L4"}, + "compress/flate": {"L4"}, + "compress/gzip": {"L4", "compress/flate"}, + "compress/lzw": {"L4"}, + "compress/zlib": {"L4", "compress/flate"}, + "context": {"errors", "fmt", "reflect", "sync", "time"}, + "database/sql": {"L4", "container/list", "context", "database/sql/driver", "database/sql/internal"}, + "database/sql/driver": {"L4", "context", "time", "database/sql/internal"}, + "debug/dwarf": {"L4"}, + "debug/elf": {"L4", "OS", "debug/dwarf", "compress/zlib"}, + "debug/gosym": {"L4"}, + "debug/macho": {"L4", "OS", "debug/dwarf"}, + "debug/pe": {"L4", "OS", "debug/dwarf"}, + "debug/plan9obj": {"L4", "OS"}, + "encoding": {"L4"}, + "encoding/ascii85": {"L4"}, + "encoding/asn1": {"L4", "math/big"}, + "encoding/csv": {"L4"}, + "encoding/gob": {"L4", "OS", "encoding"}, + "encoding/hex": {"L4"}, + "encoding/json": {"L4", "encoding"}, + "encoding/pem": {"L4"}, + "encoding/xml": {"L4", "encoding"}, + "flag": {"L4", "OS"}, + "go/build": {"L4", "OS", "GOPARSER"}, + "html": {"L4"}, + "image/draw": {"L4", "image/internal/imageutil"}, + "image/gif": {"L4", "compress/lzw", "image/color/palette", "image/draw"}, + "image/internal/imageutil": {"L4"}, + "image/jpeg": {"L4", "image/internal/imageutil"}, + "image/png": {"L4", "compress/zlib"}, + "index/suffixarray": {"L4", "regexp"}, + "internal/singleflight": {"sync"}, + "internal/trace": {"L4", "OS"}, + "math/big": {"L4"}, + "mime": {"L4", "OS", "syscall", "internal/syscall/windows/registry"}, + "mime/quotedprintable": {"L4"}, + "net/internal/socktest": {"L4", "OS", "syscall", "internal/syscall/windows"}, + "net/url": {"L4"}, + "plugin": {"L0", "OS", "CGO"}, "runtime/pprof/internal/profile": {"L4", "OS", "compress/gzip", "regexp"}, "testing/internal/testdeps": {"L4", "internal/testlog", "runtime/pprof", "regexp"}, "text/scanner": {"L4", "OS"}, -- 2.48.1