I am trying to encrypt some data, which works perfectly fine. However, when I try to decrypt it, it fails, because the keys differ after reading them from a file. Any help with this?
The issues I'm having are in the following functions:
- EncryptMapToFileWithKey
- DecryptMapFromFileWithKey
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/json"
"errors"
"fmt"
"io"
"os"
)
// NewEncryptionKey generates a random 256-bit key for Encrypt() and
// Decrypt(). It panics if the source of randomness fails.
func NewEncryptionKey() *[32]byte {
key := [32]byte{}
_, err := io.ReadFull(rand.Reader, key[:])
if err != nil {
panic(err)
}
return &key
}
func Encrypt(plaintext []byte, key *[32]byte) (ciphertext []byte, err error) {
block, err := aes.NewCipher(key[:])
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
nonce := make([]byte, gcm.NonceSize())
_, err = io.ReadFull(rand.Reader, nonce)
if err != nil {
return nil, err
}
return gcm.Seal(nonce, nonce, plaintext, nil), nil
}
// Decrypt decrypts data using 256-bit AES-GCM. This both hides the content of
// the data and provides a check that it hasn't been altered. Expects input
// form nonce|ciphertext|tag where '|' indicates concatenation.
func Decrypt(ciphertext []byte, key *[32]byte) (plaintext []byte, err error) {
block, err := aes.NewCipher(key[:])
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
if len(ciphertext) < gcm.NonceSize() {
return nil, errors.New("malformed ciphertext")
}
return gcm.Open(nil,
ciphertext[:gcm.NonceSize()],
ciphertext[gcm.NonceSize():],
nil,
)
}
func EncryptMapToFileWithKey(m map[string]string, filename string) ([]byte, error) {
key := NewEncryptionKey()
m["EXTRA_KEY"] = string(key[:])
encrypted, _ := EncryptMap(m, key)
encrypted_json, _ := json.Marshal(encrypted)
WriteFile(filename, encrypted_json)
fmt.Println(string(encrypted_json))
return encrypted_json, nil
}
func DecryptMapFromFileWithKey(filename string) (map[string]string, error) {
encrypted_json, _ := ReadFile(filename)
encrypted := make(map[string]string)
json.Unmarshal(encrypted_json, &encrypted)
key := [32]byte{}
copy(key[:], encrypted["EXTRA_KEY"])
return DecryptMap(encrypted, &key)
}
func WriteFile(filename string, data []byte) error {
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
_, err = f.Write(data)
return err
}
func ReadFile(filename string) ([]byte, error) {
f, err := os.Open(filename)
if err != nil {
return nil, err
}
defer f.Close()
return io.ReadAll(f)
}
func EncryptMap(m map[string]string, key *[32]byte) (map[string]string, error) {
encrypted := make(map[string]string)
var err error
for k, v := range m {
encrypted[k], err = EncryptString(v, key)
if err != nil {
return nil, err
}
}
return encrypted, nil
}
func DecryptMap(m map[string]string, key *[32]byte) (map[string]string, error) {
decrypted := make(map[string]string)
var err error
for k, v := range m {
decrypted[k], err = DecryptString(v, key)
if err != nil {
return nil, err
}
}
return decrypted, nil
}
The way I intend to use the functions:
dir, err := os.UserConfigDir()
if err != nil {
fmt.Println(err)
}
path := dir + "\\TEST\\"
map_to_encrypt := map[string]string{
"data1": "dummydata_one",
"data2": "dummydata_two",
"data3": "dummydata_three",
}
encrypted, _ := EncryptMapToFileWithKey(map_to_encrypt, path+"\\test.enc")
fmt.Println(encrypted)
decrypted, _ := DecryptMapFromFileWithKey(path + "\\test.enc")
fmt.Println(decrypted)
Example output of the 'error':
Key used to encrypt:
[211 151 223 79 217 102 199 23 93 38 120 147 35 236 3 166 46 23 157 80 182 91 14 126 181 16 104 156 48 2 89 57]
Key being retrieved from the file:
[120 70 75 73 101 99 83 109 99 106 54 50 79 109 47 65 69 117 111 57 115 121 53 115 122 47 55 104 80 85 115 108]
The key (string version) in the file being written:
xFKIecSmcj62Om/AEuo9sy5sz/7hPUslfqF5O5rhlQgbzMvzWG6UyAsArNPSDm6mOWmdfdqwcj6HsHCG
The key in the file being read:
xFKIecSmcj62Om/AEuo9sy5sz/7hPUslfqF5O5rhlQgbzMvzWG6UyAsArNPSDm6mOWmdfdqwcj6HsHCG
Because the string(encrypted_json) is the same as the decrypted JSON from the file; I think the error might be when I'm trying to write the key to the file, but I don't really understand what's going wrong.