github.com/mad-day/Yawning-crypto@v0.0.0-20190711051033-5a5f8cca32ec/bsaes/internal/modes/gcm.go (about) 1 // Copyright (c) 2016 Thomas Pornin <pornin@bolet.org> 2 // Copyright (c) 2017 Yawning Angel <yawning at schwanenlied dot me> 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining 5 // a copy of this software and associated documentation files (the 6 // "Software"), to deal in the Software without restriction, including 7 // without limitation the rights to use, copy, modify, merge, publish, 8 // distribute, sublicense, and/or sell copies of the Software, and to 9 // permit persons to whom the Software is furnished to do so, subject to 10 // the following conditions: 11 // 12 // The above copyright notice and this permission notice shall be 13 // included in all copies or substantial portions of the Software. 14 // 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 // SOFTWARE. 23 24 package modes 25 26 import ( 27 "crypto/cipher" 28 "crypto/subtle" 29 "encoding/binary" 30 "errors" 31 32 "github.com/mad-day/Yawning-crypto/bsaes/ghash" 33 ) 34 35 const ( 36 gcmNonceSize = 96 / 8 37 gcmTagSize = 16 38 ) 39 40 func (m *BlockModesImpl) NewGCM(size int) (cipher.AEAD, error) { 41 ecb := m.b.(bulkECBAble) 42 if ecb.BlockSize() != blockSize { 43 return nil, errors.New("bsaes/NewGCM: GCM requires 128 bit block sizes") 44 } 45 46 return newGCMImpl(ecb, size), nil 47 } 48 49 type gcmImpl struct { 50 ecb bulkECBAble 51 52 nonceSize int 53 stride int 54 } 55 56 func (g *gcmImpl) NonceSize() int { 57 return g.nonceSize 58 } 59 60 func (g *gcmImpl) Overhead() int { 61 return gcmTagSize 62 } 63 64 func (g *gcmImpl) deriveNonceVals(h, j, preCounterBlock *[blockSize]byte, nonce []byte) { 65 g.ecb.Encrypt(h[:], h[:]) 66 if len(nonce) == gcmNonceSize { 67 copy(j[:], nonce[:gcmNonceSize]) 68 j[blockSize-1] = 1 69 } else { 70 var p [blockSize]byte 71 ghash.Ghash(j, h, nonce) 72 binary.BigEndian.PutUint32(p[12:], uint32(len(nonce))<<3) 73 ghash.Ghash(j, h, p[:]) 74 } 75 g.ecb.Encrypt(preCounterBlock[:], j[:]) 76 } 77 78 func (g *gcmImpl) gctr(iv *[blockSize]byte, dst, src []byte) { 79 idx := g.stride * blockSize 80 buf := make([]byte, g.stride*blockSize) 81 inc32(iv) 82 83 for len(src) > 0 { 84 if idx >= len(buf) { 85 for i := 0; i < g.stride; i++ { 86 copy(buf[i*blockSize:], iv[:]) 87 inc32(iv) 88 } 89 g.ecb.BulkEncrypt(buf, buf) 90 idx = 0 91 } 92 93 n := len(buf) - idx 94 if sLen := len(src); sLen < n { 95 n = sLen 96 } 97 for i, v := range src[:n] { 98 dst[i] = v ^ buf[idx+i] 99 } 100 101 dst, src = dst[n:], src[n:] 102 idx += n 103 } 104 105 for i := range buf { 106 buf[i] = 0 107 } 108 } 109 110 func (g *gcmImpl) Seal(dst, nonce, plaintext, additionalData []byte) []byte { 111 if len(nonce) != g.nonceSize { 112 panic("bsaes/gcmImpl.Seal: nonce with invalid size provided") 113 } 114 115 // Yes, this always allocates. It makes life easier. 116 sz := len(plaintext) 117 if uint64(sz) > 0xfffffffe0 { // len(P) <= 2^39 - 256 (bits) 118 panic("bsaes/gcmImpl.Seal: plaintext too large") 119 } 120 out := make([]byte, sz+gcmTagSize) 121 122 // Define H, block J0, and the pre-counter block. 123 var h, j, preCounterBlock [blockSize]byte 124 g.deriveNonceVals(&h, &j, &preCounterBlock, nonce) 125 126 // Let C=GCTR K(inc32(J0), P). 127 g.gctr(&j, out, plaintext) 128 129 // S = GHASH H (A || 0 v || C || 0 u || [len(A)] 64 || [len(C)] 64). 130 var s, p [blockSize]byte 131 ghash.Ghash(&s, &h, additionalData) 132 ghash.Ghash(&s, &h, out[:sz]) 133 binary.BigEndian.PutUint32(p[4:], uint32(len(additionalData))<<3) 134 binary.BigEndian.PutUint32(p[12:], uint32(sz)<<3) 135 ghash.Ghash(&s, &h, p[:]) 136 137 // Let T = MSB t(GCTR K(J0, S)) 138 for i, v := range preCounterBlock { 139 out[sz+i] = s[i] ^ v 140 } 141 142 dst = append(dst, out...) 143 return dst 144 } 145 146 var errFail = errors.New("cipher: message authentication failed") 147 148 func (g *gcmImpl) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) { 149 if len(nonce) != g.nonceSize { 150 panic("bsaes/gcmImpl.Seal: nonce with invalid size provided") 151 } 152 153 sz := len(ciphertext) 154 if sz < gcmTagSize { 155 return nil, errFail 156 } 157 sz -= gcmTagSize 158 if uint64(sz) > 0xfffffffe0 { 159 return nil, errFail 160 } 161 162 // Define H, block J0, and the pre-counter block. 163 var h, j, preCounterBlock [blockSize]byte 164 g.deriveNonceVals(&h, &j, &preCounterBlock, nonce) 165 166 // S = GHASH H (A || 0 v || C || 0 u || [len(A)] 64 || [len(C)] 64). 167 var s, p [blockSize]byte 168 ghash.Ghash(&s, &h, additionalData) 169 ghash.Ghash(&s, &h, ciphertext[:sz]) 170 binary.BigEndian.PutUint32(p[4:], uint32(len(additionalData))<<3) 171 binary.BigEndian.PutUint32(p[12:], uint32(sz)<<3) 172 ghash.Ghash(&s, &h, p[:]) 173 for i, v := range preCounterBlock { 174 s[i] ^= v 175 } 176 177 if subtle.ConstantTimeCompare(s[:], ciphertext[sz:]) != 1 { 178 return nil, errFail 179 } 180 181 out := make([]byte, sz) 182 g.gctr(&j, out, ciphertext[:sz]) 183 dst = append(dst, out...) 184 185 return dst, nil 186 } 187 188 func inc32(ctr *[blockSize]byte) { 189 v := binary.BigEndian.Uint32(ctr[12:]) + 1 190 binary.BigEndian.PutUint32(ctr[12:], v) 191 } 192 193 func newGCMImpl(ecb bulkECBAble, size int) cipher.AEAD { 194 g := new(gcmImpl) 195 g.ecb = ecb 196 g.nonceSize = size 197 g.stride = g.ecb.Stride() 198 return g 199 }