func ExampleCipher() { key, err := hex.DecodeString("60143a3d7c7137c3622d490e7dbb85859138d198d9c648960e186412a6250722") if err != nil { panic(err) } // A nonce should only be used once. Generate it randomly. nonce, err := hex.DecodeString("308c92676fa95973") if err != nil { panic(err) } c, err := chacha20.New(key, nonce) if err != nil { panic(err) } src := []byte("hello I am a secret message") dst := make([]byte, len(src)) c.XORKeyStream(dst, src) fmt.Printf("%x\n", dst) // Output: // a05452ebd981422dcdab2c9cde0d20a03f769e87d3e976ee6d6a11 }
func TestBadNonceSize(t *testing.T) { key := make([]byte, chacha20.KeySize) nonce := make([]byte, 3) _, err := chacha20.New(key, nonce) if err != chacha20.ErrInvalidNonce { t.Error("Should have rejected an invalid nonce") } }
// generateCipherStream generates a stream of cryptographic psuedo-random bytes // intened to be used to encrypt a message using a one-time-pad like // construciton. func generateCipherStream(key [keyLen]byte, numBytes uint) []byte { var nonce [8]byte cipher, err := chacha20.New(key[:], nonce[:]) if err != nil { panic(err) } output := make([]byte, numBytes) cipher.XORKeyStream(output, output) return output }
// Test how and if de-/encoding works with chacha20 - surprise it works func TestChacha20(t *testing.T) { K, _ := hex.DecodeString("6a3bfd77d9efac53f8ef51712796bf7a37541f425a5dc5397c8a2c3c040d9301") message, _ := hex.DecodeString("8e685bd3237866e7a424b0f33df1a087a397a78e147042d2d17b159044d2ad1162dea13df2a119b61c90d62fc76335f49954557f2b07c463dca1664ca042599fca66068b16bc3e7e1896536ca2") c, err := chacha20.New(K, []byte("PS-Msg05")) if err != nil { t.Fatal(err) } var out = make([]byte, len(message)) c.XORKeyStream(out, message) c2, err := chacha20.New(K, []byte("PS-Msg05")) if err != nil { t.Fatal(err) } var out2 = make([]byte, len(message)) c2.XORKeyStream(out2, out) if reflect.DeepEqual(out2, message) == false { t.Fatal(out2) } }
func main() { fmt.Println("[") // 5 tests for i := 0; i < 5; i++ { plaintext := make([]byte, 64) rand.Read(plaintext) key := make([]byte, 32) rand.Read(key) nonce := make([]byte, 8) rand.Read(nonce) stream, _ := chacha20.New(key[:], nonce) e32a := make([]byte, 32) var pkey [32]byte stream.XORKeyStream(pkey[:], e32a) ciphertext := make([]byte, 64) stream.XORKeyStream(ciphertext, plaintext) var tag [16]byte poly1305.Sum(&tag, ciphertext, &pkey) fmt.Printf(` { key: new Buffer([ %s ]), nonce: new Buffer([ %s ]), plain: new Buffer([ %s ]), cipher: new Buffer([ %s ]), tag: new Buffer([ %s ]), }, `, hexify(key, "\t\t\t"), hexify(nonce, "\t\t\t"), hexify(plaintext, "\t\t\t"), hexify(ciphertext, "\t\t\t"), hexify(tag[:], "\t\t\t"), ) } fmt.Println("]") }
// DecryptAndVerify returns the chacha20 decrypted messages. // An error is returned when the poly1305 message authenticator (seal) could not be verified. // Nonce should be 8 byte. func DecryptAndVerify(key, nonce, message []byte, mac [16]byte, add []byte) ([]byte, error) { chacha20, err := chacha20.New(key, nonce) if err != nil { panic(err) } // poly1305 key is chacha20 over 32 zeros var poly1305Key [32]byte var chacha20KeyOut = make([]byte, 64) var zeros = make([]byte, 64) chacha20.XORKeyStream(chacha20KeyOut, zeros) copy(poly1305Key[:], chacha20KeyOut) var chacha20Out = make([]byte, len(message)) var poly1305Out [16]byte // poly1305 byte order // - add bytes up to mod 16 (if available) // - message up to mod 16 // - number of add bytes up to mod 8 // - number of message bytes up to mod 8 var poly1305In []byte if len(add) > 0 { poly1305In = AddBytes(poly1305In, add, 16) } poly1305In = AddBytes(poly1305In, message, 16) addLength := make([]byte, 8) msgLength := make([]byte, 8) binary.LittleEndian.PutUint64(addLength, uint64(len(add))) binary.LittleEndian.PutUint64(msgLength, uint64(len(message))) poly1305In = AddBytes(poly1305In, addLength, 8) poly1305In = AddBytes(poly1305In, msgLength, 8) poly1305.Sum(&poly1305Out, poly1305In, &poly1305Key) if poly1305.Verify(&mac, poly1305In, &poly1305Key) == false { return nil, errors.New("MAC not equal: " + hex.EncodeToString(poly1305Out[:]) + " != " + hex.EncodeToString(mac[:])) } chacha20.XORKeyStream(chacha20Out, message) return chacha20Out, nil }
func TestChaCha20(t *testing.T) { for i, vector := range testVectors { if vector.rounds == 20 { t.Logf("Running test vector %d", i) key, err := hex.DecodeString(vector.key) if err != nil { t.Error(err) } nonce, err := hex.DecodeString(vector.nonce) if err != nil { t.Error(err) } c, err := chacha20.New(key, nonce) if err != nil { t.Error(err) } expected, err := hex.DecodeString(vector.keyStream) if err != nil { t.Error(err) } src := make([]byte, len(expected)) dst := make([]byte, len(expected)) c.XORKeyStream(dst, src) if !bytes.Equal(expected, dst) { t.Errorf("Bad keystream: expected %x, was %x", expected, dst) for i, v := range expected { if dst[i] != v { t.Logf("Mismatch at offset %d: %x vs %x", i, v, dst[i]) break } } } } } }
// EncryptAndSeal returns the chacha20 encrypted message and poly1305 message authentictor (also refered as seals) // Nonce should be 8 byte func EncryptAndSeal(key, nonce, message []byte, add []byte) ([]byte /*encrypted*/, [16]byte /*mac*/, error) { chacha20, err := chacha20.New(key, nonce) if err != nil { panic(err) } // poly1305 key is chacha20 over 32 zeros var poly1305Key [32]byte var chacha20KeyOut = make([]byte, 64) var zeros = make([]byte, 64) chacha20.XORKeyStream(chacha20KeyOut, zeros) copy(poly1305Key[:], chacha20KeyOut) var chacha20Out = make([]byte, len(message)) var poly1305Out [16]byte chacha20.XORKeyStream(chacha20Out, message) var poly1305In []byte if len(add) > 0 { poly1305In = AddBytes(poly1305In, add, 16) } poly1305In = AddBytes(poly1305In, chacha20Out, 16) addLength := make([]byte, 8) msgLength := make([]byte, 8) binary.LittleEndian.PutUint64(addLength, uint64(len(add))) binary.LittleEndian.PutUint64(msgLength, uint64(len(message))) poly1305In = AddBytes(poly1305In, addLength, 8) poly1305In = AddBytes(poly1305In, msgLength, 8) poly1305.Sum(&poly1305Out, poly1305In, &poly1305Key) return chacha20Out, poly1305Out, nil }
func newChaCha20Stream(key, iv []byte, _ DecOrEnc) (cipher.Stream, error) { return chacha20.New(key, iv) }
func BenchmarkChaCha20(b *testing.B) { key := make([]byte, chacha20.KeySize) nonce := make([]byte, chacha20.NonceSize) c, _ := chacha20.New(key, nonce) benchmarkStream(b, c) }
func chacha20XOR(nonce []byte, dst []byte, src []byte) { chacha20Cipher, _ := chacha20.New(secretKey, nonce) chacha20Cipher.XORKeyStream(dst, src) }