| // Copyright 2016 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package chacha20poly1305 |
| |
| import ( |
| "bytes" |
| cr "crypto/rand" |
| "encoding/hex" |
| mr "math/rand" |
| "testing" |
| ) |
| |
| func TestVectors(t *testing.T) { |
| for i, test := range chacha20Poly1305Tests { |
| key, _ := hex.DecodeString(test.key) |
| nonce, _ := hex.DecodeString(test.nonce) |
| ad, _ := hex.DecodeString(test.aad) |
| plaintext, _ := hex.DecodeString(test.plaintext) |
| |
| aead, err := New(key) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| ct := aead.Seal(nil, nonce, plaintext, ad) |
| if ctHex := hex.EncodeToString(ct); ctHex != test.out { |
| t.Errorf("#%d: got %s, want %s", i, ctHex, test.out) |
| continue |
| } |
| |
| plaintext2, err := aead.Open(nil, nonce, ct, ad) |
| if err != nil { |
| t.Errorf("#%d: Open failed", i) |
| continue |
| } |
| |
| if !bytes.Equal(plaintext, plaintext2) { |
| t.Errorf("#%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext) |
| continue |
| } |
| |
| if len(ad) > 0 { |
| alterAdIdx := mr.Intn(len(ad)) |
| ad[alterAdIdx] ^= 0x80 |
| if _, err := aead.Open(nil, nonce, ct, ad); err == nil { |
| t.Errorf("#%d: Open was successful after altering additional data", i) |
| } |
| ad[alterAdIdx] ^= 0x80 |
| } |
| |
| alterNonceIdx := mr.Intn(aead.NonceSize()) |
| nonce[alterNonceIdx] ^= 0x80 |
| if _, err := aead.Open(nil, nonce, ct, ad); err == nil { |
| t.Errorf("#%d: Open was successful after altering nonce", i) |
| } |
| nonce[alterNonceIdx] ^= 0x80 |
| |
| alterCtIdx := mr.Intn(len(ct)) |
| ct[alterCtIdx] ^= 0x80 |
| if _, err := aead.Open(nil, nonce, ct, ad); err == nil { |
| t.Errorf("#%d: Open was successful after altering ciphertext", i) |
| } |
| ct[alterCtIdx] ^= 0x80 |
| } |
| } |
| |
| func TestRandom(t *testing.T) { |
| // Some random tests to verify Open(Seal) == Plaintext |
| for i := 0; i < 256; i++ { |
| var nonce [12]byte |
| var key [32]byte |
| |
| al := mr.Intn(128) |
| pl := mr.Intn(16384) |
| ad := make([]byte, al) |
| plaintext := make([]byte, pl) |
| cr.Read(key[:]) |
| cr.Read(nonce[:]) |
| cr.Read(ad) |
| cr.Read(plaintext) |
| |
| aead, err := New(key[:]) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| ct := aead.Seal(nil, nonce[:], plaintext, ad) |
| |
| plaintext2, err := aead.Open(nil, nonce[:], ct, ad) |
| if err != nil { |
| t.Errorf("Random #%d: Open failed", i) |
| continue |
| } |
| |
| if !bytes.Equal(plaintext, plaintext2) { |
| t.Errorf("Random #%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext) |
| continue |
| } |
| |
| if len(ad) > 0 { |
| alterAdIdx := mr.Intn(len(ad)) |
| ad[alterAdIdx] ^= 0x80 |
| if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil { |
| t.Errorf("Random #%d: Open was successful after altering additional data", i) |
| } |
| ad[alterAdIdx] ^= 0x80 |
| } |
| |
| alterNonceIdx := mr.Intn(aead.NonceSize()) |
| nonce[alterNonceIdx] ^= 0x80 |
| if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil { |
| t.Errorf("Random #%d: Open was successful after altering nonce", i) |
| } |
| nonce[alterNonceIdx] ^= 0x80 |
| |
| alterCtIdx := mr.Intn(len(ct)) |
| ct[alterCtIdx] ^= 0x80 |
| if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil { |
| t.Errorf("Random #%d: Open was successful after altering ciphertext", i) |
| } |
| ct[alterCtIdx] ^= 0x80 |
| } |
| } |
| |
| func benchamarkChaCha20Poly1305Seal(b *testing.B, buf []byte) { |
| b.SetBytes(int64(len(buf))) |
| |
| var key [32]byte |
| var nonce [12]byte |
| var ad [13]byte |
| var out []byte |
| |
| aead, _ := New(key[:]) |
| b.ResetTimer() |
| for i := 0; i < b.N; i++ { |
| out = aead.Seal(out[:0], nonce[:], buf[:], ad[:]) |
| } |
| } |
| |
| func benchamarkChaCha20Poly1305Open(b *testing.B, buf []byte) { |
| b.SetBytes(int64(len(buf))) |
| |
| var key [32]byte |
| var nonce [12]byte |
| var ad [13]byte |
| var ct []byte |
| var out []byte |
| |
| aead, _ := New(key[:]) |
| ct = aead.Seal(ct[:0], nonce[:], buf[:], ad[:]) |
| |
| b.ResetTimer() |
| for i := 0; i < b.N; i++ { |
| out, _ = aead.Open(out[:0], nonce[:], ct[:], ad[:]) |
| } |
| } |
| |
| func BenchmarkChacha20Poly1305Open_64(b *testing.B) { |
| benchamarkChaCha20Poly1305Open(b, make([]byte, 64)) |
| } |
| |
| func BenchmarkChacha20Poly1305Seal_64(b *testing.B) { |
| benchamarkChaCha20Poly1305Seal(b, make([]byte, 64)) |
| } |
| |
| func BenchmarkChacha20Poly1305Open_1350(b *testing.B) { |
| benchamarkChaCha20Poly1305Open(b, make([]byte, 1350)) |
| } |
| |
| func BenchmarkChacha20Poly1305Seal_1350(b *testing.B) { |
| benchamarkChaCha20Poly1305Seal(b, make([]byte, 1350)) |
| } |
| |
| func BenchmarkChacha20Poly1305Open_8K(b *testing.B) { |
| benchamarkChaCha20Poly1305Open(b, make([]byte, 8*1024)) |
| } |
| |
| func BenchmarkChacha20Poly1305Seal_8K(b *testing.B) { |
| benchamarkChaCha20Poly1305Seal(b, make([]byte, 8*1024)) |
| } |