Skip to content

Commit dd7a7ba

Browse files
FiloSottilegopherbot
authored andcommitted
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 <[email protected]> Reviewed-by: Roland Shoemaker <[email protected]> Auto-Submit: Filippo Valsorda <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 427a240 commit dd7a7ba

File tree

6 files changed

+24
-15
lines changed

6 files changed

+24
-15
lines changed

src/crypto/internal/fips140/aes/aes.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ func newBlockExpanded(c *blockExpanded, key []byte) {
9494
func (c *Block) BlockSize() int { return BlockSize }
9595

9696
func (c *Block) Encrypt(dst, src []byte) {
97+
// AES-ECB is not approved in FIPS 140-3 mode.
98+
fips140.RecordNonApproved()
9799
if len(src) < BlockSize {
98100
panic("crypto/aes: input not full block")
99101
}
@@ -103,11 +105,12 @@ func (c *Block) Encrypt(dst, src []byte) {
103105
if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
104106
panic("crypto/aes: invalid buffer overlap")
105107
}
106-
fips140.RecordApproved()
107108
encryptBlock(c, dst, src)
108109
}
109110

110111
func (c *Block) Decrypt(dst, src []byte) {
112+
// AES-ECB is not approved in FIPS 140-3 mode.
113+
fips140.RecordNonApproved()
111114
if len(src) < BlockSize {
112115
panic("crypto/aes: input not full block")
113116
}
@@ -117,6 +120,12 @@ func (c *Block) Decrypt(dst, src []byte) {
117120
if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
118121
panic("crypto/aes: invalid buffer overlap")
119122
}
120-
fips140.RecordApproved()
121123
decryptBlock(c, dst, src)
122124
}
125+
126+
// EncryptBlockInternal applies the AES encryption function to one block.
127+
//
128+
// It is an internal function meant only for the gcm package.
129+
func EncryptBlockInternal(c *Block, dst, src []byte) {
130+
encryptBlock(c, dst, src)
131+
}

src/crypto/internal/fips140/aes/cbc.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func cryptBlocksEncGeneric(b *Block, civ *[BlockSize]byte, dst, src []byte) {
5050
for len(src) > 0 {
5151
// Write the xor to dst, then encrypt in place.
5252
subtle.XORBytes(dst[:BlockSize], src[:BlockSize], iv)
53-
b.Encrypt(dst[:BlockSize], dst[:BlockSize])
53+
encryptBlock(b, dst[:BlockSize], dst[:BlockSize])
5454

5555
// Move to the next block with this block as the next iv.
5656
iv = dst[:BlockSize]
@@ -111,7 +111,7 @@ func cryptBlocksDecGeneric(b *Block, civ *[BlockSize]byte, dst, src []byte) {
111111
copy(civ[:], src[start:end])
112112

113113
for start >= 0 {
114-
b.Decrypt(dst[start:end], src[start:end])
114+
decryptBlock(b, dst[start:end], src[start:end])
115115

116116
if start > 0 {
117117
subtle.XORBytes(dst[start:end], dst[start:end], src[prev:start])

src/crypto/internal/fips140/aes/ctr.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ func ctrBlocks(b *Block, dst, src []byte, ivlo, ivhi uint64) {
132132
byteorder.BEPutUint64(buf[i:], ivhi)
133133
byteorder.BEPutUint64(buf[i+8:], ivlo)
134134
ivlo, ivhi = add128(ivlo, ivhi, 1)
135-
b.Encrypt(buf[i:], buf[i:])
135+
encryptBlock(b, buf[i:], buf[i:])
136136
}
137137
// XOR into buf first, in case src and dst overlap (see above).
138138
subtle.XORBytes(buf, src, buf)

src/crypto/internal/fips140/aes/gcm/cmac.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func NewCMAC(b *aes.Block) *CMAC {
2828
}
2929

3030
func (c *CMAC) deriveSubkeys() {
31-
c.b.Encrypt(c.k1[:], c.k1[:])
31+
aes.EncryptBlockInternal(&c.b, c.k1[:], c.k1[:])
3232
msb := shiftLeft(&c.k1)
3333
c.k1[len(c.k1)-1] ^= msb * 0b10000111
3434

@@ -45,7 +45,7 @@ func (c *CMAC) MAC(m []byte) [aes.BlockSize]byte {
4545
// Special-cased as a single empty partial final block.
4646
x = c.k2
4747
x[len(m)] ^= 0b10000000
48-
c.b.Encrypt(x[:], x[:])
48+
aes.EncryptBlockInternal(&c.b, x[:], x[:])
4949
return x
5050
}
5151
for len(m) >= aes.BlockSize {
@@ -54,15 +54,15 @@ func (c *CMAC) MAC(m []byte) [aes.BlockSize]byte {
5454
// Final complete block.
5555
subtle.XORBytes(x[:], c.k1[:], x[:])
5656
}
57-
c.b.Encrypt(x[:], x[:])
57+
aes.EncryptBlockInternal(&c.b, x[:], x[:])
5858
m = m[aes.BlockSize:]
5959
}
6060
if len(m) > 0 {
6161
// Final incomplete block.
6262
subtle.XORBytes(x[:], m, x[:])
6363
subtle.XORBytes(x[:], c.k2[:], x[:])
6464
x[len(m)] ^= 0b10000000
65-
c.b.Encrypt(x[:], x[:])
65+
aes.EncryptBlockInternal(&c.b, x[:], x[:])
6666
}
6767
return x
6868
}

src/crypto/internal/fips140/aes/gcm/gcm_asm.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ func seal(out []byte, g *GCM, nonce, plaintext, data []byte) {
8181
gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
8282
}
8383

84-
g.cipher.Encrypt(tagMask[:], counter[:])
84+
aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:])
8585

8686
var tagOut [gcmTagSize]byte
8787
gcmAesData(&g.productTable, data, &tagOut)
@@ -114,7 +114,7 @@ func open(out []byte, g *GCM, nonce, ciphertext, data []byte) error {
114114
gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
115115
}
116116

117-
g.cipher.Encrypt(tagMask[:], counter[:])
117+
aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:])
118118

119119
var expectedTag [gcmTagSize]byte
120120
gcmAesData(&g.productTable, data, &expectedTag)

src/crypto/internal/fips140/aes/gcm/gcm_generic.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212

1313
func sealGeneric(out []byte, g *GCM, nonce, plaintext, additionalData []byte) {
1414
var H, counter, tagMask [gcmBlockSize]byte
15-
g.cipher.Encrypt(H[:], H[:])
15+
aes.EncryptBlockInternal(&g.cipher, H[:], H[:])
1616
deriveCounterGeneric(&H, &counter, nonce)
1717
gcmCounterCryptGeneric(&g.cipher, tagMask[:], tagMask[:], &counter)
1818

@@ -25,7 +25,7 @@ func sealGeneric(out []byte, g *GCM, nonce, plaintext, additionalData []byte) {
2525

2626
func openGeneric(out []byte, g *GCM, nonce, ciphertext, additionalData []byte) error {
2727
var H, counter, tagMask [gcmBlockSize]byte
28-
g.cipher.Encrypt(H[:], H[:])
28+
aes.EncryptBlockInternal(&g.cipher, H[:], H[:])
2929
deriveCounterGeneric(&H, &counter, nonce)
3030
gcmCounterCryptGeneric(&g.cipher, tagMask[:], tagMask[:], &counter)
3131

@@ -70,7 +70,7 @@ func gcmCounterCryptGeneric(b *aes.Block, out, src []byte, counter *[gcmBlockSiz
7070
var mask [gcmBlockSize]byte
7171

7272
for len(src) >= gcmBlockSize {
73-
b.Encrypt(mask[:], counter[:])
73+
aes.EncryptBlockInternal(b, mask[:], counter[:])
7474
gcmInc32(counter)
7575

7676
subtle.XORBytes(out, src, mask[:])
@@ -79,7 +79,7 @@ func gcmCounterCryptGeneric(b *aes.Block, out, src []byte, counter *[gcmBlockSiz
7979
}
8080

8181
if len(src) > 0 {
82-
b.Encrypt(mask[:], counter[:])
82+
aes.EncryptBlockInternal(b, mask[:], counter[:])
8383
gcmInc32(counter)
8484
subtle.XORBytes(out, src, mask[:])
8585
}

0 commit comments

Comments
 (0)