github.com/icodeface/tls@v0.0.0-20230910023335-34df9250cd12/internal/x/crypto/chacha20poly1305/chacha20poly1305.go (about)

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