mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
crypto/internal/fips140/aes: mark AES-ECB as not approved
NIST SP 800-131Ar3 ipd, scheduled for publication in 2025Q1, marks AES-ECB as disallowed for encryption, and legacy use for decryption. There are apparently no details on how the transition is going to work, so to avoid surprises we just mark direct use of the Block as non-approved. We need to use Encrypt from higher level modes without tripping the service indicator. Within the aes package, we just use the internal function. For the gcm package we could do something more clever, but this deep into the freeze, just make an exported function that we commit to use nowhere else. I could not figure out a decent way to block ECB on GODEBUG=fips140=only. For #69536 Change-Id: I972a4b5da8efd0a0ab68d7dd509bec73aa2d6b68 Reviewed-on: https://go-review.googlesource.com/c/go/+/636775 Reviewed-by: David Chase <drchase@google.com> Reviewed-by: Roland Shoemaker <roland@golang.org> Auto-Submit: Filippo Valsorda <filippo@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
427a2401af
commit
dd7a7ba38f
6 changed files with 24 additions and 15 deletions
|
|
@ -94,6 +94,8 @@ func newBlockExpanded(c *blockExpanded, key []byte) {
|
||||||
func (c *Block) BlockSize() int { return BlockSize }
|
func (c *Block) BlockSize() int { return BlockSize }
|
||||||
|
|
||||||
func (c *Block) Encrypt(dst, src []byte) {
|
func (c *Block) Encrypt(dst, src []byte) {
|
||||||
|
// AES-ECB is not approved in FIPS 140-3 mode.
|
||||||
|
fips140.RecordNonApproved()
|
||||||
if len(src) < BlockSize {
|
if len(src) < BlockSize {
|
||||||
panic("crypto/aes: input not full block")
|
panic("crypto/aes: input not full block")
|
||||||
}
|
}
|
||||||
|
|
@ -103,11 +105,12 @@ func (c *Block) Encrypt(dst, src []byte) {
|
||||||
if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
|
if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
|
||||||
panic("crypto/aes: invalid buffer overlap")
|
panic("crypto/aes: invalid buffer overlap")
|
||||||
}
|
}
|
||||||
fips140.RecordApproved()
|
|
||||||
encryptBlock(c, dst, src)
|
encryptBlock(c, dst, src)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Block) Decrypt(dst, src []byte) {
|
func (c *Block) Decrypt(dst, src []byte) {
|
||||||
|
// AES-ECB is not approved in FIPS 140-3 mode.
|
||||||
|
fips140.RecordNonApproved()
|
||||||
if len(src) < BlockSize {
|
if len(src) < BlockSize {
|
||||||
panic("crypto/aes: input not full block")
|
panic("crypto/aes: input not full block")
|
||||||
}
|
}
|
||||||
|
|
@ -117,6 +120,12 @@ func (c *Block) Decrypt(dst, src []byte) {
|
||||||
if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
|
if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
|
||||||
panic("crypto/aes: invalid buffer overlap")
|
panic("crypto/aes: invalid buffer overlap")
|
||||||
}
|
}
|
||||||
fips140.RecordApproved()
|
|
||||||
decryptBlock(c, dst, src)
|
decryptBlock(c, dst, src)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EncryptBlockInternal applies the AES encryption function to one block.
|
||||||
|
//
|
||||||
|
// It is an internal function meant only for the gcm package.
|
||||||
|
func EncryptBlockInternal(c *Block, dst, src []byte) {
|
||||||
|
encryptBlock(c, dst, src)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ func cryptBlocksEncGeneric(b *Block, civ *[BlockSize]byte, dst, src []byte) {
|
||||||
for len(src) > 0 {
|
for len(src) > 0 {
|
||||||
// Write the xor to dst, then encrypt in place.
|
// Write the xor to dst, then encrypt in place.
|
||||||
subtle.XORBytes(dst[:BlockSize], src[:BlockSize], iv)
|
subtle.XORBytes(dst[:BlockSize], src[:BlockSize], iv)
|
||||||
b.Encrypt(dst[:BlockSize], dst[:BlockSize])
|
encryptBlock(b, dst[:BlockSize], dst[:BlockSize])
|
||||||
|
|
||||||
// Move to the next block with this block as the next iv.
|
// Move to the next block with this block as the next iv.
|
||||||
iv = dst[:BlockSize]
|
iv = dst[:BlockSize]
|
||||||
|
|
@ -111,7 +111,7 @@ func cryptBlocksDecGeneric(b *Block, civ *[BlockSize]byte, dst, src []byte) {
|
||||||
copy(civ[:], src[start:end])
|
copy(civ[:], src[start:end])
|
||||||
|
|
||||||
for start >= 0 {
|
for start >= 0 {
|
||||||
b.Decrypt(dst[start:end], src[start:end])
|
decryptBlock(b, dst[start:end], src[start:end])
|
||||||
|
|
||||||
if start > 0 {
|
if start > 0 {
|
||||||
subtle.XORBytes(dst[start:end], dst[start:end], src[prev:start])
|
subtle.XORBytes(dst[start:end], dst[start:end], src[prev:start])
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ func ctrBlocks(b *Block, dst, src []byte, ivlo, ivhi uint64) {
|
||||||
byteorder.BEPutUint64(buf[i:], ivhi)
|
byteorder.BEPutUint64(buf[i:], ivhi)
|
||||||
byteorder.BEPutUint64(buf[i+8:], ivlo)
|
byteorder.BEPutUint64(buf[i+8:], ivlo)
|
||||||
ivlo, ivhi = add128(ivlo, ivhi, 1)
|
ivlo, ivhi = add128(ivlo, ivhi, 1)
|
||||||
b.Encrypt(buf[i:], buf[i:])
|
encryptBlock(b, buf[i:], buf[i:])
|
||||||
}
|
}
|
||||||
// XOR into buf first, in case src and dst overlap (see above).
|
// XOR into buf first, in case src and dst overlap (see above).
|
||||||
subtle.XORBytes(buf, src, buf)
|
subtle.XORBytes(buf, src, buf)
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ func NewCMAC(b *aes.Block) *CMAC {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CMAC) deriveSubkeys() {
|
func (c *CMAC) deriveSubkeys() {
|
||||||
c.b.Encrypt(c.k1[:], c.k1[:])
|
aes.EncryptBlockInternal(&c.b, c.k1[:], c.k1[:])
|
||||||
msb := shiftLeft(&c.k1)
|
msb := shiftLeft(&c.k1)
|
||||||
c.k1[len(c.k1)-1] ^= msb * 0b10000111
|
c.k1[len(c.k1)-1] ^= msb * 0b10000111
|
||||||
|
|
||||||
|
|
@ -45,7 +45,7 @@ func (c *CMAC) MAC(m []byte) [aes.BlockSize]byte {
|
||||||
// Special-cased as a single empty partial final block.
|
// Special-cased as a single empty partial final block.
|
||||||
x = c.k2
|
x = c.k2
|
||||||
x[len(m)] ^= 0b10000000
|
x[len(m)] ^= 0b10000000
|
||||||
c.b.Encrypt(x[:], x[:])
|
aes.EncryptBlockInternal(&c.b, x[:], x[:])
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
for len(m) >= aes.BlockSize {
|
for len(m) >= aes.BlockSize {
|
||||||
|
|
@ -54,7 +54,7 @@ func (c *CMAC) MAC(m []byte) [aes.BlockSize]byte {
|
||||||
// Final complete block.
|
// Final complete block.
|
||||||
subtle.XORBytes(x[:], c.k1[:], x[:])
|
subtle.XORBytes(x[:], c.k1[:], x[:])
|
||||||
}
|
}
|
||||||
c.b.Encrypt(x[:], x[:])
|
aes.EncryptBlockInternal(&c.b, x[:], x[:])
|
||||||
m = m[aes.BlockSize:]
|
m = m[aes.BlockSize:]
|
||||||
}
|
}
|
||||||
if len(m) > 0 {
|
if len(m) > 0 {
|
||||||
|
|
@ -62,7 +62,7 @@ func (c *CMAC) MAC(m []byte) [aes.BlockSize]byte {
|
||||||
subtle.XORBytes(x[:], m, x[:])
|
subtle.XORBytes(x[:], m, x[:])
|
||||||
subtle.XORBytes(x[:], c.k2[:], x[:])
|
subtle.XORBytes(x[:], c.k2[:], x[:])
|
||||||
x[len(m)] ^= 0b10000000
|
x[len(m)] ^= 0b10000000
|
||||||
c.b.Encrypt(x[:], x[:])
|
aes.EncryptBlockInternal(&c.b, x[:], x[:])
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ func seal(out []byte, g *GCM, nonce, plaintext, data []byte) {
|
||||||
gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
|
gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
g.cipher.Encrypt(tagMask[:], counter[:])
|
aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:])
|
||||||
|
|
||||||
var tagOut [gcmTagSize]byte
|
var tagOut [gcmTagSize]byte
|
||||||
gcmAesData(&g.productTable, data, &tagOut)
|
gcmAesData(&g.productTable, data, &tagOut)
|
||||||
|
|
@ -114,7 +114,7 @@ func open(out []byte, g *GCM, nonce, ciphertext, data []byte) error {
|
||||||
gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
|
gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
g.cipher.Encrypt(tagMask[:], counter[:])
|
aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:])
|
||||||
|
|
||||||
var expectedTag [gcmTagSize]byte
|
var expectedTag [gcmTagSize]byte
|
||||||
gcmAesData(&g.productTable, data, &expectedTag)
|
gcmAesData(&g.productTable, data, &expectedTag)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import (
|
||||||
|
|
||||||
func sealGeneric(out []byte, g *GCM, nonce, plaintext, additionalData []byte) {
|
func sealGeneric(out []byte, g *GCM, nonce, plaintext, additionalData []byte) {
|
||||||
var H, counter, tagMask [gcmBlockSize]byte
|
var H, counter, tagMask [gcmBlockSize]byte
|
||||||
g.cipher.Encrypt(H[:], H[:])
|
aes.EncryptBlockInternal(&g.cipher, H[:], H[:])
|
||||||
deriveCounterGeneric(&H, &counter, nonce)
|
deriveCounterGeneric(&H, &counter, nonce)
|
||||||
gcmCounterCryptGeneric(&g.cipher, tagMask[:], tagMask[:], &counter)
|
gcmCounterCryptGeneric(&g.cipher, tagMask[:], tagMask[:], &counter)
|
||||||
|
|
||||||
|
|
@ -25,7 +25,7 @@ func sealGeneric(out []byte, g *GCM, nonce, plaintext, additionalData []byte) {
|
||||||
|
|
||||||
func openGeneric(out []byte, g *GCM, nonce, ciphertext, additionalData []byte) error {
|
func openGeneric(out []byte, g *GCM, nonce, ciphertext, additionalData []byte) error {
|
||||||
var H, counter, tagMask [gcmBlockSize]byte
|
var H, counter, tagMask [gcmBlockSize]byte
|
||||||
g.cipher.Encrypt(H[:], H[:])
|
aes.EncryptBlockInternal(&g.cipher, H[:], H[:])
|
||||||
deriveCounterGeneric(&H, &counter, nonce)
|
deriveCounterGeneric(&H, &counter, nonce)
|
||||||
gcmCounterCryptGeneric(&g.cipher, tagMask[:], tagMask[:], &counter)
|
gcmCounterCryptGeneric(&g.cipher, tagMask[:], tagMask[:], &counter)
|
||||||
|
|
||||||
|
|
@ -70,7 +70,7 @@ func gcmCounterCryptGeneric(b *aes.Block, out, src []byte, counter *[gcmBlockSiz
|
||||||
var mask [gcmBlockSize]byte
|
var mask [gcmBlockSize]byte
|
||||||
|
|
||||||
for len(src) >= gcmBlockSize {
|
for len(src) >= gcmBlockSize {
|
||||||
b.Encrypt(mask[:], counter[:])
|
aes.EncryptBlockInternal(b, mask[:], counter[:])
|
||||||
gcmInc32(counter)
|
gcmInc32(counter)
|
||||||
|
|
||||||
subtle.XORBytes(out, src, mask[:])
|
subtle.XORBytes(out, src, mask[:])
|
||||||
|
|
@ -79,7 +79,7 @@ func gcmCounterCryptGeneric(b *aes.Block, out, src []byte, counter *[gcmBlockSiz
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(src) > 0 {
|
if len(src) > 0 {
|
||||||
b.Encrypt(mask[:], counter[:])
|
aes.EncryptBlockInternal(b, mask[:], counter[:])
|
||||||
gcmInc32(counter)
|
gcmInc32(counter)
|
||||||
subtle.XORBytes(out, src, mask[:])
|
subtle.XORBytes(out, src, mask[:])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue