Commit 75d15a20 authored by Filippo Valsorda's avatar Filippo Valsorda

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 <filippo@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent c6e455bb
...@@ -8,6 +8,7 @@ package aes ...@@ -8,6 +8,7 @@ package aes
import ( import (
"crypto/cipher" "crypto/cipher"
subtleoverlap "crypto/internal/subtle"
"crypto/subtle" "crypto/subtle"
"errors" "errors"
) )
...@@ -99,10 +100,10 @@ func sliceForAppend(in []byte, n int) (head, tail []byte) { ...@@ -99,10 +100,10 @@ func sliceForAppend(in []byte, n int) (head, tail []byte) {
// details. // details.
func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
if len(nonce) != g.nonceSize { 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 { 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 var counter, tagMask [gcmBlockSize]byte
...@@ -123,6 +124,9 @@ func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { ...@@ -123,6 +124,9 @@ func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
gcmAesData(&g.productTable, data, &tagOut) gcmAesData(&g.productTable, data, &tagOut)
ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize) 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 { if len(plaintext) > 0 {
gcmAesEnc(&g.productTable, out, plaintext, &counter, &tagOut, g.ks) gcmAesEnc(&g.productTable, out, plaintext, &counter, &tagOut, g.ks)
} }
...@@ -136,12 +140,12 @@ func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { ...@@ -136,12 +140,12 @@ func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
// for details. // for details.
func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
if len(nonce) != g.nonceSize { 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 // Sanity check to prevent the authentication from always succeeding if an implementation
// leaves tagSize uninitialized, for example. // leaves tagSize uninitialized, for example.
if g.tagSize < gcmMinimumTagSize { if g.tagSize < gcmMinimumTagSize {
panic("cipher: incorrect GCM tag size") panic("crypto/cipher: incorrect GCM tag size")
} }
if len(ciphertext) < g.tagSize { if len(ciphertext) < g.tagSize {
...@@ -173,6 +177,9 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { ...@@ -173,6 +177,9 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
gcmAesData(&g.productTable, data, &expectedTag) gcmAesData(&g.productTable, data, &expectedTag)
ret, out := sliceForAppend(dst, len(ciphertext)) ret, out := sliceForAppend(dst, len(ciphertext))
if subtleoverlap.InexactOverlap(out, ciphertext) {
panic("crypto/cipher: invalid buffer overlap")
}
if len(ciphertext) > 0 { if len(ciphertext) > 0 {
gcmAesDec(&g.productTable, out, ciphertext, &counter, &expectedTag, g.ks) gcmAesDec(&g.productTable, out, ciphertext, &counter, &expectedTag, g.ks)
} }
......
...@@ -6,6 +6,7 @@ package aes ...@@ -6,6 +6,7 @@ package aes
import ( import (
"crypto/cipher" "crypto/cipher"
"crypto/internal/subtle"
) )
// Assert that aesCipherAsm implements the cbcEncAble and cbcDecAble interfaces. // Assert that aesCipherAsm implements the cbcEncAble and cbcDecAble interfaces.
...@@ -48,6 +49,9 @@ func (x *cbc) CryptBlocks(dst, src []byte) { ...@@ -48,6 +49,9 @@ func (x *cbc) CryptBlocks(dst, src []byte) {
if len(dst) < len(src) { if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input") panic("crypto/cipher: output smaller than input")
} }
if subtle.InexactOverlap(dst[:len(src)], src) {
panic("crypto/cipher: invalid buffer overlap")
}
if len(src) > 0 { if len(src) > 0 {
cryptBlocksChain(x.c, &x.iv[0], &x.b.key[0], &dst[0], &src[0], len(src)) cryptBlocksChain(x.c, &x.iv[0], &x.b.key[0], &dst[0], &src[0], len(src))
} }
......
...@@ -6,6 +6,7 @@ package aes ...@@ -6,6 +6,7 @@ package aes
import ( import (
"crypto/cipher" "crypto/cipher"
"crypto/internal/subtle"
"strconv" "strconv"
) )
...@@ -57,6 +58,9 @@ func (c *aesCipher) Encrypt(dst, src []byte) { ...@@ -57,6 +58,9 @@ func (c *aesCipher) Encrypt(dst, src []byte) {
if len(dst) < BlockSize { if len(dst) < BlockSize {
panic("crypto/aes: output not full block") 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) encryptBlockGo(c.enc, dst, src)
} }
...@@ -67,5 +71,8 @@ func (c *aesCipher) Decrypt(dst, src []byte) { ...@@ -67,5 +71,8 @@ func (c *aesCipher) Decrypt(dst, src []byte) {
if len(dst) < BlockSize { if len(dst) < BlockSize {
panic("crypto/aes: output not full block") 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) decryptBlockGo(c.dec, dst, src)
} }
...@@ -6,6 +6,7 @@ package aes ...@@ -6,6 +6,7 @@ package aes
import ( import (
"crypto/cipher" "crypto/cipher"
"crypto/internal/subtle"
"internal/cpu" "internal/cpu"
) )
...@@ -52,6 +53,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) { ...@@ -52,6 +53,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) {
if len(dst) < BlockSize { if len(dst) < BlockSize {
panic("crypto/aes: output not full block") 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]) encryptBlockAsm(len(c.enc)/4-1, &c.enc[0], &dst[0], &src[0])
} }
...@@ -62,6 +66,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) { ...@@ -62,6 +66,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) {
if len(dst) < BlockSize { if len(dst) < BlockSize {
panic("crypto/aes: output not full block") 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]) decryptBlockAsm(len(c.dec)/4-1, &c.dec[0], &dst[0], &src[0])
} }
......
...@@ -6,6 +6,7 @@ package aes ...@@ -6,6 +6,7 @@ package aes
import ( import (
"crypto/cipher" "crypto/cipher"
"crypto/internal/subtle"
"internal/cpu" "internal/cpu"
"math/bits" "math/bits"
) )
...@@ -40,6 +41,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) { ...@@ -40,6 +41,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) {
if len(dst) < BlockSize { if len(dst) < BlockSize {
panic("crypto/aes: output not full block") 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]) encryptBlockAsm(len(c.enc)/4-1, &c.enc[0], &dst[0], &src[0])
} }
...@@ -50,6 +54,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) { ...@@ -50,6 +54,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) {
if len(dst) < BlockSize { if len(dst) < BlockSize {
panic("crypto/aes: output not full block") 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]) decryptBlockAsm(len(c.dec)/4-1, &c.dec[0], &dst[0], &src[0])
} }
......
...@@ -6,6 +6,7 @@ package aes ...@@ -6,6 +6,7 @@ package aes
import ( import (
"crypto/cipher" "crypto/cipher"
"crypto/internal/subtle"
) )
// defined in asm_ppc64le.s // defined in asm_ppc64le.s
...@@ -54,6 +55,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) { ...@@ -54,6 +55,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) {
if len(dst) < BlockSize { if len(dst) < BlockSize {
panic("crypto/aes: output not full block") 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]) encryptBlockAsm(&dst[0], &src[0], &c.enc[0])
} }
...@@ -64,6 +68,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) { ...@@ -64,6 +68,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) {
if len(dst) < BlockSize { if len(dst) < BlockSize {
panic("crypto/aes: output not full block") 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]) decryptBlockAsm(&dst[0], &src[0], &c.dec[0])
} }
......
...@@ -6,6 +6,7 @@ package aes ...@@ -6,6 +6,7 @@ package aes
import ( import (
"crypto/cipher" "crypto/cipher"
"crypto/internal/subtle"
"internal/cpu" "internal/cpu"
) )
...@@ -67,6 +68,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) { ...@@ -67,6 +68,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) {
if len(dst) < BlockSize { if len(dst) < BlockSize {
panic("crypto/aes: output not full block") 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) cryptBlocks(c.function, &c.key[0], &dst[0], &src[0], BlockSize)
} }
...@@ -77,6 +81,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) { ...@@ -77,6 +81,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) {
if len(dst) < BlockSize { if len(dst) < BlockSize {
panic("crypto/aes: output not full block") 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. // The decrypt function code is equal to the function code + 128.
cryptBlocks(c.function+128, &c.key[0], &dst[0], &src[0], BlockSize) cryptBlocks(c.function+128, &c.key[0], &dst[0], &src[0], BlockSize)
} }
......
...@@ -6,6 +6,7 @@ package aes ...@@ -6,6 +6,7 @@ package aes
import ( import (
"crypto/cipher" "crypto/cipher"
"crypto/internal/subtle"
"unsafe" "unsafe"
) )
...@@ -64,9 +65,11 @@ func (c *aesctr) refill() { ...@@ -64,9 +65,11 @@ func (c *aesctr) refill() {
} }
func (c *aesctr) XORKeyStream(dst, src []byte) { func (c *aesctr) XORKeyStream(dst, src []byte) {
if len(src) > 0 { if len(dst) < len(src) {
// Assert len(dst) >= len(src) panic("crypto/cipher: output smaller than input")
_ = dst[len(src)-1] }
if subtle.InexactOverlap(dst[:len(src)], src) {
panic("crypto/cipher: invalid buffer overlap")
} }
for len(src) > 0 { for len(src) > 0 {
if len(c.buffer) == 0 { if len(c.buffer) == 0 {
......
...@@ -6,6 +6,7 @@ package aes ...@@ -6,6 +6,7 @@ package aes
import ( import (
"crypto/cipher" "crypto/cipher"
subtleoverlap "crypto/internal/subtle"
"crypto/subtle" "crypto/subtle"
"errors" "errors"
"internal/cpu" "internal/cpu"
...@@ -220,13 +221,16 @@ func (g *gcmAsm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSi ...@@ -220,13 +221,16 @@ func (g *gcmAsm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSi
// details. // details.
func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
if len(nonce) != g.nonceSize { 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 { 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) 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) counter := g.deriveCounter(nonce)
...@@ -246,12 +250,12 @@ func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { ...@@ -246,12 +250,12 @@ func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
// for details. // for details.
func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
if len(nonce) != g.nonceSize { 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 // Sanity check to prevent the authentication from always succeeding if an implementation
// leaves tagSize uninitialized, for example. // leaves tagSize uninitialized, for example.
if g.tagSize < gcmMinimumTagSize { if g.tagSize < gcmMinimumTagSize {
panic("cipher: incorrect GCM tag size") panic("crypto/cipher: incorrect GCM tag size")
} }
if len(ciphertext) < g.tagSize { if len(ciphertext) < g.tagSize {
return nil, errOpen return nil, errOpen
...@@ -273,6 +277,9 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { ...@@ -273,6 +277,9 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
g.auth(expectedTag[:], ciphertext, data, &tagMask) g.auth(expectedTag[:], ciphertext, data, &tagMask)
ret, out := sliceForAppend(dst, len(ciphertext)) 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 { if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
// The AESNI code decrypts and authenticates concurrently, and // 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) ...@@ -314,13 +321,16 @@ func kmaGCM(fn code, key, dst, src, aad []byte, tag *[16]byte, cnt *gcmCount)
// details. // details.
func (g *gcmKMA) Seal(dst, nonce, plaintext, data []byte) []byte { func (g *gcmKMA) Seal(dst, nonce, plaintext, data []byte) []byte {
if len(nonce) != g.nonceSize { 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 { 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) 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) counter := g.deriveCounter(nonce)
fc := g.block.function | kmaLAAD | kmaLPC fc := g.block.function | kmaLAAD | kmaLPC
...@@ -336,7 +346,7 @@ func (g *gcmKMA) Seal(dst, nonce, plaintext, data []byte) []byte { ...@@ -336,7 +346,7 @@ func (g *gcmKMA) Seal(dst, nonce, plaintext, data []byte) []byte {
// for details. // for details.
func (g *gcmKMA) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { func (g *gcmKMA) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
if len(nonce) != g.nonceSize { 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 { if len(ciphertext) < g.tagSize {
return nil, errOpen return nil, errOpen
...@@ -348,9 +358,12 @@ func (g *gcmKMA) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { ...@@ -348,9 +358,12 @@ func (g *gcmKMA) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
tag := ciphertext[len(ciphertext)-g.tagSize:] tag := ciphertext[len(ciphertext)-g.tagSize:]
ciphertext = ciphertext[:len(ciphertext)-g.tagSize] ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
ret, out := sliceForAppend(dst, len(ciphertext)) ret, out := sliceForAppend(dst, len(ciphertext))
if subtleoverlap.InexactOverlap(out, ciphertext) {
panic("crypto/cipher: invalid buffer overlap")
}
if g.tagSize < gcmMinimumTagSize { if g.tagSize < gcmMinimumTagSize {
panic("cipher: incorrect GCM tag size") panic("crypto/cipher: incorrect GCM tag size")
} }
counter := g.deriveCounter(nonce) counter := g.deriveCounter(nonce)
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
package cipher package cipher
import "crypto/internal/subtle"
type cbc struct { type cbc struct {
b Block b Block
blockSize int blockSize int
...@@ -59,6 +61,9 @@ func (x *cbcEncrypter) CryptBlocks(dst, src []byte) { ...@@ -59,6 +61,9 @@ func (x *cbcEncrypter) CryptBlocks(dst, src []byte) {
if len(dst) < len(src) { if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input") panic("crypto/cipher: output smaller than input")
} }
if subtle.InexactOverlap(dst[:len(src)], src) {
panic("crypto/cipher: invalid buffer overlap")
}
iv := x.iv iv := x.iv
...@@ -116,6 +121,9 @@ func (x *cbcDecrypter) CryptBlocks(dst, src []byte) { ...@@ -116,6 +121,9 @@ func (x *cbcDecrypter) CryptBlocks(dst, src []byte) {
if len(dst) < len(src) { if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input") panic("crypto/cipher: output smaller than input")
} }
if subtle.InexactOverlap(dst[:len(src)], src) {
panic("crypto/cipher: invalid buffer overlap")
}
if len(src) == 0 { if len(src) == 0 {
return return
} }
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
package cipher package cipher
import "crypto/internal/subtle"
type cfb struct { type cfb struct {
b Block b Block
next []byte next []byte
...@@ -16,6 +18,12 @@ type cfb struct { ...@@ -16,6 +18,12 @@ type cfb struct {
} }
func (x *cfb) XORKeyStream(dst, src []byte) { 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 { for len(src) > 0 {
if x.outUsed == len(x.out) { if x.outUsed == len(x.out) {
x.b.Encrypt(x.out, x.next) x.b.Encrypt(x.out, x.next)
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
package cipher package cipher
import "crypto/internal/subtle"
type ctr struct { type ctr struct {
b Block b Block
ctr []byte ctr []byte
...@@ -71,6 +73,12 @@ func (x *ctr) refill() { ...@@ -71,6 +73,12 @@ func (x *ctr) refill() {
} }
func (x *ctr) XORKeyStream(dst, src []byte) { 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 { for len(src) > 0 {
if x.outUsed >= len(x.out)-x.b.BlockSize() { if x.outUsed >= len(x.out)-x.b.BlockSize() {
x.refill() x.refill()
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package cipher package cipher
import ( import (
subtleoverlap "crypto/internal/subtle"
"crypto/subtle" "crypto/subtle"
"errors" "errors"
) )
...@@ -26,8 +27,8 @@ type AEAD interface { ...@@ -26,8 +27,8 @@ type AEAD interface {
// slice. The nonce must be NonceSize() bytes long and unique for all // slice. The nonce must be NonceSize() bytes long and unique for all
// time, for a given key. // time, for a given key.
// //
// The plaintext and dst must overlap exactly or not at all. To reuse // To reuse plaintext's storage for the encrypted output, use plaintext[:0]
// plaintext's storage for the encrypted output, use plaintext[:0] as dst. // as dst. Otherwise, the remaining capacity of dst must not overlap plaintext.
Seal(dst, nonce, plaintext, additionalData []byte) []byte Seal(dst, nonce, plaintext, additionalData []byte) []byte
// Open decrypts and authenticates ciphertext, authenticates the // Open decrypts and authenticates ciphertext, authenticates the
...@@ -36,8 +37,8 @@ type AEAD interface { ...@@ -36,8 +37,8 @@ type AEAD interface {
// bytes long and both it and the additional data must match the // bytes long and both it and the additional data must match the
// value passed to Seal. // value passed to Seal.
// //
// The ciphertext and dst must overlap exactly or not at all. To reuse // To reuse ciphertext's storage for the decrypted output, use ciphertext[:0]
// ciphertext's storage for the decrypted output, use ciphertext[:0] as dst. // 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, // Even if the function fails, the contents of dst, up to its capacity,
// may be overwritten. // may be overwritten.
...@@ -159,13 +160,16 @@ func (g *gcm) Overhead() int { ...@@ -159,13 +160,16 @@ func (g *gcm) Overhead() int {
func (g *gcm) Seal(dst, nonce, plaintext, data []byte) []byte { func (g *gcm) Seal(dst, nonce, plaintext, data []byte) []byte {
if len(nonce) != g.nonceSize { 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()) { 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) ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
if subtleoverlap.InexactOverlap(out, plaintext) {
panic("crypto/cipher: invalid buffer overlap")
}
var counter, tagMask [gcmBlockSize]byte var counter, tagMask [gcmBlockSize]byte
g.deriveCounter(&counter, nonce) g.deriveCounter(&counter, nonce)
...@@ -186,12 +190,12 @@ var errOpen = errors.New("cipher: message authentication failed") ...@@ -186,12 +190,12 @@ var errOpen = errors.New("cipher: message authentication failed")
func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
if len(nonce) != g.nonceSize { 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 // Sanity check to prevent the authentication from always succeeding if an implementation
// leaves tagSize uninitialized, for example. // leaves tagSize uninitialized, for example.
if g.tagSize < gcmMinimumTagSize { if g.tagSize < gcmMinimumTagSize {
panic("cipher: incorrect GCM tag size") panic("crypto/cipher: incorrect GCM tag size")
} }
if len(ciphertext) < g.tagSize { if len(ciphertext) < g.tagSize {
...@@ -214,6 +218,9 @@ func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { ...@@ -214,6 +218,9 @@ func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
g.auth(expectedTag[:], ciphertext, data, &tagMask) g.auth(expectedTag[:], ciphertext, data, &tagMask)
ret, out := sliceForAppend(dst, len(ciphertext)) 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 { if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
// The AESNI code decrypts and authenticates concurrently, and // The AESNI code decrypts and authenticates concurrently, and
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
package cipher package cipher
import "crypto/internal/subtle"
type ofb struct { type ofb struct {
b Block b Block
cipher []byte cipher []byte
...@@ -54,6 +56,12 @@ func (x *ofb) refill() { ...@@ -54,6 +56,12 @@ func (x *ofb) refill() {
} }
func (x *ofb) XORKeyStream(dst, src []byte) { 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 { for len(src) > 0 {
if x.outUsed >= len(x.out)-x.b.BlockSize() { if x.outUsed >= len(x.out)-x.b.BlockSize() {
x.refill() x.refill()
......
...@@ -6,6 +6,7 @@ package des ...@@ -6,6 +6,7 @@ package des
import ( import (
"crypto/cipher" "crypto/cipher"
"crypto/internal/subtle"
"encoding/binary" "encoding/binary"
"strconv" "strconv"
) )
...@@ -37,9 +38,31 @@ func NewCipher(key []byte) (cipher.Block, error) { ...@@ -37,9 +38,31 @@ func NewCipher(key []byte) (cipher.Block, error) {
func (c *desCipher) BlockSize() int { return BlockSize } 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. // A tripleDESCipher is an instance of TripleDES encryption.
type tripleDESCipher struct { type tripleDESCipher struct {
...@@ -62,6 +85,16 @@ func NewTripleDESCipher(key []byte) (cipher.Block, error) { ...@@ -62,6 +85,16 @@ func NewTripleDESCipher(key []byte) (cipher.Block, error) {
func (c *tripleDESCipher) BlockSize() int { return BlockSize } func (c *tripleDESCipher) BlockSize() int { return BlockSize }
func (c *tripleDESCipher) Encrypt(dst, src []byte) { 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 := binary.BigEndian.Uint64(src)
b = permuteInitialBlock(b) b = permuteInitialBlock(b)
left, right := uint32(b>>32), uint32(b) left, right := uint32(b>>32), uint32(b)
...@@ -87,6 +120,16 @@ func (c *tripleDESCipher) Encrypt(dst, src []byte) { ...@@ -87,6 +120,16 @@ func (c *tripleDESCipher) Encrypt(dst, src []byte) {
} }
func (c *tripleDESCipher) Decrypt(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 := binary.BigEndian.Uint64(src)
b = permuteInitialBlock(b) b = permuteInitialBlock(b)
left, right := uint32(b>>32), uint32(b) left, right := uint32(b>>32), uint32(b)
......
// 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)
}
// 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)
}
// 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)
}
}
...@@ -9,7 +9,10 @@ ...@@ -9,7 +9,10 @@
// applications. // applications.
package rc4 package rc4
import "strconv" import (
"crypto/internal/subtle"
"strconv"
)
// A Cipher is an instance of RC4 using a particular key. // A Cipher is an instance of RC4 using a particular key.
type Cipher struct { type Cipher struct {
...@@ -60,6 +63,9 @@ func (c *Cipher) xorKeyStreamGeneric(dst, src []byte) { ...@@ -60,6 +63,9 @@ func (c *Cipher) xorKeyStreamGeneric(dst, src []byte) {
if len(src) == 0 { if len(src) == 0 {
return return
} }
if subtle.InexactOverlap(dst[:len(src)], src) {
panic("crypto/rc4: invalid buffer overlap")
}
i, j := c.i, c.j i, j := c.i, c.j
_ = dst[len(src)-1] _ = dst[len(src)-1]
dst = dst[:len(src)] // eliminate bounds check from loop dst = dst[:len(src)] // eliminate bounds check from loop
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
package rc4 package rc4
import "crypto/internal/subtle"
func xorKeyStream(dst, src *byte, n int, state *[256]uint32, i, j *uint8) 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. // XORKeyStream sets dst to the result of XORing src with the key stream.
...@@ -14,7 +16,11 @@ func (c *Cipher) XORKeyStream(dst, src []byte) { ...@@ -14,7 +16,11 @@ func (c *Cipher) XORKeyStream(dst, src []byte) {
if len(src) == 0 { if len(src) == 0 {
return return
} }
// Assert len(dst) >= len(src) if len(dst) < len(src) {
_ = dst[len(src)-1] 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) xorKeyStream(&dst[0], &src[0], len(src), &c.s, &c.i, &c.j)
} }
...@@ -100,7 +100,8 @@ var pkgDeps = map[string][]string{ ...@@ -100,7 +100,8 @@ var pkgDeps = map[string][]string{
// and interface definitions, but nothing that makes // and interface definitions, but nothing that makes
// system calls. // system calls.
"crypto": {"L2", "hash"}, // interfaces "crypto": {"L2", "hash"}, // interfaces
"crypto/cipher": {"L2", "crypto/subtle"}, "crypto/cipher": {"L2", "crypto/subtle", "crypto/internal/subtle"},
"crypto/internal/subtle": {"unsafe", "reflect"}, // reflect behind a appengine tag
"crypto/subtle": {}, "crypto/subtle": {},
"encoding/base32": {"L2"}, "encoding/base32": {"L2"},
"encoding/base64": {"L2", "encoding/binary"}, "encoding/base64": {"L2", "encoding/binary"},
...@@ -120,6 +121,7 @@ var pkgDeps = map[string][]string{ ...@@ -120,6 +121,7 @@ var pkgDeps = map[string][]string{
"L2", "L2",
"crypto", "crypto",
"crypto/cipher", "crypto/cipher",
"crypto/internal/subtle",
"crypto/subtle", "crypto/subtle",
"encoding/base32", "encoding/base32",
"encoding/base64", "encoding/base64",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment