aesgcm.go raw
1 package config
2
3 import (
4 "crypto/aes"
5 "crypto/cipher"
6 "crypto/rand"
7 "encoding/hex"
8 "fmt"
9 "strings"
10
11 "golang.org/x/crypto/argon2"
12 )
13
14 func DeriveKey(password string, salt []byte) ([]byte, []byte, error) {
15 if salt == nil {
16 salt = make([]byte, 32)
17 if _, err := rand.Read(salt); err != nil {
18 return nil, nil, err
19 }
20 }
21
22 key := argon2.Key([]byte(password), salt, 3, 32*1024, 1, 32)
23
24 return key, salt, nil
25 }
26
27 func AesGcmEncryptWithPassword(plaintext string, password string) (string, error) {
28 secretKey, salt, err := DeriveKey(password, nil)
29 if err != nil {
30 return "", err
31 }
32
33 ciphertext, err := AesGcmEncryptWithKey(plaintext, secretKey)
34 if err != nil {
35 return "", err
36 }
37
38 return hex.EncodeToString(salt) + "-" + ciphertext, nil
39 }
40
41 func AesGcmDecryptWithPassword(ciphertext string, password string) (string, error) {
42 arr := strings.Split(ciphertext, "-")
43 salt, _ := hex.DecodeString(arr[0])
44 secretKey, _, err := DeriveKey(password, salt)
45 if err != nil {
46 return "", err
47 }
48
49 return AesGcmDecryptWithKey(arr[1]+"-"+arr[2], secretKey)
50 }
51
52 func AesGcmEncryptWithKey(plaintext string, key []byte) (string, error) {
53 // require a 32 bytes key (256 bits)
54 if len(key) != 32 {
55 return "", fmt.Errorf("key must be at least 32 bytes, got %d", len(key))
56 }
57
58 plaintextBytes := []byte(plaintext)
59
60 aes, err := aes.NewCipher(key)
61 if err != nil {
62 return "", err
63 }
64
65 aesgcm, err := cipher.NewGCM(aes)
66 if err != nil {
67 return "", err
68 }
69
70 nonce := make([]byte, aesgcm.NonceSize())
71 _, err = rand.Read(nonce)
72 if err != nil {
73 return "", err
74 }
75
76 ciphertext := aesgcm.Seal(nil, nonce, plaintextBytes, nil)
77
78 return hex.EncodeToString(nonce) + "-" + hex.EncodeToString(ciphertext), nil
79 }
80
81 func AesGcmDecryptWithKey(ciphertext string, key []byte) (string, error) {
82 // require a 32 bytes key (256 bits)
83 if len(key) != 32 {
84 return "", fmt.Errorf("key must be at least 32 bytes, got %d", len(key))
85 }
86
87 arr := strings.Split(ciphertext, "-")
88 nonce, _ := hex.DecodeString(arr[0])
89 data, _ := hex.DecodeString(arr[1])
90
91 aes, err := aes.NewCipher([]byte(key))
92 if err != nil {
93 return "", err
94 }
95
96 aesgcm, err := cipher.NewGCM(aes)
97 if err != nil {
98 return "", err
99 }
100
101 plaintext, err := aesgcm.Open(nil, nonce, data, nil)
102 if err != nil {
103 return "", err
104 }
105
106 return string(plaintext), nil
107 }
108