You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

261 lines
7.4 KiB

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