github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/crypto/aes/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 // +build amd64 6 7 package aes 8 9 import ( 10 "crypto/cipher" 11 "crypto/subtle" 12 "errors" 13 ) 14 15 // The following functions are defined in gcm_amd64.s. 16 func hasGCMAsm() bool 17 func aesEncBlock(dst, src *[16]byte, ks []uint32) 18 func gcmAesInit(productTable *[256]byte, ks []uint32) 19 func gcmAesData(productTable *[256]byte, data []byte, T *[16]byte) 20 func gcmAesEnc(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32) 21 func gcmAesDec(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32) 22 func gcmAesFinish(productTable *[256]byte, tagMask, T *[16]byte, pLen, dLen uint64) 23 24 const ( 25 gcmBlockSize = 16 26 gcmTagSize = 16 27 gcmStandardNonceSize = 12 28 ) 29 30 var errOpen = errors.New("cipher: message authentication failed") 31 32 // aesCipherGCM implements crypto/cipher.gcmAble so that crypto/cipher.NewGCM 33 // will use the optimised implementation in this file when possible. Instances 34 // of this type only exist when hasGCMAsm returns true. 35 type aesCipherGCM struct { 36 aesCipher 37 } 38 39 // NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only 40 // called by crypto/cipher.NewGCM via the gcmAble interface. 41 func (c *aesCipherGCM) NewGCM(nonceSize int) (cipher.AEAD, error) { 42 g := &gcmAsm{ks: c.enc, nonceSize: nonceSize} 43 gcmAesInit(&g.productTable, g.ks) 44 return g, nil 45 } 46 47 type gcmAsm struct { 48 // ks is the key schedule, the length of which depends on the size of 49 // the AES key. 50 ks []uint32 51 // productTable contains pre-computed multiples of the binary-field 52 // element used in GHASH. 53 productTable [256]byte 54 // nonceSize contains the expected size of the nonce, in bytes. 55 nonceSize int 56 } 57 58 func (g *gcmAsm) NonceSize() int { 59 return g.nonceSize 60 } 61 62 func (*gcmAsm) Overhead() int { 63 return gcmTagSize 64 } 65 66 // sliceForAppend takes a slice and a requested number of bytes. It returns a 67 // slice with the contents of the given slice followed by that many bytes and a 68 // second slice that aliases into it and contains only the extra bytes. If the 69 // original slice has sufficient capacity then no allocation is performed. 70 func sliceForAppend(in []byte, n int) (head, tail []byte) { 71 if total := len(in) + n; cap(in) >= total { 72 head = in[:total] 73 } else { 74 head = make([]byte, total) 75 copy(head, in) 76 } 77 tail = head[len(in):] 78 return 79 } 80 81 // Seal encrypts and authenticates plaintext. See the cipher.AEAD interface for 82 // details. 83 func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { 84 if len(nonce) != g.nonceSize { 85 panic("cipher: incorrect nonce length given to GCM") 86 } 87 88 var counter, tagMask [gcmBlockSize]byte 89 90 if len(nonce) == gcmStandardNonceSize { 91 // Init counter to nonce||1 92 copy(counter[:], nonce) 93 counter[gcmBlockSize-1] = 1 94 } else { 95 // Otherwise counter = GHASH(nonce) 96 gcmAesData(&g.productTable, nonce, &counter) 97 gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0)) 98 } 99 100 aesEncBlock(&tagMask, &counter, g.ks) 101 102 var tagOut [gcmTagSize]byte 103 gcmAesData(&g.productTable, data, &tagOut) 104 105 ret, out := sliceForAppend(dst, len(plaintext)+gcmTagSize) 106 if len(plaintext) > 0 { 107 gcmAesEnc(&g.productTable, out, plaintext, &counter, &tagOut, g.ks) 108 } 109 gcmAesFinish(&g.productTable, &tagMask, &tagOut, uint64(len(plaintext)), uint64(len(data))) 110 copy(out[len(plaintext):], tagOut[:]) 111 112 return ret 113 } 114 115 // Open authenticates and decrypts ciphertext. See the cipher.AEAD interface 116 // for details. 117 func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { 118 if len(nonce) != g.nonceSize { 119 panic("cipher: incorrect nonce length given to GCM") 120 } 121 122 if len(ciphertext) < gcmTagSize { 123 return nil, errOpen 124 } 125 tag := ciphertext[len(ciphertext)-gcmTagSize:] 126 ciphertext = ciphertext[:len(ciphertext)-gcmTagSize] 127 128 // See GCM spec, section 7.1. 129 var counter, tagMask [gcmBlockSize]byte 130 131 if len(nonce) == gcmStandardNonceSize { 132 // Init counter to nonce||1 133 copy(counter[:], nonce) 134 counter[gcmBlockSize-1] = 1 135 } else { 136 // Otherwise counter = GHASH(nonce) 137 gcmAesData(&g.productTable, nonce, &counter) 138 gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0)) 139 } 140 141 aesEncBlock(&tagMask, &counter, g.ks) 142 143 var expectedTag [gcmTagSize]byte 144 gcmAesData(&g.productTable, data, &expectedTag) 145 146 ret, out := sliceForAppend(dst, len(ciphertext)) 147 if len(ciphertext) > 0 { 148 gcmAesDec(&g.productTable, out, ciphertext, &counter, &expectedTag, g.ks) 149 } 150 gcmAesFinish(&g.productTable, &tagMask, &expectedTag, uint64(len(ciphertext)), uint64(len(data))) 151 152 if subtle.ConstantTimeCompare(expectedTag[:], tag) != 1 { 153 for i := range out { 154 out[i] = 0 155 } 156 return nil, errOpen 157 } 158 159 return ret, nil 160 }