aboutsummaryrefslogtreecommitdiff
path: root/backend/security/encrypt.go
diff options
context:
space:
mode:
authorJacky Zhao <[email protected]>2020-05-15 18:53:37 -0700
committerGitHub <[email protected]>2020-05-15 18:53:37 -0700
commit2e4a87393d6fdf0320696faedecdc7699289fffb (patch)
tree7afe72a155fd9f6afd1bdded4a214b6fbba77fa0 /backend/security/encrypt.go
parentMerge pull request #24 from jackyzha0/update-readme (diff)
parentAdd comments and clean up encryption (diff)
downloadctrl-v-2e4a87393d6fdf0320696faedecdc7699289fffb.tar.xz
ctrl-v-2e4a87393d6fdf0320696faedecdc7699289fffb.zip
Merge pull request #25 from jackyzha0/security
Add encryption to content when password is specified
Diffstat (limited to 'backend/security/encrypt.go')
-rw-r--r--backend/security/encrypt.go81
1 files changed, 81 insertions, 0 deletions
diff --git a/backend/security/encrypt.go b/backend/security/encrypt.go
new file mode 100644
index 0000000..4af5e3c
--- /dev/null
+++ b/backend/security/encrypt.go
@@ -0,0 +1,81 @@
+package security
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/rand"
+ "errors"
+ "golang.org/x/crypto/scrypt"
+)
+
+var EncryptionError = errors.New("could not encrypt the given content")
+
+func Encrypt(key, data string) (string, error) {
+ // initialize aes block cipher with given key
+ blockCipher, err := aes.NewCipher([]byte(key))
+ if err != nil {
+ return "", err
+ }
+
+ // wrap block cipher with Galois Counter Mode and standard nonce length
+ gcm, err := cipher.NewGCM(blockCipher)
+ if err != nil {
+ return "", err
+ }
+
+ // generate nonce (number once used) unique to the given key
+ nonce := make([]byte, gcm.NonceSize())
+ if _, err = rand.Read(nonce); err != nil {
+ return "", err
+ }
+
+ // seal nonce with data to use during decryption
+ cipherText := gcm.Seal(nonce, nonce, []byte(data), nil)
+
+ return string(cipherText), nil
+}
+
+func Decrypt(key, data string) (string, error) {
+ // similar to encrypt, create cipher and wrap with GCM
+ blockCipher, err := aes.NewCipher([]byte(key))
+ if err != nil {
+ return "", err
+ }
+
+ gcm, err := cipher.NewGCM(blockCipher)
+ if err != nil {
+ return "", err
+ }
+
+ // extract the nonce from the data
+ nonce, cipherText := data[:gcm.NonceSize()], data[gcm.NonceSize():]
+
+ // use nonce to decrypt the data
+ plaintext, err := gcm.Open(nil, []byte(nonce), []byte(cipherText), nil)
+ if err != nil {
+ return "", err
+ }
+
+ return string(plaintext), nil
+}
+
+const keyBytes = 16
+const iterations = 16384
+const relativeMemoryCost = 8
+const relativeCPUCost = 1
+
+func DeriveKey(password string, salt []byte) (string, []byte, error) {
+ if salt == nil {
+ salt = make([]byte, keyBytes)
+ if _, err := rand.Read(salt); err != nil {
+ return "", nil, err
+ }
+ }
+
+ key, err := scrypt.Key([]byte(password), salt, iterations, relativeMemoryCost, relativeCPUCost, keyBytes)
+ if err != nil {
+ return "", nil, err
+ }
+
+ return string(key), salt, nil
+}