package aes
import (
"crypto/cipher"
"crypto/internal/alias"
"crypto/subtle"
"errors"
)
func gcmAesInit (productTable *[256 ]byte , ks []uint32 )
func gcmAesData (productTable *[256 ]byte , data []byte , T *[16 ]byte )
func gcmAesEnc (productTable *[256 ]byte , dst , src []byte , ctr , T *[16 ]byte , ks []uint32 )
func gcmAesDec (productTable *[256 ]byte , dst , src []byte , ctr , T *[16 ]byte , ks []uint32 )
func gcmAesFinish (productTable *[256 ]byte , tagMask , T *[16 ]byte , pLen , dLen uint64 )
const (
gcmBlockSize = 16
gcmTagSize = 16
gcmMinimumTagSize = 12
gcmStandardNonceSize = 12
)
var errOpen = errors .New ("cipher: message authentication failed" )
var _ gcmAble = (*aesCipherGCM )(nil )
func (c *aesCipherGCM ) NewGCM (nonceSize , tagSize int ) (cipher .AEAD , error ) {
g := &gcmAsm {ks : c .enc , nonceSize : nonceSize , tagSize : tagSize }
gcmAesInit (&g .productTable , g .ks )
return g , nil
}
type gcmAsm struct {
ks []uint32
productTable [256 ]byte
nonceSize int
tagSize int
}
func (g *gcmAsm ) NonceSize () int {
return g .nonceSize
}
func (g *gcmAsm ) Overhead () int {
return g .tagSize
}
func sliceForAppend (in []byte , n int ) (head , tail []byte ) {
if total := len (in ) + n ; cap (in ) >= total {
head = in [:total ]
} else {
head = make ([]byte , total )
copy (head , in )
}
tail = head [len (in ):]
return
}
func (g *gcmAsm ) Seal (dst , nonce , plaintext , data []byte ) []byte {
if len (nonce ) != g .nonceSize {
panic ("crypto/cipher: incorrect nonce length given to GCM" )
}
if uint64 (len (plaintext )) > ((1 <<32 )-2 )*BlockSize {
panic ("crypto/cipher: message too large for GCM" )
}
var counter , tagMask [gcmBlockSize ]byte
if len (nonce ) == gcmStandardNonceSize {
copy (counter [:], nonce )
counter [gcmBlockSize -1 ] = 1
} else {
gcmAesData (&g .productTable , nonce , &counter )
gcmAesFinish (&g .productTable , &tagMask , &counter , uint64 (len (nonce )), uint64 (0 ))
}
encryptBlockAsm (len (g .ks )/4 -1 , &g .ks [0 ], &tagMask [0 ], &counter [0 ])
var tagOut [gcmTagSize ]byte
gcmAesData (&g .productTable , data , &tagOut )
ret , out := sliceForAppend (dst , len (plaintext )+g .tagSize )
if alias .InexactOverlap (out [:len (plaintext )], plaintext ) {
panic ("crypto/cipher: invalid buffer overlap" )
}
if len (plaintext ) > 0 {
gcmAesEnc (&g .productTable , out , plaintext , &counter , &tagOut , g .ks )
}
gcmAesFinish (&g .productTable , &tagMask , &tagOut , uint64 (len (plaintext )), uint64 (len (data )))
copy (out [len (plaintext ):], tagOut [:])
return ret
}
func (g *gcmAsm ) Open (dst , nonce , ciphertext , data []byte ) ([]byte , error ) {
if len (nonce ) != g .nonceSize {
panic ("crypto/cipher: incorrect nonce length given to GCM" )
}
if g .tagSize < gcmMinimumTagSize {
panic ("crypto/cipher: incorrect GCM tag size" )
}
if len (ciphertext ) < g .tagSize {
return nil , errOpen
}
if uint64 (len (ciphertext )) > ((1 <<32 )-2 )*uint64 (BlockSize )+uint64 (g .tagSize ) {
return nil , errOpen
}
tag := ciphertext [len (ciphertext )-g .tagSize :]
ciphertext = ciphertext [:len (ciphertext )-g .tagSize ]
var counter , tagMask [gcmBlockSize ]byte
if len (nonce ) == gcmStandardNonceSize {
copy (counter [:], nonce )
counter [gcmBlockSize -1 ] = 1
} else {
gcmAesData (&g .productTable , nonce , &counter )
gcmAesFinish (&g .productTable , &tagMask , &counter , uint64 (len (nonce )), uint64 (0 ))
}
encryptBlockAsm (len (g .ks )/4 -1 , &g .ks [0 ], &tagMask [0 ], &counter [0 ])
var expectedTag [gcmTagSize ]byte
gcmAesData (&g .productTable , data , &expectedTag )
ret , out := sliceForAppend (dst , len (ciphertext ))
if alias .InexactOverlap (out , ciphertext ) {
panic ("crypto/cipher: invalid buffer overlap" )
}
if len (ciphertext ) > 0 {
gcmAesDec (&g .productTable , out , ciphertext , &counter , &expectedTag , g .ks )
}
gcmAesFinish (&g .productTable , &tagMask , &expectedTag , uint64 (len (ciphertext )), uint64 (len (data )))
if subtle .ConstantTimeCompare (expectedTag [:g .tagSize ], tag ) != 1 {
for i := range out {
out [i ] = 0
}
return nil , errOpen
}
return ret , nil
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .