git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/crypto/aead.go (about)

     1  package crypto
     2  
     3  import (
     4  	"crypto/aes"
     5  	"crypto/cipher"
     6  	"errors"
     7  )
     8  
     9  const (
    10  	// AEADKeySize is the size of the key used by this AEAD, in bytes.
    11  	AEADKeySize = KeySize256
    12  
    13  	// AEADNonceSize is the size of the nonce used with the AES-256-GCM
    14  	// variant of this AEAD, in bytes.
    15  	AEADNonceSize = 12
    16  )
    17  
    18  // NewAEADKey generates a new random secret key.
    19  func NewAEADKey() ([]byte, error) {
    20  	return RandBytes(AEADKeySize)
    21  }
    22  
    23  // NewAEADNonce generates a new random nonce.
    24  func NewAEADNonce() ([]byte, error) {
    25  	return RandBytes(AEADNonceSize)
    26  }
    27  
    28  // NewAEAD returns a AES-256-GCM AEAD that uses the given 256-bit key.
    29  func NewAEAD(key []byte) (aeadCipher cipher.AEAD, err error) {
    30  	blockCipher, err := aes.NewCipher(key)
    31  	if err != nil {
    32  		return
    33  	}
    34  
    35  	aeadCipher, err = cipher.NewGCM(blockCipher)
    36  	if err != nil {
    37  		return
    38  	}
    39  	return
    40  }
    41  
    42  // Encrypt is an helper function to symetrically encrypt a piece of data using AES-256-GCM
    43  // returning the nonce separatly
    44  func EncryptWithNonce(key, plaintext, additionalData []byte) (ciphertext, nonce []byte, err error) {
    45  	nonce, err = NewAEADNonce()
    46  	if err != nil {
    47  		return
    48  	}
    49  	cipher, err := NewAEAD(key)
    50  	if err != nil {
    51  		return
    52  	}
    53  	ciphertext = cipher.Seal(nil, nonce, plaintext, additionalData)
    54  	return
    55  }
    56  
    57  // DecryptWithNonce is an helper function to symetrically  decrypt a piece of data using AES-256-GCM
    58  // taking the nonce as a separate piece of input
    59  func DecryptWithNonce(key, nonce, ciphertext, additionalData []byte) (plaintext []byte, err error) {
    60  	cipher, err := NewAEAD(key)
    61  	if err != nil {
    62  		return
    63  	}
    64  	plaintext, err = cipher.Open(nil, nonce, ciphertext, additionalData)
    65  	return
    66  }
    67  
    68  // Encrypt is an helper function to symetrically encrypt a piece of data using AES-256-GCM
    69  // the nonce is prepended to the ciphertext in the returned buffer
    70  func Encrypt(key, plaintext, additionalData []byte) (ciphertext []byte, err error) {
    71  	nonce, err := NewAEADNonce()
    72  	if err != nil {
    73  		return
    74  	}
    75  	cipher, err := NewAEAD(key)
    76  	if err != nil {
    77  		return
    78  	}
    79  	ciphertext = cipher.Seal(nil, nonce, plaintext, additionalData)
    80  	ciphertext = append(nonce, ciphertext...)
    81  	return
    82  }
    83  
    84  // DecryptWithNonce is an helper function to symetrically decrypt a piece of data using AES-256-GCM
    85  // The nonce should be at the begining of the ciphertext
    86  func Decrypt(key, ciphertext, additionalData []byte) (plaintext []byte, err error) {
    87  	cipher, err := NewAEAD(key)
    88  	if err != nil {
    89  		return
    90  	}
    91  
    92  	if len(ciphertext) < AEADNonceSize {
    93  		err = errors.New("crypto.Decrypt: len(ciphertext) < NonceSize")
    94  		return
    95  	}
    96  	nonce := ciphertext[:AEADNonceSize]
    97  	ciphertext = ciphertext[AEADNonceSize:]
    98  
    99  	plaintext, err = cipher.Open(nil, nonce, ciphertext, additionalData)
   100  	return
   101  }