mirror of
https://github.com/kataras/iris.git
synced 2025-01-24 03:01:03 +01:00
135 lines
2.8 KiB
Go
135 lines
2.8 KiB
Go
|
// Package gcm implements encryption/decription using the AES algorithm and the Galois/Counter Mode.
|
||
|
package gcm
|
||
|
|
||
|
import (
|
||
|
"crypto/aes"
|
||
|
"crypto/cipher"
|
||
|
"crypto/rand"
|
||
|
"crypto/sha512"
|
||
|
"encoding/hex"
|
||
|
)
|
||
|
|
||
|
// MustGenerateKey generates an aes key.
|
||
|
// It panics if any error occurred.
|
||
|
func MustGenerateKey() []byte {
|
||
|
aesKey, err := GenerateKey()
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
|
||
|
return aesKey
|
||
|
}
|
||
|
|
||
|
// GenerateKey returns a random aes key.
|
||
|
func GenerateKey() ([]byte, error) {
|
||
|
key := make([]byte, 64)
|
||
|
n, err := rand.Read(key)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return encode(key[:n]), nil
|
||
|
}
|
||
|
|
||
|
// Encrypt encrypts and authenticates the plain data and additional data
|
||
|
// and returns the ciphertext of it.
|
||
|
// It uses the AEAD cipher mode providing authenticated encryption with associated
|
||
|
// data.
|
||
|
// The same additional data must be kept the same for `Decrypt`.
|
||
|
func Encrypt(aesKey, data, additionalData []byte) ([]byte, error) {
|
||
|
key, err := decode(aesKey)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
h := sha512.New()
|
||
|
h.Write(key)
|
||
|
digest := encode(h.Sum(nil))
|
||
|
|
||
|
// key based on the hash itself, we have space because of sha512.
|
||
|
newKey, err := decode(digest[:64])
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
// nonce based on the hash itself.
|
||
|
nonce, err := decode(digest[64:(64 + 24)])
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
aData, err := decode(additionalData)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
block, err := aes.NewCipher(newKey)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
gcm, err := cipher.NewGCM(block)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
ciphertext := encode(gcm.Seal(nil, nonce, data, aData))
|
||
|
return ciphertext, nil
|
||
|
}
|
||
|
|
||
|
// Decrypt decrypts and authenticates ciphertext, authenticates the
|
||
|
// additional data and, if successful, returns the resulting plain data.
|
||
|
// The additional data must match the value passed to `Encrypt`.
|
||
|
func Decrypt(aesKey, ciphertext, additionalData []byte) ([]byte, error) {
|
||
|
key, err := decode(aesKey)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
h := sha512.New()
|
||
|
h.Write(key)
|
||
|
digest := encode(h.Sum(nil))
|
||
|
|
||
|
newKey, err := decode(digest[:64])
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
nonce, err := decode(digest[64:(64 + 24)])
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
additionalData, err = decode(additionalData)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
block, err := aes.NewCipher(newKey)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
gcm, err := cipher.NewGCM(block)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
ciphertext, err = decode(ciphertext)
|
||
|
return gcm.Open(nil, nonce, ciphertext, additionalData)
|
||
|
}
|
||
|
|
||
|
func decode(src []byte) ([]byte, error) {
|
||
|
buf := make([]byte, hex.DecodedLen(len(src)))
|
||
|
n, err := hex.Decode(buf, src)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return buf[:n], nil
|
||
|
}
|
||
|
|
||
|
func encode(src []byte) []byte {
|
||
|
buf := make([]byte, hex.EncodedLen(len(src)))
|
||
|
hex.Encode(buf, src)
|
||
|
return buf
|
||
|
}
|