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 } 84