93 lines
1.9 KiB
Go
93 lines
1.9 KiB
Go
|
|
/*
|
||
|
|
* Copyright (c) 2026 Kaiy Ragur
|
||
|
|
*
|
||
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||
|
|
*/
|
||
|
|
package utils
|
||
|
|
|
||
|
|
import (
|
||
|
|
"crypto/aes"
|
||
|
|
"crypto/cipher"
|
||
|
|
"crypto/rand"
|
||
|
|
"encoding/base64"
|
||
|
|
"fmt"
|
||
|
|
"io"
|
||
|
|
|
||
|
|
"golang.org/x/crypto/scrypt"
|
||
|
|
)
|
||
|
|
|
||
|
|
// Get base64 string of encrpted data
|
||
|
|
// salt [:16]
|
||
|
|
// nonce [16:28]
|
||
|
|
// data [28:]
|
||
|
|
func AESEncrypt(rawKey string, password string) (string, error) {
|
||
|
|
salt := make([]byte, 16)
|
||
|
|
if _, err := io.ReadFull(rand.Reader, salt); err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
key, err := scrypt.Key([]byte(password), salt, 32768, 8, 1, 32)
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
block, err := aes.NewCipher(key)
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
gcm, err := cipher.NewGCM(block)
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
nonce := make([]byte, gcm.NonceSize())
|
||
|
|
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
ciphertext := gcm.Seal(nil, nonce, []byte(rawKey), nil)
|
||
|
|
|
||
|
|
result := append(salt, append(nonce, ciphertext...)...)
|
||
|
|
return base64.StdEncoding.EncodeToString(result), nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func AESDecrypt(encryptedB64 string, password string) (string, error) {
|
||
|
|
data, err := base64.StdEncoding.DecodeString(encryptedB64)
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(data) < 16+12 { // Salt(16) + Nonce(12)
|
||
|
|
return "", fmt.Errorf("invalid encrypted data")
|
||
|
|
}
|
||
|
|
|
||
|
|
salt := data[:16]
|
||
|
|
nonce := data[16:28]
|
||
|
|
ciphertext := data[28:]
|
||
|
|
|
||
|
|
key, err := scrypt.Key([]byte(password), salt, 32768, 8, 1, 32)
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
block, err := aes.NewCipher(key)
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
gcm, err := cipher.NewGCM(block)
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
rawKey, err := gcm.Open(nil, nonce, ciphertext, nil)
|
||
|
|
if err != nil {
|
||
|
|
return "", fmt.Errorf("decryption failed (wrong password?): %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return string(rawKey), nil
|
||
|
|
}
|