From ac5314396ee76613f6f17f376e9843ca33568426 Mon Sep 17 00:00:00 2001 From: Randall Winkhart Date: Thu, 8 May 2025 17:26:12 +0000 Subject: [PATCH] Use multiple KDFs (add Scrypt for AES256) --- example.go | 3 ++- wrappers/aes.go | 4 ++-- wrappers/chacha.go | 4 ++-- wrappers/keyDeriv.go | 24 ++++++++++++++++++------ 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/example.go b/example.go index ea77117..e094e07 100644 --- a/example.go +++ b/example.go @@ -27,7 +27,8 @@ import ( // TODO Enhancements: // Security: -// Play with nonce sizes and Argon2 parameters to find the best speed-security balance +// Handle decryption in the daemon and return decrypted data, rather than returning the passphrase +// Play with nonce sizes and KDF parameters to find the best speed-security balance // Standalone cmd: // Usable as symmetric-only GPG replacement diff --git a/wrappers/aes.go b/wrappers/aes.go index 45f5922..18e1d73 100644 --- a/wrappers/aes.go +++ b/wrappers/aes.go @@ -19,7 +19,7 @@ func encryptAES(decBytes []byte, passphrase []byte) []byte { io.ReadFull(rand.Reader, salt) // derive key from passphrase using the salt - key := deriveKey(passphrase, salt) + key := deriveKeyScrypt(passphrase, salt) // create AES-256 cipher block, _ := aes.NewCipher(key) @@ -55,7 +55,7 @@ func decryptAES(encBytes []byte, passphrase []byte) ([]byte, error) { ciphertext := encBytes[saltSize+nonceSizeAES:] // derive key from passphrase using the salt - key := deriveKey(passphrase, salt) + key := deriveKeyScrypt(passphrase, salt) // create AES-256 cipher block, _ := aes.NewCipher(key) diff --git a/wrappers/chacha.go b/wrappers/chacha.go index 270a277..10f44eb 100644 --- a/wrappers/chacha.go +++ b/wrappers/chacha.go @@ -19,7 +19,7 @@ func encryptCha(data []byte, passphrase []byte) []byte { io.ReadFull(rand.Reader, salt) // derive key from passphrase using the salt - key := deriveKey(passphrase, salt) + key := deriveKeyArgon2(passphrase, salt) // create ChaCha20-Poly1305 cipher stream, _ := chacha20poly1305.NewX(key) @@ -52,7 +52,7 @@ func decryptCha(encryptedData []byte, passphrase []byte) ([]byte, error) { ciphertext := encryptedData[saltSize+nonceSizeCha:] // derive key from passphrase using the salt - key := deriveKey(passphrase, salt) + key := deriveKeyArgon2(passphrase, salt) // create ChaCha20-Poly1305 cipher stream, _ := chacha20poly1305.NewX(key) diff --git a/wrappers/keyDeriv.go b/wrappers/keyDeriv.go index ae4fcf9..09d4265 100644 --- a/wrappers/keyDeriv.go +++ b/wrappers/keyDeriv.go @@ -4,21 +4,33 @@ import ( "runtime" "golang.org/x/crypto/argon2" + "golang.org/x/crypto/scrypt" ) const ( // parameters for Argon2 argonTime = 8 // set to pass 1-second test in dev environment argonMemory = 384 * 1024 // 384 MB - argonKeyLen = 32 // 256 bits, key length for both ChaCha20 and AES256 + + // parameters for Scrypt + scryptN = 262144 + scryptR = 8 // block size, recommended to be 8 + scryptP = 1 // parallelization factor, recommended to be 1 // general constants - saltSize = 16 + keyLen = 32 // 256 bits, key length for both algorithms + saltSize = 16 // 128 bits, recommended salt size for both algorithms ) -var argonThreads = uint8(runtime.NumCPU()) +var threads = uint8(runtime.NumCPU()) -// DeriveKey derives an encryption key from a passphrase using Argon2. -func deriveKey(passphrase []byte, salt []byte) []byte { - return argon2.IDKey(passphrase, salt, argonTime, argonMemory, argonThreads, argonKeyLen) +// DeriveKeyArgon2 derives an encryption key from a passphrase using Argon2. +func deriveKeyArgon2(passphrase []byte, salt []byte) []byte { + return argon2.IDKey(passphrase, salt, argonTime, argonMemory, threads, keyLen) +} + +// DeriveKeyScrypt derives an encryption key from a passphrase using Scrypt. +func deriveKeyScrypt(passphrase []byte, salt []byte) []byte { + key, _ := scrypt.Key(passphrase, salt, scryptN, scryptR, scryptP, keyLen) + return key }