Adam Langley | 594708b | 2016-10-10 14:34:47 -0700 | [diff] [blame] | 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 | |
| 5 | // Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD as specified in RFC 7539. |
| 6 | package chacha20poly1305 |
| 7 | |
| 8 | import ( |
| 9 | "crypto/cipher" |
| 10 | "errors" |
| 11 | ) |
| 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 = 12 |
| 18 | ) |
| 19 | |
| 20 | type chacha20poly1305 struct { |
| 21 | key [32]byte |
| 22 | } |
| 23 | |
| 24 | // New returns a ChaCha20-Poly1305 AEAD that uses the given, 256-bit key. |
| 25 | func New(key []byte) (cipher.AEAD, error) { |
| 26 | if len(key) != KeySize { |
| 27 | return nil, errors.New("chacha20poly1305: bad key length") |
| 28 | } |
| 29 | ret := new(chacha20poly1305) |
| 30 | copy(ret.key[:], key) |
| 31 | return ret, nil |
| 32 | } |
| 33 | |
| 34 | func (c *chacha20poly1305) NonceSize() int { |
| 35 | return NonceSize |
| 36 | } |
| 37 | |
| 38 | func (c *chacha20poly1305) Overhead() int { |
| 39 | return 16 |
| 40 | } |
| 41 | |
| 42 | func (c *chacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte { |
| 43 | if len(nonce) != NonceSize { |
| 44 | panic("chacha20poly1305: bad nonce length passed to Seal") |
| 45 | } |
| 46 | |
| 47 | if uint64(len(plaintext)) > (1<<38)-64 { |
| 48 | panic("chacha20poly1305: plaintext too large") |
| 49 | } |
| 50 | |
| 51 | return c.seal(dst, nonce, plaintext, additionalData) |
| 52 | } |
| 53 | |
| 54 | var errOpen = errors.New("chacha20poly1305: message authentication failed") |
| 55 | |
| 56 | func (c *chacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) { |
| 57 | if len(nonce) != NonceSize { |
| 58 | panic("chacha20poly1305: bad nonce length passed to Open") |
| 59 | } |
| 60 | if len(ciphertext) < 16 { |
| 61 | return nil, errOpen |
| 62 | } |
| 63 | if uint64(len(ciphertext)) > (1<<38)-48 { |
| 64 | panic("chacha20poly1305: ciphertext too large") |
| 65 | } |
| 66 | |
| 67 | return c.open(dst, nonce, ciphertext, additionalData) |
| 68 | } |
| 69 | |
| 70 | // sliceForAppend takes a slice and a requested number of bytes. It returns a |
| 71 | // slice with the contents of the given slice followed by that many bytes and a |
| 72 | // second slice that aliases into it and contains only the extra bytes. If the |
| 73 | // original slice has sufficient capacity then no allocation is performed. |
| 74 | func sliceForAppend(in []byte, n int) (head, tail []byte) { |
| 75 | if total := len(in) + n; cap(in) >= total { |
| 76 | head = in[:total] |
| 77 | } else { |
| 78 | head = make([]byte, total) |
| 79 | copy(head, in) |
| 80 | } |
| 81 | tail = head[len(in):] |
| 82 | return |
| 83 | } |