go-crypt/crypt/chachapoly/chachapoly.go
Snider 36bf16b06e
Some checks failed
Security Scan / security (pull_request) Failing after 8s
Test / test (pull_request) Failing after 4m46s
fix(coderabbit): address review findings
- auth: prevent legacy .lthn fallback when .hash file exists but is
  unreadable or has unexpected format (security fix in verifyPassword
  and Login)
- chachapoly: wrap raw error returns in Decrypt with coreerr.E()
- trust: reject trailing data in LoadPolicies JSON decoder

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-17 13:32:21 +00:00

54 lines
1.3 KiB
Go

package chachapoly
import (
"crypto/rand"
"fmt"
"io"
coreerr "forge.lthn.ai/core/go-log"
"golang.org/x/crypto/chacha20poly1305"
)
// Encrypt encrypts data using ChaCha20-Poly1305.
func Encrypt(plaintext []byte, key []byte) ([]byte, error) {
aead, err := chacha20poly1305.NewX(key)
if err != nil {
return nil, err
}
nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(plaintext)+aead.Overhead())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return nil, err
}
return aead.Seal(nonce, nonce, plaintext, nil), nil
}
// Decrypt decrypts data using ChaCha20-Poly1305.
func Decrypt(ciphertext []byte, key []byte) ([]byte, error) {
const op = "chachapoly.Decrypt"
aead, err := chacha20poly1305.NewX(key)
if err != nil {
return nil, coreerr.E(op, "failed to create cipher", err)
}
minLen := aead.NonceSize() + aead.Overhead()
if len(ciphertext) < minLen {
return nil, coreerr.E(op, fmt.Sprintf("ciphertext too short: got %d bytes, need at least %d bytes", len(ciphertext), minLen), nil)
}
nonce, ciphertext := ciphertext[:aead.NonceSize()], ciphertext[aead.NonceSize():]
decrypted, err := aead.Open(nil, nonce, ciphertext, nil)
if err != nil {
return nil, coreerr.E(op, "decryption failed", err)
}
if len(decrypted) == 0 {
return []byte{}, nil
}
return decrypted, nil
}