chacha20poly1305_test.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. // Copyright 2016 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package chacha20poly1305
  5. import (
  6. "bytes"
  7. "crypto/cipher"
  8. cryptorand "crypto/rand"
  9. "encoding/hex"
  10. "fmt"
  11. "log"
  12. mathrand "math/rand"
  13. "strconv"
  14. "testing"
  15. )
  16. func TestVectors(t *testing.T) {
  17. for i, test := range chacha20Poly1305Tests {
  18. key, _ := hex.DecodeString(test.key)
  19. nonce, _ := hex.DecodeString(test.nonce)
  20. ad, _ := hex.DecodeString(test.aad)
  21. plaintext, _ := hex.DecodeString(test.plaintext)
  22. var (
  23. aead cipher.AEAD
  24. err error
  25. )
  26. switch len(nonce) {
  27. case NonceSize:
  28. aead, err = New(key)
  29. case NonceSizeX:
  30. aead, err = NewX(key)
  31. default:
  32. t.Fatalf("#%d: wrong nonce length: %d", i, len(nonce))
  33. }
  34. if err != nil {
  35. t.Fatal(err)
  36. }
  37. ct := aead.Seal(nil, nonce, plaintext, ad)
  38. if ctHex := hex.EncodeToString(ct); ctHex != test.out {
  39. t.Errorf("#%d: got %s, want %s", i, ctHex, test.out)
  40. continue
  41. }
  42. plaintext2, err := aead.Open(nil, nonce, ct, ad)
  43. if err != nil {
  44. t.Errorf("#%d: Open failed", i)
  45. continue
  46. }
  47. if !bytes.Equal(plaintext, plaintext2) {
  48. t.Errorf("#%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext)
  49. continue
  50. }
  51. if len(ad) > 0 {
  52. alterAdIdx := mathrand.Intn(len(ad))
  53. ad[alterAdIdx] ^= 0x80
  54. if _, err := aead.Open(nil, nonce, ct, ad); err == nil {
  55. t.Errorf("#%d: Open was successful after altering additional data", i)
  56. }
  57. ad[alterAdIdx] ^= 0x80
  58. }
  59. alterNonceIdx := mathrand.Intn(aead.NonceSize())
  60. nonce[alterNonceIdx] ^= 0x80
  61. if _, err := aead.Open(nil, nonce, ct, ad); err == nil {
  62. t.Errorf("#%d: Open was successful after altering nonce", i)
  63. }
  64. nonce[alterNonceIdx] ^= 0x80
  65. alterCtIdx := mathrand.Intn(len(ct))
  66. ct[alterCtIdx] ^= 0x80
  67. if _, err := aead.Open(nil, nonce, ct, ad); err == nil {
  68. t.Errorf("#%d: Open was successful after altering ciphertext", i)
  69. }
  70. ct[alterCtIdx] ^= 0x80
  71. }
  72. }
  73. func TestRandom(t *testing.T) {
  74. // Some random tests to verify Open(Seal) == Plaintext
  75. f := func(t *testing.T, nonceSize int) {
  76. for i := 0; i < 256; i++ {
  77. var nonce = make([]byte, nonceSize)
  78. var key [32]byte
  79. al := mathrand.Intn(128)
  80. pl := mathrand.Intn(16384)
  81. ad := make([]byte, al)
  82. plaintext := make([]byte, pl)
  83. cryptorand.Read(key[:])
  84. cryptorand.Read(nonce[:])
  85. cryptorand.Read(ad)
  86. cryptorand.Read(plaintext)
  87. var (
  88. aead cipher.AEAD
  89. err error
  90. )
  91. switch len(nonce) {
  92. case NonceSize:
  93. aead, err = New(key[:])
  94. case NonceSizeX:
  95. aead, err = NewX(key[:])
  96. default:
  97. t.Fatalf("#%d: wrong nonce length: %d", i, len(nonce))
  98. }
  99. if err != nil {
  100. t.Fatal(err)
  101. }
  102. ct := aead.Seal(nil, nonce[:], plaintext, ad)
  103. plaintext2, err := aead.Open(nil, nonce[:], ct, ad)
  104. if err != nil {
  105. t.Errorf("Random #%d: Open failed", i)
  106. continue
  107. }
  108. if !bytes.Equal(plaintext, plaintext2) {
  109. t.Errorf("Random #%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext)
  110. continue
  111. }
  112. if len(ad) > 0 {
  113. alterAdIdx := mathrand.Intn(len(ad))
  114. ad[alterAdIdx] ^= 0x80
  115. if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
  116. t.Errorf("Random #%d: Open was successful after altering additional data", i)
  117. }
  118. ad[alterAdIdx] ^= 0x80
  119. }
  120. alterNonceIdx := mathrand.Intn(aead.NonceSize())
  121. nonce[alterNonceIdx] ^= 0x80
  122. if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
  123. t.Errorf("Random #%d: Open was successful after altering nonce", i)
  124. }
  125. nonce[alterNonceIdx] ^= 0x80
  126. alterCtIdx := mathrand.Intn(len(ct))
  127. ct[alterCtIdx] ^= 0x80
  128. if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
  129. t.Errorf("Random #%d: Open was successful after altering ciphertext", i)
  130. }
  131. ct[alterCtIdx] ^= 0x80
  132. }
  133. }
  134. t.Run("Standard", func(t *testing.T) { f(t, NonceSize) })
  135. t.Run("X", func(t *testing.T) { f(t, NonceSizeX) })
  136. }
  137. func benchamarkChaCha20Poly1305Seal(b *testing.B, buf []byte, nonceSize int) {
  138. b.ReportAllocs()
  139. b.SetBytes(int64(len(buf)))
  140. var key [32]byte
  141. var nonce = make([]byte, nonceSize)
  142. var ad [13]byte
  143. var out []byte
  144. var aead cipher.AEAD
  145. switch len(nonce) {
  146. case NonceSize:
  147. aead, _ = New(key[:])
  148. case NonceSizeX:
  149. aead, _ = NewX(key[:])
  150. }
  151. b.ResetTimer()
  152. for i := 0; i < b.N; i++ {
  153. out = aead.Seal(out[:0], nonce[:], buf[:], ad[:])
  154. }
  155. }
  156. func benchamarkChaCha20Poly1305Open(b *testing.B, buf []byte, nonceSize int) {
  157. b.ReportAllocs()
  158. b.SetBytes(int64(len(buf)))
  159. var key [32]byte
  160. var nonce = make([]byte, nonceSize)
  161. var ad [13]byte
  162. var ct []byte
  163. var out []byte
  164. var aead cipher.AEAD
  165. switch len(nonce) {
  166. case NonceSize:
  167. aead, _ = New(key[:])
  168. case NonceSizeX:
  169. aead, _ = NewX(key[:])
  170. }
  171. ct = aead.Seal(ct[:0], nonce[:], buf[:], ad[:])
  172. b.ResetTimer()
  173. for i := 0; i < b.N; i++ {
  174. out, _ = aead.Open(out[:0], nonce[:], ct[:], ad[:])
  175. }
  176. }
  177. func BenchmarkChacha20Poly1305(b *testing.B) {
  178. for _, length := range []int{64, 1350, 8 * 1024} {
  179. b.Run("Open-"+strconv.Itoa(length), func(b *testing.B) {
  180. benchamarkChaCha20Poly1305Open(b, make([]byte, length), NonceSize)
  181. })
  182. b.Run("Seal-"+strconv.Itoa(length), func(b *testing.B) {
  183. benchamarkChaCha20Poly1305Seal(b, make([]byte, length), NonceSize)
  184. })
  185. b.Run("Open-"+strconv.Itoa(length)+"-X", func(b *testing.B) {
  186. benchamarkChaCha20Poly1305Open(b, make([]byte, length), NonceSizeX)
  187. })
  188. b.Run("Seal-"+strconv.Itoa(length)+"-X", func(b *testing.B) {
  189. benchamarkChaCha20Poly1305Seal(b, make([]byte, length), NonceSizeX)
  190. })
  191. }
  192. }
  193. var key = make([]byte, KeySize)
  194. func ExampleNewX() {
  195. aead, err := NewX(key)
  196. if err != nil {
  197. log.Fatalln("Failed to instantiate XChaCha20-Poly1305:", err)
  198. }
  199. for _, msg := range []string{
  200. "Attack at dawn.",
  201. "The eagle has landed.",
  202. "Gophers, gophers, gophers everywhere!",
  203. } {
  204. // Encryption.
  205. nonce := make([]byte, NonceSizeX)
  206. if _, err := cryptorand.Read(nonce); err != nil {
  207. panic(err)
  208. }
  209. ciphertext := aead.Seal(nil, nonce, []byte(msg), nil)
  210. // Decryption.
  211. plaintext, err := aead.Open(nil, nonce, ciphertext, nil)
  212. if err != nil {
  213. log.Fatalln("Failed to decrypt or authenticate message:", err)
  214. }
  215. fmt.Printf("%s\n", plaintext)
  216. }
  217. // Output: Attack at dawn.
  218. // The eagle has landed.
  219. // Gophers, gophers, gophers everywhere!
  220. }