diff options
Diffstat (limited to 'internal/encryption/encryption.go')
-rw-r--r-- | internal/encryption/encryption.go | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/internal/encryption/encryption.go b/internal/encryption/encryption.go new file mode 100644 index 0000000..0f9c748 --- /dev/null +++ b/internal/encryption/encryption.go @@ -0,0 +1,93 @@ +package encryption + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/base64" + "errors" + "io" + "strings" +) + +func addBase64Padding(value string) string { + m := len(value) % 4 + if m != 0 { + value += strings.Repeat("=", 4-m) + } + + return value +} + +func removeBase64Padding(value string) string { + return strings.Replace(value, "=", "", -1) +} + +func pad(src []byte) []byte { + padding := aes.BlockSize - len(src)%aes.BlockSize + padtext := bytes.Repeat([]byte{byte(padding)}, padding) + + return append(src, padtext...) +} + +func Unpad(src []byte) ([]byte, error) { + length := len(src) + unpadding := int(src[length-1]) + + if unpadding > length { + return nil, errors.New("unpad error. This could happen when incorrect encryption key is used") + } + + return src[:(length - unpadding)], nil +} + +func Encrypt(key []byte, text string) (string, error) { + block, err := aes.NewCipher(key) + if err != nil { + return "", err + } + + msg := pad([]byte(text)) + ciphertext := make([]byte, aes.BlockSize+len(msg)) + iv := ciphertext[:aes.BlockSize] + + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return "", err + } + + cfb := cipher.NewCFBEncrypter(block, iv) + cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(msg)) + finalMsg := removeBase64Padding(base64.URLEncoding.EncodeToString(ciphertext)) + + return finalMsg, nil +} + +func Decrypt(key []byte, text string) (string, error) { + block, err := aes.NewCipher(key) + if err != nil { + return "", err + } + + decodedMsg, err := base64.URLEncoding.DecodeString(addBase64Padding(text)) + if err != nil { + return "", err + } + + if (len(decodedMsg) % aes.BlockSize) != 0 { + return "", errors.New("blocksize must be multipe of decoded message length") + } + + iv := decodedMsg[:aes.BlockSize] + msg := decodedMsg[aes.BlockSize:] + + cfb := cipher.NewCFBDecrypter(block, iv) + cfb.XORKeyStream(msg, msg) + + unpadMsg, err := Unpad(msg) + if err != nil { + return "", err + } + + return string(unpadMsg), nil +} |