github.com/fiagdao/tendermint@v0.32.11-0.20220824195748-2087fcc480c1/crypto/xchacha20poly1305/xchachapoly.go (about) 1 // Package xchacha20poly1305 creates an AEAD using hchacha, chacha, and poly1305 2 // This allows for randomized nonces to be used in conjunction with chacha. 3 package xchacha20poly1305 4 5 import ( 6 "crypto/cipher" 7 "encoding/binary" 8 "errors" 9 "fmt" 10 11 "golang.org/x/crypto/chacha20poly1305" 12 ) 13 14 // Implements crypto.AEAD 15 type xchacha20poly1305 struct { 16 key [KeySize]byte 17 } 18 19 const ( 20 // KeySize is the size of the key used by this AEAD, in bytes. 21 KeySize = 32 22 // NonceSize is the size of the nonce used with this AEAD, in bytes. 23 NonceSize = 24 24 // TagSize is the size added from poly1305 25 TagSize = 16 26 // MaxPlaintextSize is the max size that can be passed into a single call of Seal 27 MaxPlaintextSize = (1 << 38) - 64 28 // MaxCiphertextSize is the max size that can be passed into a single call of Open, 29 // this differs from plaintext size due to the tag 30 MaxCiphertextSize = (1 << 38) - 48 31 32 // sigma are constants used in xchacha. 33 // Unrolled from a slice so that they can be inlined, as slices can't be constants. 34 sigma0 = uint32(0x61707865) 35 sigma1 = uint32(0x3320646e) 36 sigma2 = uint32(0x79622d32) 37 sigma3 = uint32(0x6b206574) 38 ) 39 40 // New returns a new xchachapoly1305 AEAD 41 func New(key []byte) (cipher.AEAD, error) { 42 if len(key) != KeySize { 43 return nil, errors.New("xchacha20poly1305: bad key length") 44 } 45 ret := new(xchacha20poly1305) 46 copy(ret.key[:], key) 47 return ret, nil 48 } 49 50 // nolint 51 func (c *xchacha20poly1305) NonceSize() int { 52 return NonceSize 53 } 54 55 // nolint 56 func (c *xchacha20poly1305) Overhead() int { 57 return TagSize 58 } 59 60 func (c *xchacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte { 61 if len(nonce) != NonceSize { 62 panic("xchacha20poly1305: bad nonce length passed to Seal") 63 } 64 65 if uint64(len(plaintext)) > MaxPlaintextSize { 66 panic("xchacha20poly1305: plaintext too large") 67 } 68 69 var subKey [KeySize]byte 70 var hNonce [16]byte 71 var subNonce [chacha20poly1305.NonceSize]byte 72 copy(hNonce[:], nonce[:16]) 73 74 HChaCha20(&subKey, &hNonce, &c.key) 75 76 // This can't error because we always provide a correctly sized key 77 chacha20poly1305, _ := chacha20poly1305.New(subKey[:]) 78 79 copy(subNonce[4:], nonce[16:]) 80 81 return chacha20poly1305.Seal(dst, subNonce[:], plaintext, additionalData) 82 } 83 84 func (c *xchacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) { 85 if len(nonce) != NonceSize { 86 return nil, fmt.Errorf("xchacha20poly1305: bad nonce length passed to Open") 87 } 88 if uint64(len(ciphertext)) > MaxCiphertextSize { 89 return nil, fmt.Errorf("xchacha20poly1305: ciphertext too large") 90 } 91 var subKey [KeySize]byte 92 var hNonce [16]byte 93 var subNonce [chacha20poly1305.NonceSize]byte 94 copy(hNonce[:], nonce[:16]) 95 96 HChaCha20(&subKey, &hNonce, &c.key) 97 98 // This can't error because we always provide a correctly sized key 99 chacha20poly1305, _ := chacha20poly1305.New(subKey[:]) 100 101 copy(subNonce[4:], nonce[16:]) 102 103 return chacha20poly1305.Open(dst, subNonce[:], ciphertext, additionalData) 104 } 105 106 // HChaCha exported from 107 // https://github.com/aead/chacha20/blob/8b13a72661dae6e9e5dea04f344f0dc95ea29547/chacha/chacha_generic.go#L194 108 // TODO: Add support for the different assembly instructions used there. 109 110 // The MIT License (MIT) 111 112 // Copyright (c) 2016 Andreas Auernhammer 113 114 // Permission is hereby granted, free of charge, to any person obtaining a copy 115 // of this software and associated documentation files (the "Software"), to deal 116 // in the Software without restriction, including without limitation the rights 117 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 118 // copies of the Software, and to permit persons to whom the Software is 119 // furnished to do so, subject to the following conditions: 120 121 // The above copyright notice and this permission notice shall be included in all 122 // copies or substantial portions of the Software. 123 124 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 125 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 126 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 127 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 128 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 129 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 130 // SOFTWARE. 131 132 // HChaCha20 generates 32 pseudo-random bytes from a 128 bit nonce and a 256 bit secret key. 133 // It can be used as a key-derivation-function (KDF). 134 func HChaCha20(out *[32]byte, nonce *[16]byte, key *[32]byte) { hChaCha20Generic(out, nonce, key) } 135 136 func hChaCha20Generic(out *[32]byte, nonce *[16]byte, key *[32]byte) { 137 v00 := sigma0 138 v01 := sigma1 139 v02 := sigma2 140 v03 := sigma3 141 v04 := binary.LittleEndian.Uint32(key[0:]) 142 v05 := binary.LittleEndian.Uint32(key[4:]) 143 v06 := binary.LittleEndian.Uint32(key[8:]) 144 v07 := binary.LittleEndian.Uint32(key[12:]) 145 v08 := binary.LittleEndian.Uint32(key[16:]) 146 v09 := binary.LittleEndian.Uint32(key[20:]) 147 v10 := binary.LittleEndian.Uint32(key[24:]) 148 v11 := binary.LittleEndian.Uint32(key[28:]) 149 v12 := binary.LittleEndian.Uint32(nonce[0:]) 150 v13 := binary.LittleEndian.Uint32(nonce[4:]) 151 v14 := binary.LittleEndian.Uint32(nonce[8:]) 152 v15 := binary.LittleEndian.Uint32(nonce[12:]) 153 154 for i := 0; i < 20; i += 2 { 155 v00 += v04 156 v12 ^= v00 157 v12 = (v12 << 16) | (v12 >> 16) 158 v08 += v12 159 v04 ^= v08 160 v04 = (v04 << 12) | (v04 >> 20) 161 v00 += v04 162 v12 ^= v00 163 v12 = (v12 << 8) | (v12 >> 24) 164 v08 += v12 165 v04 ^= v08 166 v04 = (v04 << 7) | (v04 >> 25) 167 v01 += v05 168 v13 ^= v01 169 v13 = (v13 << 16) | (v13 >> 16) 170 v09 += v13 171 v05 ^= v09 172 v05 = (v05 << 12) | (v05 >> 20) 173 v01 += v05 174 v13 ^= v01 175 v13 = (v13 << 8) | (v13 >> 24) 176 v09 += v13 177 v05 ^= v09 178 v05 = (v05 << 7) | (v05 >> 25) 179 v02 += v06 180 v14 ^= v02 181 v14 = (v14 << 16) | (v14 >> 16) 182 v10 += v14 183 v06 ^= v10 184 v06 = (v06 << 12) | (v06 >> 20) 185 v02 += v06 186 v14 ^= v02 187 v14 = (v14 << 8) | (v14 >> 24) 188 v10 += v14 189 v06 ^= v10 190 v06 = (v06 << 7) | (v06 >> 25) 191 v03 += v07 192 v15 ^= v03 193 v15 = (v15 << 16) | (v15 >> 16) 194 v11 += v15 195 v07 ^= v11 196 v07 = (v07 << 12) | (v07 >> 20) 197 v03 += v07 198 v15 ^= v03 199 v15 = (v15 << 8) | (v15 >> 24) 200 v11 += v15 201 v07 ^= v11 202 v07 = (v07 << 7) | (v07 >> 25) 203 v00 += v05 204 v15 ^= v00 205 v15 = (v15 << 16) | (v15 >> 16) 206 v10 += v15 207 v05 ^= v10 208 v05 = (v05 << 12) | (v05 >> 20) 209 v00 += v05 210 v15 ^= v00 211 v15 = (v15 << 8) | (v15 >> 24) 212 v10 += v15 213 v05 ^= v10 214 v05 = (v05 << 7) | (v05 >> 25) 215 v01 += v06 216 v12 ^= v01 217 v12 = (v12 << 16) | (v12 >> 16) 218 v11 += v12 219 v06 ^= v11 220 v06 = (v06 << 12) | (v06 >> 20) 221 v01 += v06 222 v12 ^= v01 223 v12 = (v12 << 8) | (v12 >> 24) 224 v11 += v12 225 v06 ^= v11 226 v06 = (v06 << 7) | (v06 >> 25) 227 v02 += v07 228 v13 ^= v02 229 v13 = (v13 << 16) | (v13 >> 16) 230 v08 += v13 231 v07 ^= v08 232 v07 = (v07 << 12) | (v07 >> 20) 233 v02 += v07 234 v13 ^= v02 235 v13 = (v13 << 8) | (v13 >> 24) 236 v08 += v13 237 v07 ^= v08 238 v07 = (v07 << 7) | (v07 >> 25) 239 v03 += v04 240 v14 ^= v03 241 v14 = (v14 << 16) | (v14 >> 16) 242 v09 += v14 243 v04 ^= v09 244 v04 = (v04 << 12) | (v04 >> 20) 245 v03 += v04 246 v14 ^= v03 247 v14 = (v14 << 8) | (v14 >> 24) 248 v09 += v14 249 v04 ^= v09 250 v04 = (v04 << 7) | (v04 >> 25) 251 } 252 253 binary.LittleEndian.PutUint32(out[0:], v00) 254 binary.LittleEndian.PutUint32(out[4:], v01) 255 binary.LittleEndian.PutUint32(out[8:], v02) 256 binary.LittleEndian.PutUint32(out[12:], v03) 257 binary.LittleEndian.PutUint32(out[16:], v12) 258 binary.LittleEndian.PutUint32(out[20:], v13) 259 binary.LittleEndian.PutUint32(out[24:], v14) 260 binary.LittleEndian.PutUint32(out[28:], v15) 261 }