Skip to content

Commit

Permalink
Avoid unnecessary copy of ciphertext in ChaCha20 Poly1305 AEAD implem…
Browse files Browse the repository at this point in the history
…entation.

To do this, we directly use golang's implementation (similar to xchacha20poly1305.go) instead of ChaCha20Poly1305InsecureNonce.

PiperOrigin-RevId: 534320923
Change-Id: I022f1debb42198a9d83a11bee930f408595e0fa8
  • Loading branch information
juergw authored and copybara-github committed May 23, 2023
1 parent 97b1dfa commit e4ee4b6
Showing 1 changed file with 36 additions and 13 deletions.
49 changes: 36 additions & 13 deletions aead/subtle/chacha20poly1305.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
package subtle

import (
"errors"
"fmt"

"golang.org/x/crypto/chacha20poly1305"
internalaead "github.com/tink-crypto/tink-go/internal/aead"
"github.com/tink-crypto/tink-go/subtle/random"
"github.com/tink-crypto/tink-go/tink"
)
Expand All @@ -31,8 +31,7 @@ const (

// ChaCha20Poly1305 is an implementation of AEAD interface.
type ChaCha20Poly1305 struct {
Key []byte
chaCha20Poly1305InsecureNonce *internalaead.ChaCha20Poly1305InsecureNonce
Key []byte
}

// Assert that ChaCha20Poly1305 implements the AEAD interface.
Expand All @@ -41,30 +40,54 @@ var _ tink.AEAD = (*ChaCha20Poly1305)(nil)
// NewChaCha20Poly1305 returns an ChaCha20Poly1305 instance.
// The key argument should be a 32-bytes key.
func NewChaCha20Poly1305(key []byte) (*ChaCha20Poly1305, error) {
chaCha20Poly1305InsecureNonce, err := internalaead.NewChaCha20Poly1305InsecureNonce(key)
return &ChaCha20Poly1305{
Key: key,
chaCha20Poly1305InsecureNonce: chaCha20Poly1305InsecureNonce,
}, err
if len(key) != chacha20poly1305.KeySize {
return nil, errors.New("chacha20poly1305: bad key length")
}

return &ChaCha20Poly1305{Key: key}, nil
}

// Encrypt encrypts plaintext with associatedData.
//
// The resulting ciphertext consists of two parts:
// (1) the nonce used for encryption and (2) the actual ciphertext.
// 1. the nonce used for encryption
// 2. the actual ciphertext
func (ca *ChaCha20Poly1305) Encrypt(plaintext []byte, associatedData []byte) ([]byte, error) {
nonce := random.GetRandomBytes(chacha20poly1305.NonceSize)
ct, err := ca.chaCha20Poly1305InsecureNonce.Encrypt(nonce, plaintext, associatedData)
if len(plaintext) > maxInt-chacha20poly1305.NonceSize-poly1305TagSize {
return nil, fmt.Errorf("chacha20poly1305: plaintext too long")
}
c, err := chacha20poly1305.New(ca.Key)
if err != nil {
return nil, err
}
return append(nonce, ct...), nil

nonce := random.GetRandomBytes(chacha20poly1305.NonceSize)
// Set dst's capacity to fit the nonce and ciphertext.
dst := make([]byte, 0, chacha20poly1305.NonceSize+len(plaintext)+c.Overhead())
dst = append(dst, nonce...)
// Seal appends the ciphertext to dst. So the final output is: nonce || ciphertext.
return c.Seal(dst, nonce, plaintext, associatedData), nil
}

// Decrypt decrypts ciphertext with associatedData.
//
// ciphertext consists of two parts:
// 1. the nonce used for encryption
// 2. the actual ciphertext
func (ca *ChaCha20Poly1305) Decrypt(ciphertext []byte, associatedData []byte) ([]byte, error) {
if len(ciphertext) < chacha20poly1305.NonceSize+poly1305TagSize {
return nil, fmt.Errorf("chacha20poly1305: ciphertext too short")
}

c, err := chacha20poly1305.New(ca.Key)
if err != nil {
return nil, err
}

nonce := ciphertext[:chacha20poly1305.NonceSize]
return ca.chaCha20Poly1305InsecureNonce.Decrypt(nonce, ciphertext[chacha20poly1305.NonceSize:], associatedData)
pt, err := c.Open(nil, nonce, ciphertext[chacha20poly1305.NonceSize:] /*=ciphertext*/, associatedData)
if err != nil {
return nil, fmt.Errorf("ChaCha20Poly1305.Decrypt: %v", err)
}
return pt, nil
}

0 comments on commit e4ee4b6

Please sign in to comment.