]> Cypherpunks repositories - gostls13.git/commitdiff
crypto: panic on illegal input and output overlap
authorFilippo Valsorda <filippo@golang.org>
Thu, 26 Apr 2018 21:35:01 +0000 (17:35 -0400)
committerFilippo Valsorda <filippo@golang.org>
Tue, 19 Jun 2018 21:06:50 +0000 (21:06 +0000)
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 <filippo@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
21 files changed:
src/crypto/aes/aes_gcm.go
src/crypto/aes/cbc_s390x.go
src/crypto/aes/cipher.go
src/crypto/aes/cipher_amd64.go
src/crypto/aes/cipher_arm64.go
src/crypto/aes/cipher_ppc64le.go
src/crypto/aes/cipher_s390x.go
src/crypto/aes/ctr_s390x.go
src/crypto/aes/gcm_s390x.go
src/crypto/cipher/cbc.go
src/crypto/cipher/cfb.go
src/crypto/cipher/ctr.go
src/crypto/cipher/gcm.go
src/crypto/cipher/ofb.go
src/crypto/des/cipher.go
src/crypto/internal/subtle/aliasing.go [new file with mode: 0644]
src/crypto/internal/subtle/aliasing_appengine.go [new file with mode: 0644]
src/crypto/internal/subtle/aliasing_test.go [new file with mode: 0644]
src/crypto/rc4/rc4.go
src/crypto/rc4/rc4_asm.go
src/go/build/deps_test.go

index c1cacdb7524d132bc47da20fcb43d942f8174975..13ae2fcb82032b73a356a61cde04c119c2320900 100644 (file)
@@ -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)
        }
index 739e1febc310f2d3232c6187e2dd3c4e17a3ec56..28a6b1d546157052bb2fcc451d6f5065ad0d6e95 100644 (file)
@@ -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))
        }
index c5a8e91d009b790da6d790edc04e26e175dcb736..bb93fbb36e289abfff7bf9b6341acf7769e719d3 100644 (file)
@@ -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)
 }
index 4b3b877cd72b41f585f76448a562f2f9720dd725..b12d9b46a2b7604ea4b126f6e91d40250bfc7eec 100644 (file)
@@ -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])
 }
 
index c8027eec8b42912833a7cdd478183192ca7fa8fa..a03547841f26822cc31b8d2586451b901f2ea3f6 100644 (file)
@@ -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])
 }
 
index 110f61f57c0d1040d22c2730529f4581b249e776..b788ea7d475fa9d4165a927f3271146c2ef7bc77 100644 (file)
@@ -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])
 }
 
index 82f6f8f335c42ab6cb65365bfbbd02ea738d8c2f..65b6b2fc1b593c80ba26c53d68e7ff4c54f48064 100644 (file)
@@ -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)
 }
index 8078aa68026c3777b2dd7bed011f62477411ea90..8fa85a3ae8fe7909c120a0d38e83c791ca37b282 100644 (file)
@@ -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 {
index ca06ae52ac0bd0fa087d7a6ef74de4eeaea23ffc..d154ddbaa0834afd7cd5a289de2a9ba27658c50b 100644 (file)
@@ -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)
index 0367d5971a6b803404de46b1e7837c439ae2509a..0d07192e291aa11fae49ebf86d10ba2054387b94 100644 (file)
@@ -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
        }
index 9b4eebf5b454164c794e6e166f1e2769a1c3adbd..80c9bc24ea01f71293bab3055d2a38f04e7c0a2f 100644 (file)
@@ -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)
index 75f46cfe512a97502a887f80c25f2a3ea0876526..cba028d2a4453c9cfd41feafa44b0706e1749c12 100644 (file)
@@ -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()
index 28f8b2093e74e59493f8a677fd53ec0f1a8d1f11..6321e9e82d3d6a6e7f2b51544d577cc4d54221a3 100644 (file)
@@ -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
index 7b35f8995c8e71c4b1eabd8549d2483a4d37e44a..fc477248658c8d83c9b360faeae2ba3830d55c32 100644 (file)
@@ -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()
index 46af5b0f022c8816781d4ab9c582f28f4cc36667..9e6779c216b5f85ddf2e5e4c9ee2cf198191b70d 100644 (file)
@@ -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 (file)
index 0000000..812ce3c
--- /dev/null
@@ -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 (file)
index 0000000..844f901
--- /dev/null
@@ -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 (file)
index 0000000..f1e7238
--- /dev/null
@@ -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)
+       }
+}
index cf08ba7f8c42ecdb4f3e9aff343e7688ff6ab9d6..c445bb078f290d2174182a61a3da28eaed9dbf87 100644 (file)
@@ -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
index 7e5f8b2fa40296fac1bb002ea3b39ecbd992f9e2..fc79e7ffc78346e459c93a0bf37ac4e7bae68b9b 100644 (file)
@@ -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)
 }
index 663d5246f89c38c87a05285089ad5ec30a08592e..508ed8ac301e085b77c6f8905cc8b90ecec09169 100644 (file)
@@ -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"},