1
0
Fork 0
forked from jriou/coller

Initial commit

Signed-off-by: Julien Riou <julien@riou.xyz>
This commit is contained in:
Julien Riou 2025-08-21 16:22:03 +02:00
commit ef9aca1f3b
Signed by: jriou
GPG key ID: 9A099EDA51316854
26 changed files with 1668 additions and 0 deletions

View file

@ -0,0 +1,77 @@
package internal
import (
"crypto/cipher"
"crypto/rand"
"fmt"
"golang.org/x/crypto/argon2"
"golang.org/x/crypto/chacha20poly1305"
)
const (
SaltSize = 32
KeySize = uint32(32) // KeySize is 32 bytes (256 bits).
KeyTime = uint32(5)
KeyMemory = uint32(1024 * 64) // KeyMemory in KiB. here, 64 MiB.
KeyThreads = uint8(4)
)
// NewCipher creates a cipher using XChaCha20-Poly1305
// https://pkg.go.dev/golang.org/x/crypto/chacha20poly1305
// A salt is required to derive the key from a password using argon
func NewCipher(password string, salt []byte) (cipher.AEAD, error) {
key := argon2.IDKey([]byte(password), salt, KeyTime, KeyMemory, KeyThreads, KeySize)
return chacha20poly1305.NewX(key)
}
// Encrypt to encrypt a plaintext with a password
// Returns a byte slice with the generated salt, nonce and the ciphertext
func Encrypt(plaintext []byte, password string) (result []byte, err error) {
salt := make([]byte, SaltSize)
if n, err := rand.Read(salt); err != nil || n != SaltSize {
return nil, err
}
aead, err := NewCipher(password, salt)
if err != nil {
return nil, err
}
result = append(result, salt...)
nonce := make([]byte, aead.NonceSize())
if m, err := rand.Read(nonce); err != nil || m != aead.NonceSize() {
return nil, err
}
result = append(result, nonce...)
ciphertext := aead.Seal(nil, nonce, plaintext, nil)
result = append(result, ciphertext...)
return result, nil
}
// Decrypt to decrypt a ciphertext with a password
// Returns the plaintext
func Decrypt(ciphertext []byte, password string) ([]byte, error) {
if len(ciphertext) < SaltSize {
return nil, fmt.Errorf("ciphertext is too short: cannot read salt")
}
salt := ciphertext[:SaltSize]
aead, err := NewCipher(password, salt)
if err != nil {
return nil, err
}
if len(ciphertext) < SaltSize+aead.NonceSize() {
return nil, fmt.Errorf("ciphertext is too short: cannot read nonce")
}
nonce := ciphertext[SaltSize : SaltSize+aead.NonceSize()]
ciphertext = ciphertext[SaltSize+aead.NonceSize():]
return aead.Open(nil, nonce, ciphertext, nil)
}