|
|
- // Package hkdfchacha20poly1305 creates an AEAD using hkdf, chacha20, and poly1305
- // When sealing and opening, the hkdf is used to obtain the nonce and subkey for
- // chacha20. Other than the change for the how the subkey and nonce for chacha
- // are obtained, this is the same as chacha20poly1305
- package hkdfchacha20poly1305
-
- import (
- "crypto/cipher"
- "crypto/sha256"
- "errors"
- "io"
-
- "golang.org/x/crypto/chacha20poly1305"
- "golang.org/x/crypto/hkdf"
- )
-
- // Implements crypto.AEAD
- type hkdfchacha20poly1305 struct {
- key [KeySize]byte
- }
-
- const (
- // KeySize is the size of the key used by this AEAD, in bytes.
- KeySize = 32
- // NonceSize is the size of the nonce used with this AEAD, in bytes.
- NonceSize = 24
- // TagSize is the size added from poly1305
- TagSize = 16
- // MaxPlaintextSize is the max size that can be passed into a single call of Seal
- MaxPlaintextSize = (1 << 38) - 64
- // MaxCiphertextSize is the max size that can be passed into a single call of Open,
- // this differs from plaintext size due to the tag
- MaxCiphertextSize = (1 << 38) - 48
- // HkdfInfo is the parameter used internally for Hkdf's info parameter.
- HkdfInfo = "TENDERMINT_SECRET_CONNECTION_FRAME_KEY_DERIVE"
- )
-
- //New xChaChapoly1305 AEAD with 24 byte nonces
- func New(key []byte) (cipher.AEAD, error) {
- if len(key) != KeySize {
- return nil, errors.New("chacha20poly1305: bad key length")
- }
- ret := new(hkdfchacha20poly1305)
- copy(ret.key[:], key)
- return ret, nil
-
- }
- func (c *hkdfchacha20poly1305) NonceSize() int {
- return NonceSize
- }
-
- func (c *hkdfchacha20poly1305) Overhead() int {
- return TagSize
- }
-
- func (c *hkdfchacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
- if len(nonce) != NonceSize {
- panic("hkdfchacha20poly1305: bad nonce length passed to Seal")
- }
-
- if uint64(len(plaintext)) > MaxPlaintextSize {
- panic("hkdfchacha20poly1305: plaintext too large")
- }
-
- subKey, chachaNonce := getSubkeyAndChachaNonceFromHkdf(&c.key, &nonce)
-
- aead, err := chacha20poly1305.New(subKey[:])
- if err != nil {
- panic("hkdfchacha20poly1305: failed to initialize chacha20poly1305")
- }
-
- return aead.Seal(dst, chachaNonce[:], plaintext, additionalData)
- }
-
- func (c *hkdfchacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
- if len(nonce) != NonceSize {
- return nil, errors.New("hkdfchacha20poly1305: bad nonce length passed to Open")
- }
- if uint64(len(ciphertext)) > MaxCiphertextSize {
- return nil, errors.New("hkdfchacha20poly1305: ciphertext too large")
- }
-
- subKey, chachaNonce := getSubkeyAndChachaNonceFromHkdf(&c.key, &nonce)
-
- aead, err := chacha20poly1305.New(subKey[:])
- if err != nil {
- panic("hkdfchacha20poly1305: failed to initialize chacha20poly1305")
- }
-
- return aead.Open(dst, chachaNonce[:], ciphertext, additionalData)
- }
-
- func getSubkeyAndChachaNonceFromHkdf(cKey *[32]byte, nonce *[]byte) (
- subKey [KeySize]byte, chachaNonce [chacha20poly1305.NonceSize]byte) {
- hash := sha256.New
- hkdf := hkdf.New(hash, (*cKey)[:], *nonce, []byte(HkdfInfo))
- _, err := io.ReadFull(hkdf, subKey[:])
- if err != nil {
- panic("hkdfchacha20poly1305: failed to read subkey from hkdf")
- }
- _, err = io.ReadFull(hkdf, chachaNonce[:])
- if err != nil {
- panic("hkdfchacha20poly1305: failed to read chachaNonce from hkdf")
- }
- return
- }
|