| // 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 ( |
| "encoding/binary" |
| |
| "golang.org/x/crypto/chacha20" |
| "golang.org/x/crypto/internal/subtle" |
| "golang.org/x/crypto/poly1305" |
| ) |
| |
| func writeWithPadding(p *poly1305.MAC, b []byte) { |
| p.Write(b) |
| if rem := len(b) % 16; rem != 0 { |
| var buf [16]byte |
| padLen := 16 - rem |
| p.Write(buf[:padLen]) |
| } |
| } |
| |
| func writeUint64(p *poly1305.MAC, n int) { |
| var buf [8]byte |
| binary.LittleEndian.PutUint64(buf[:], uint64(n)) |
| p.Write(buf[:]) |
| } |
| |
| func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte { |
| ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize) |
| ciphertext, tag := out[:len(plaintext)], out[len(plaintext):] |
| if subtle.InexactOverlap(out, plaintext) { |
| panic("chacha20poly1305: invalid buffer overlap") |
| } |
| |
| var polyKey [32]byte |
| s, _ := chacha20.NewUnauthenticatedCipher(c.key[:], nonce) |
| s.XORKeyStream(polyKey[:], polyKey[:]) |
| s.SetCounter(1) // set the counter to 1, skipping 32 bytes |
| s.XORKeyStream(ciphertext, plaintext) |
| |
| p := poly1305.New(&polyKey) |
| writeWithPadding(p, additionalData) |
| writeWithPadding(p, ciphertext) |
| writeUint64(p, len(additionalData)) |
| writeUint64(p, len(plaintext)) |
| p.Sum(tag[:0]) |
| |
| return ret |
| } |
| |
| func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) { |
| tag := ciphertext[len(ciphertext)-16:] |
| ciphertext = ciphertext[:len(ciphertext)-16] |
| |
| var polyKey [32]byte |
| s, _ := chacha20.NewUnauthenticatedCipher(c.key[:], nonce) |
| s.XORKeyStream(polyKey[:], polyKey[:]) |
| s.SetCounter(1) // set the counter to 1, skipping 32 bytes |
| |
| p := poly1305.New(&polyKey) |
| writeWithPadding(p, additionalData) |
| writeWithPadding(p, ciphertext) |
| writeUint64(p, len(additionalData)) |
| writeUint64(p, len(ciphertext)) |
| |
| ret, out := sliceForAppend(dst, len(ciphertext)) |
| if subtle.InexactOverlap(out, ciphertext) { |
| panic("chacha20poly1305: invalid buffer overlap") |
| } |
| if !p.Verify(tag) { |
| for i := range out { |
| out[i] = 0 |
| } |
| return nil, errOpen |
| } |
| |
| s.XORKeyStream(out, ciphertext) |
| return ret, nil |
| } |