github.com/birneee/aes6@v0.0.0-20240131140838-9e8f775f7eae/aes_gcm.go (about) 1 // Copyright 2015 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 //go:build amd64 || arm64 6 7 package aes6 8 9 import ( 10 "crypto/cipher" 11 "crypto/subtle" 12 "github.com/birneee/aes6/alias" 13 ) 14 15 import ( 16 _ "unsafe" 17 ) 18 19 // The following functions are defined in gcm_*.s. 20 21 //go:linkname gcmAesInit crypto/aes.gcmAesInit 22 func gcmAesInit(productTable *[256]byte, ks []uint32) 23 24 //go:linkname gcmAesData crypto/aes.gcmAesData 25 func gcmAesData(productTable *[256]byte, data []byte, T *[16]byte) 26 27 //go:linkname gcmAesEnc crypto/aes.gcmAesEnc 28 func gcmAesEnc(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32) 29 30 //go:linkname gcmAesDec crypto/aes.gcmAesDec 31 func gcmAesDec(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32) 32 33 //go:linkname gcmAesFinish crypto/aes.gcmAesFinish 34 func gcmAesFinish(productTable *[256]byte, tagMask, T *[16]byte, pLen, dLen uint64) 35 36 const ( 37 gcmBlockSize = 16 38 gcmTagSize = 16 39 gcmMinimumTagSize = 6 // ignore NIST SP 800-38D recommended tags of 12 or more bytes. 40 gcmStandardNonceSize = 12 41 ) 42 43 // Assert that aesCipherGCM implements the gcmAble interface. 44 var _ gcmAble = (*aesCipherGCM)(nil) 45 46 // copy of crypto/aes with reduced minimum tag size 47 func (c *aesCipherGCM) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) { 48 g := &gcmAsm{ks: c.enc, nonceSize: nonceSize, tagSize: tagSize} 49 gcmAesInit(&g.productTable, g.ks) 50 return g, nil 51 } 52 53 // copy of crypto/aes with reduced minimum tag size 54 type gcmAsm struct { 55 // ks is the key schedule, the length of which depends on the size of 56 // the AES key. 57 ks []uint32 58 // productTable contains pre-computed multiples of the binary-field 59 // element used in GHASH. 60 productTable [256]byte 61 // nonceSize contains the expected size of the nonce, in bytes. 62 nonceSize int 63 // tagSize contains the size of the tag, in bytes. 64 tagSize int 65 } 66 67 //go:linkname _gcmAsmNonceSize crypto/aes.(*gcmAsm).NonceSize 68 func _gcmAsmNonceSize(g *gcmAsm) int 69 70 func (g *gcmAsm) NonceSize() int { 71 return _gcmAsmNonceSize(g) 72 } 73 74 //go:linkname _gcmAsmOverhead crypto/aes.(*gcmAsm).Overhead 75 func _gcmAsmOverhead(g *gcmAsm) int 76 77 func (g *gcmAsm) Overhead() int { 78 return _gcmAsmOverhead(g) 79 } 80 81 //go:linkname _gcmAsmSeal crypto/aes.(*gcmAsm).Seal 82 func _gcmAsmSeal(g *gcmAsm, dst, nonce, plaintext, data []byte) []byte 83 84 func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { 85 return _gcmAsmSeal(g, dst, nonce, plaintext, data) 86 } 87 88 // copy of crypto/aes with reduced minimum tag size 89 func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { 90 if len(nonce) != g.nonceSize { 91 panic("crypto/cipher: incorrect nonce length given to GCM") 92 } 93 // Sanity check to prevent the authentication from always succeeding if an implementation 94 // leaves tagSize uninitialized, for example. 95 if g.tagSize < gcmMinimumTagSize { 96 panic("crypto/cipher: incorrect GCM tag size") 97 } 98 99 if len(ciphertext) < g.tagSize { 100 return nil, errOpen 101 } 102 if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(BlockSize)+uint64(g.tagSize) { 103 return nil, errOpen 104 } 105 106 tag := ciphertext[len(ciphertext)-g.tagSize:] 107 ciphertext = ciphertext[:len(ciphertext)-g.tagSize] 108 109 // See GCM spec, section 7.1. 110 var counter, tagMask [gcmBlockSize]byte 111 112 if len(nonce) == gcmStandardNonceSize { 113 // Init counter to nonce||1 114 copy(counter[:], nonce) 115 counter[gcmBlockSize-1] = 1 116 } else { 117 // Otherwise counter = GHASH(nonce) 118 gcmAesData(&g.productTable, nonce, &counter) 119 gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0)) 120 } 121 122 encryptBlockAsm(len(g.ks)/4-1, &g.ks[0], &tagMask[0], &counter[0]) 123 124 var expectedTag [gcmTagSize]byte 125 gcmAesData(&g.productTable, data, &expectedTag) 126 127 ret, out := sliceForAppend(dst, len(ciphertext)) 128 if alias.InexactOverlap(out, ciphertext) { 129 panic("crypto/cipher: invalid buffer overlap") 130 } 131 if len(ciphertext) > 0 { 132 gcmAesDec(&g.productTable, out, ciphertext, &counter, &expectedTag, g.ks) 133 } 134 gcmAesFinish(&g.productTable, &tagMask, &expectedTag, uint64(len(ciphertext)), uint64(len(data))) 135 136 if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 { 137 for i := range out { 138 out[i] = 0 139 } 140 return nil, errOpen 141 } 142 143 return ret, nil 144 }