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.

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