diff --git a/src/crypto/aes/aes_gcm.go b/src/crypto/aes/aes_gcm.go index c1cacdb7524d13..13ae2fcb82032b 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 739e1febc310f2..28a6b1d5461570 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 c5a8e91d009b79..bb93fbb36e289a 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 4b3b877cd72b41..b12d9b46a2b760 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 c8027eec8b4291..a03547841f2682 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 110f61f57c0d10..b788ea7d475fa9 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 82f6f8f335c42a..65b6b2fc1b593c 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 8078aa68026c37..8fa85a3ae8fe79 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 ca06ae52ac0bd0..d154ddbaa0834a 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 0367d5971a6b80..0d07192e291aa1 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 9b4eebf5b45416..80c9bc24ea01f7 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 75f46cfe512a97..cba028d2a4453c 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 28f8b2093e74e5..6321e9e82d3d6a 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 7b35f8995c8e71..fc477248658c8d 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 46af5b0f022c88..9e6779c216b5f8 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 00000000000000..812ce3c65522bd --- /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 00000000000000..844f901d18e631 --- /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 00000000000000..f1e723848124fd --- /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 cf08ba7f8c42ec..c445bb078f290d 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 7e5f8b2fa40296..fc79e7ffc78346 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 663d5246f89c38..508ed8ac301e08 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"},