package crypto
import (
"crypto/rand"
"encoding/base64"
"golang.org/x/crypto/argon2"
chacha "golang.org/x/crypto/chacha20poly1305"
)
func Encrypt(s string, key []byte) (string, error) {
sbytes := []byte(s)
encrypted, err := encryptBytes(sbytes, key, nil)
if err != nil {
return "", err
}
encStr := base64.RawStdEncoding.EncodeToString(encrypted)
return encStr, nil
}
func Decrypt(s string, key []byte) (string, error) {
b, err := base64.RawStdEncoding.DecodeString(s)
if err != nil {
return "", err
}
unsealed, err := decryptBytes(b, key, nil)
if err != nil {
return "", err
}
return string(unsealed), nil
}
func encryptBytes(plaintext, key, additionalData []byte) ([]byte, error) {
aead, err := chacha.NewX(key)
if err != nil {
return nil, err
}
nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(plaintext)+aead.Overhead())
if _, err := rand.Read(nonce); err != nil {
return nil, err
}
sealed := aead.Seal(nonce, nonce, plaintext, additionalData)
return sealed, nil
}
func decryptBytes(cyphertext, key, additionalData []byte) ([]byte, error) {
aead, err := chacha.NewX(key)
if err != nil {
return nil, err
}
nonce, enc := cyphertext[:aead.NonceSize()], cyphertext[aead.NonceSize():]
unsealed, err := aead.Open(nil, nonce, enc, additionalData)
if err != nil {
return nil, err
}
return unsealed, nil
}
func GetKey(password, salt string) []byte {
key := Hash([]byte(password), []byte(salt), 10)
return key
}
func GenSalt(n uint32) (string, error) {
b := make([]byte, n)
_, err := rand.Read(b)
if err != nil {
return "", err
}
return base64.RawStdEncoding.EncodeToString(b), nil
}
func Hash(plaintext []byte, salt []byte, time uint32) []byte {
return argon2.IDKey(plaintext, salt, time, 64*1024, 2, 32)
}
func ClientAuthToken(username, password string) []byte {
return Hash(GetKey(password, username), []byte(password), 10)
}
func ServerAuthToken(token []byte) []byte {
return Hash(token, nil, 30)
}