From 32d21a8fb7137772f51fc1e693a0e878bf7a4cc1 Mon Sep 17 00:00:00 2001 From: pilinux Date: Wed, 28 Aug 2024 23:15:05 +0200 Subject: [PATCH] functions: en/decrypt with XChaCha20-Poly1305 --- .github/workflows/golangci-lint.yml | 2 +- README.md | 1 + _example/xchacha20poly1305/main.go | 48 +++++++++++++++++++++++++++ chaCha20.go | 50 ++++++++++++++++++++++++++++- 4 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 _example/xchacha20poly1305/main.go diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 3a98816..2cd7eef 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -40,7 +40,7 @@ jobs: uses: golangci/golangci-lint-action@v6 with: # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version - version: v1.59.1 + version: v1.60.3 # Optional: working directory, useful for monorepos # working-directory: somedir diff --git a/README.md b/README.md index 0394848..3d06cc7 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ cryptographic primitives. - [AES](_example/aes/main.go) - [ChaCha20-Poly1305 AEAD](_example/chacha20poly1305/main.go) +- [XChaCha20-Poly1305 AEAD](_example/xchacha20poly1305/main.go) - [RSA](_example/rsa/main.go) - [Hashing](_example/hashing/main.go) diff --git a/_example/xchacha20poly1305/main.go b/_example/xchacha20poly1305/main.go new file mode 100644 index 0000000..ad3fc41 --- /dev/null +++ b/_example/xchacha20poly1305/main.go @@ -0,0 +1,48 @@ +// Package main - example usage of XChaCha20-Poly1305 encryption - decryption +package main + +import ( + "crypto/rand" + "fmt" + + "golang.org/x/crypto/argon2" + + "github.com/pilinux/crypt" +) + +func main() { + text := "Hello world" + secretPass := ",D'(bHOpO#beU(Fn@~_6Enn3a2n=aEQWg''vz" + + // generate a random 256-bit salt + salt := make([]byte, 32) + if _, err := rand.Read(salt); err != nil { + fmt.Println("error generating salt:", err) + return + } + + // parameters for argon2 key derivation + timeCost := 2 // number of iterations + memoryCost := 64 * 1024 // memory usage in KiB + cpuCost := 2 // number of threads used + keyLength := 32 // length of the derived key in bytes + + // derive a 256-bit key from the user's secret pass using argon2id + key := argon2.IDKey([]byte(secretPass), salt, uint32(timeCost), uint32(memoryCost), uint8(cpuCost), uint32(keyLength)) + + // encrypt the data + ciphertext, nonce, err := crypt.EncryptXChacha20poly1305(key, text) + if err != nil { + fmt.Println(err) + return + } + fmt.Println("ciphertext:", ciphertext) + + // decrypt the data + plaintext, err := crypt.DecryptXChacha20poly1305(key, nonce, ciphertext) + if err != nil { + fmt.Println(err) + return + } + fmt.Println("plaintext:", plaintext) +} diff --git a/chaCha20.go b/chaCha20.go index 4c89e42..f9cb726 100644 --- a/chaCha20.go +++ b/chaCha20.go @@ -8,7 +8,7 @@ import ( ) // EncryptChacha20poly1305 encrypts and authenticates the given message with -// ChaCha20-Poly1305 AEAD using the given 256-bit key. +// ChaCha20-Poly1305 AEAD using the given 256-bit key and 96-bit nonce. func EncryptChacha20poly1305(key []byte, text string) (ciphertext []byte, nonce []byte, err error) { // create a new ChaCha20-Poly1305 AEAD using the given 256-bit key aead, err := chacha20poly1305.New(key) @@ -54,3 +54,51 @@ func DecryptChacha20poly1305(key, nonce, ciphertext []byte) (text string, err er return } + +// EncryptXChacha20poly1305 encrypts and authenticates the given message with +// XChaCha20-Poly1305 AEAD using the given 256-bit key and 192-bit nonce. +func EncryptXChacha20poly1305(key []byte, text string) (ciphertext []byte, nonce []byte, err error) { + // create a new XChaCha20-Poly1305 AEAD using the given 256-bit key + aead, err := chacha20poly1305.NewX(key) + if err != nil { + err = fmt.Errorf("error creating AEAD: %v", err) + return + } + + // generate a 192-bit random nonce + nonce = make([]byte, aead.NonceSize()) + _, err = rand.Read(nonce) + if err != nil { + err = fmt.Errorf("error generating nonce: %v", err) + return + } + + // data to be encrypted + data := []byte(text) + + // encrypt the data + ciphertext = aead.Seal(nil, nonce, data, nil) + + return +} + +// DecryptXChacha20poly1305 decrypts and authenticates the given message with +// XChaCha20-Poly1305 AEAD using the given 256-bit key and 192-bit nonce. +func DecryptXChacha20poly1305(key, nonce, ciphertext []byte) (text string, err error) { + // create a new XChaCha20-Poly1305 AEAD using the given 256-bit key + aead, err := chacha20poly1305.NewX(key) + if err != nil { + err = fmt.Errorf("error creating AEAD: %v", err) + return + } + + // decrypt the data + plaintext, err := aead.Open(nil, nonce, ciphertext, nil) + if err != nil { + err = fmt.Errorf("error decrypting data: %v", err) + return + } + text = string(plaintext) + + return +}