1
2
3
4
5
6
7 package gcm
8
9 import (
10 "crypto/internal/fips140/aes"
11 "crypto/internal/fips140/subtle"
12 "crypto/internal/fips140deps/cpu"
13 "crypto/internal/impl"
14 )
15
16
17
18
19 func gcmAesInit(productTable *[256]byte, ks []uint32)
20
21
22 func gcmAesData(productTable *[256]byte, data []byte, T *[16]byte)
23
24
25 func gcmAesEnc(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32)
26
27
28 func gcmAesDec(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32)
29
30
31 func gcmAesFinish(productTable *[256]byte, tagMask, T *[16]byte, pLen, dLen uint64)
32
33
34 var supportsAESGCM = cpu.X86HasAES && cpu.X86HasPCLMULQDQ && cpu.X86HasSSE41 && cpu.X86HasSSSE3 ||
35 cpu.ARM64HasAES && cpu.ARM64HasPMULL
36
37 func init() {
38 if cpu.AMD64 {
39 impl.Register("gcm", "AES-NI", &supportsAESGCM)
40 }
41 if cpu.ARM64 {
42 impl.Register("gcm", "Armv8.0", &supportsAESGCM)
43 }
44 }
45
46
47
48
49 func checkGenericIsExpected() {
50 if supportsAESGCM {
51 panic("gcm: internal error: using generic implementation despite hardware support")
52 }
53 }
54
55 type gcmPlatformData struct {
56 productTable [256]byte
57 }
58
59 func initGCM(g *GCM) {
60 if !supportsAESGCM {
61 return
62 }
63 gcmAesInit(&g.productTable, aes.EncryptionKeySchedule(&g.cipher))
64 }
65
66 func seal(out []byte, g *GCM, nonce, plaintext, data []byte) {
67 if !supportsAESGCM {
68 sealGeneric(out, g, nonce, plaintext, data)
69 return
70 }
71
72 var counter, tagMask [gcmBlockSize]byte
73
74 if len(nonce) == gcmStandardNonceSize {
75
76 copy(counter[:], nonce)
77 counter[gcmBlockSize-1] = 1
78 } else {
79
80 gcmAesData(&g.productTable, nonce, &counter)
81 gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
82 }
83
84 aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:])
85
86 var tagOut [gcmTagSize]byte
87 gcmAesData(&g.productTable, data, &tagOut)
88
89 if len(plaintext) > 0 {
90 gcmAesEnc(&g.productTable, out, plaintext, &counter, &tagOut, aes.EncryptionKeySchedule(&g.cipher))
91 }
92 gcmAesFinish(&g.productTable, &tagMask, &tagOut, uint64(len(plaintext)), uint64(len(data)))
93 copy(out[len(plaintext):], tagOut[:])
94 }
95
96 func open(out []byte, g *GCM, nonce, ciphertext, data []byte) error {
97 if !supportsAESGCM {
98 return openGeneric(out, g, nonce, ciphertext, data)
99 }
100
101 tag := ciphertext[len(ciphertext)-g.tagSize:]
102 ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
103
104
105 var counter, tagMask [gcmBlockSize]byte
106
107 if len(nonce) == gcmStandardNonceSize {
108
109 copy(counter[:], nonce)
110 counter[gcmBlockSize-1] = 1
111 } else {
112
113 gcmAesData(&g.productTable, nonce, &counter)
114 gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
115 }
116
117 aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:])
118
119 var expectedTag [gcmTagSize]byte
120 gcmAesData(&g.productTable, data, &expectedTag)
121
122 if len(ciphertext) > 0 {
123 gcmAesDec(&g.productTable, out, ciphertext, &counter, &expectedTag, aes.EncryptionKeySchedule(&g.cipher))
124 }
125 gcmAesFinish(&g.productTable, &tagMask, &expectedTag, uint64(len(ciphertext)), uint64(len(data)))
126
127 if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
128 return errOpen
129 }
130 return nil
131 }
132
View as plain text