1 // Copyright 2024 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 5 package gcm
6 7 import (
8 "crypto/internal/fips140/aes"
9 "crypto/internal/fips140/subtle"
10 "crypto/internal/fips140deps/byteorder"
11 )
12 13 func sealGeneric(out []byte, g *GCM, nonce, plaintext, additionalData []byte) {
14 var H, counter, tagMask [gcmBlockSize]byte
15 aes.EncryptBlockInternal(&g.cipher, H[:], H[:])
16 deriveCounterGeneric(&H, &counter, nonce)
17 gcmCounterCryptGeneric(&g.cipher, tagMask[:], tagMask[:], &counter)
18 19 gcmCounterCryptGeneric(&g.cipher, out, plaintext, &counter)
20 21 var tag [gcmTagSize]byte
22 gcmAuthGeneric(tag[:], &H, &tagMask, out[:len(plaintext)], additionalData)
23 copy(out[len(plaintext):], tag[:])
24 }
25 26 func openGeneric(out []byte, g *GCM, nonce, ciphertext, additionalData []byte) error {
27 var H, counter, tagMask [gcmBlockSize]byte
28 aes.EncryptBlockInternal(&g.cipher, H[:], H[:])
29 deriveCounterGeneric(&H, &counter, nonce)
30 gcmCounterCryptGeneric(&g.cipher, tagMask[:], tagMask[:], &counter)
31 32 tag := ciphertext[len(ciphertext)-g.tagSize:]
33 ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
34 35 var expectedTag [gcmTagSize]byte
36 gcmAuthGeneric(expectedTag[:], &H, &tagMask, ciphertext, additionalData)
37 if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
38 return errOpen
39 }
40 41 gcmCounterCryptGeneric(&g.cipher, out, ciphertext, &counter)
42 43 return nil
44 }
45 46 // deriveCounterGeneric computes the initial GCM counter state from the given nonce.
47 // See NIST SP 800-38D, section 7.1. This assumes that counter is filled with
48 // zeros on entry.
49 func deriveCounterGeneric(H, counter *[gcmBlockSize]byte, nonce []byte) {
50 // GCM has two modes of operation with respect to the initial counter
51 // state: a "fast path" for 96-bit (12-byte) nonces, and a "slow path"
52 // for nonces of other lengths. For a 96-bit nonce, the nonce, along
53 // with a four-byte big-endian counter starting at one, is used
54 // directly as the starting counter. For other nonce sizes, the counter
55 // is computed by passing it through the GHASH function.
56 if len(nonce) == gcmStandardNonceSize {
57 copy(counter[:], nonce)
58 counter[gcmBlockSize-1] = 1
59 } else {
60 lenBlock := []byte{:16}
61 byteorder.BEPutUint64(lenBlock[8:], uint64(len(nonce))*8)
62 ghash(counter, H, nonce, lenBlock)
63 }
64 }
65 66 // gcmCounterCryptGeneric encrypts src using AES in counter mode with 32-bit
67 // wrapping (which is different from AES-CTR) and places the result into out.
68 // counter is the initial value and will be updated with the next value.
69 func gcmCounterCryptGeneric(b *aes.Block, out, src []byte, counter *[gcmBlockSize]byte) {
70 var mask [gcmBlockSize]byte
71 72 for len(src) >= gcmBlockSize {
73 aes.EncryptBlockInternal(b, mask[:], counter[:])
74 gcmInc32(counter)
75 76 subtle.XORBytes(out, src, mask[:])
77 out = out[gcmBlockSize:]
78 src = src[gcmBlockSize:]
79 }
80 81 if len(src) > 0 {
82 aes.EncryptBlockInternal(b, mask[:], counter[:])
83 gcmInc32(counter)
84 subtle.XORBytes(out, src, mask[:])
85 }
86 }
87 88 // gcmInc32 treats the final four bytes of counterBlock as a big-endian value
89 // and increments it.
90 func gcmInc32(counterBlock *[gcmBlockSize]byte) {
91 ctr := counterBlock[len(counterBlock)-4:]
92 byteorder.BEPutUint32(ctr, byteorder.BEUint32(ctr)+1)
93 }
94 95 // gcmAuthGeneric calculates GHASH(additionalData, ciphertext), masks the result
96 // with tagMask and writes the result to out.
97 func gcmAuthGeneric(out []byte, H, tagMask *[gcmBlockSize]byte, ciphertext, additionalData []byte) {
98 checkGenericIsExpected()
99 lenBlock := []byte{:16}
100 byteorder.BEPutUint64(lenBlock[:8], uint64(len(additionalData))*8)
101 byteorder.BEPutUint64(lenBlock[8:], uint64(len(ciphertext))*8)
102 var S [gcmBlockSize]byte
103 ghash(&S, H, additionalData, ciphertext, lenBlock)
104 subtle.XORBytes(out, S[:], tagMask[:])
105 }
106