Skip to content

Commit 2cce11c

Browse files
feat(encrypt): excryption logic
1 parent f41a078 commit 2cce11c

File tree

1 file changed

+132
-0
lines changed

1 file changed

+132
-0
lines changed

system/backup/encrypt.go

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package backup
2+
3+
import (
4+
"crypto/aes"
5+
"crypto/cipher"
6+
"crypto/rand"
7+
"crypto/sha256"
8+
"encoding/base64"
9+
"fmt"
10+
"io"
11+
"os"
12+
)
13+
14+
// encryption formatt
15+
type EncryptionConfig struct {
16+
17+
Password string
18+
Salt []byte
19+
}
20+
21+
// AES-GCM encrpption with password based derivation
22+
func EncryptFile(filePath string, config *EncryptionConfig) (string, error) {
23+
24+
data, err := os.ReadFile(filePath)
25+
26+
if err != nil {
27+
28+
return "", fmt.Errorf("failed to read file %s: %w", filePath, err)
29+
30+
}
31+
32+
// derive key from password+salt
33+
key := deriveKey(config.Password, config.Salt)
34+
35+
// AES cipher from key
36+
block, err := aes.NewCipher(key)
37+
if err != nil {
38+
39+
return "", fmt.Errorf("failed to create cipher: %w", err)
40+
41+
}
42+
43+
// GCM mode from AES block
44+
gcm, err := cipher.NewGCM(block)
45+
if err != nil {
46+
47+
return "", fmt.Errorf("failed to create GCM: %w", err)
48+
49+
}
50+
51+
//generate nonce
52+
nonce := make([]byte, gcm.NonceSize())
53+
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
54+
55+
return "", fmt.Errorf("failed to generate nonce: %w", err)
56+
57+
}
58+
59+
//encrypt data with nonce
60+
ciphertext := gcm.Seal(nonce, nonce, data, nil)
61+
62+
//encode to base64
63+
encoded := base64.StdEncoding.EncodeToString(ciphertext)
64+
return encoded, nil
65+
}
66+
67+
// // decryption methods - will be used later
68+
// func DecryptFile(encryptedData string, config *EncryptionConfig) ([]byte, error) {
69+
// ///decode from base64
70+
// ciphertext, err := base64.StdEncoding.DecodeString(encryptedData)
71+
// if err != nil {
72+
73+
// return nil, fmt.Errorf("failed to decode base64: %w", err)
74+
75+
// }
76+
77+
// //derive key from password
78+
// key := deriveKey(config.Password, config.Salt)
79+
80+
// //create AES cipher
81+
// block, err := aes.NewCipher(key)
82+
// if err != nil {
83+
84+
// return nil, fmt.Errorf("failed to create cipher: %w", err)
85+
86+
// }
87+
88+
// //create GCM mode
89+
// gcm, err := cipher.NewGCM(block)
90+
// if err != nil {
91+
92+
// return nil, fmt.Errorf("failed to create GCM: %w", err)
93+
94+
// }
95+
96+
// //extract nonce
97+
// nonceSize := gcm.NonceSize()
98+
// if len(ciphertext) < nonceSize {
99+
100+
// return nil, fmt.Errorf("ciphertext too short")
101+
102+
// }
103+
104+
// nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
105+
106+
// //decrypt data
107+
// plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
108+
// if err != nil {
109+
110+
// return nil, fmt.Errorf("failed to decrypt: %w", err)
111+
112+
// }
113+
114+
// return plaintext, nil
115+
// }
116+
117+
118+
119+
// derive a 32-byte key from password and salt using SHA-256
120+
func deriveKey(password string, salt []byte) []byte {
121+
hash := sha256.New()
122+
hash.Write([]byte(password))
123+
hash.Write(salt)
124+
return hash.Sum(nil)
125+
}
126+
127+
//create a random salt for key derivation
128+
func GenerateSalt() ([]byte, error) {
129+
salt := make([]byte, 32)
130+
_, err := rand.Read(salt)
131+
return salt, err
132+
}

0 commit comments

Comments
 (0)