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.

238 lines
6.3 KiB

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