106 lines
2.1 KiB
Go
106 lines
2.1 KiB
Go
|
package s3crypto
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"crypto/aes"
|
||
|
"crypto/cipher"
|
||
|
"io"
|
||
|
"io/ioutil"
|
||
|
)
|
||
|
|
||
|
// AESGCM Symmetric encryption algorithm. Since Golang designed this
|
||
|
// with only TLS in mind. We have to load it all into memory meaning
|
||
|
// this isn't streamed.
|
||
|
type aesGCM struct {
|
||
|
aead cipher.AEAD
|
||
|
nonce []byte
|
||
|
}
|
||
|
|
||
|
// newAESGCM creates a new AES GCM cipher. Expects keys to be of
|
||
|
// the correct size.
|
||
|
//
|
||
|
// Example:
|
||
|
//
|
||
|
// cd := &s3crypto.CipherData{
|
||
|
// Key: key,
|
||
|
// "IV": iv,
|
||
|
// }
|
||
|
// cipher, err := s3crypto.newAESGCM(cd)
|
||
|
func newAESGCM(cd CipherData) (Cipher, error) {
|
||
|
block, err := aes.NewCipher(cd.Key)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
aesgcm, err := cipher.NewGCM(block)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return &aesGCM{aesgcm, cd.IV}, nil
|
||
|
}
|
||
|
|
||
|
// Encrypt will encrypt the data using AES GCM
|
||
|
// Tag will be included as the last 16 bytes of the slice
|
||
|
func (c *aesGCM) Encrypt(src io.Reader) io.Reader {
|
||
|
reader := &gcmEncryptReader{
|
||
|
encrypter: c.aead,
|
||
|
nonce: c.nonce,
|
||
|
src: src,
|
||
|
}
|
||
|
return reader
|
||
|
}
|
||
|
|
||
|
type gcmEncryptReader struct {
|
||
|
encrypter cipher.AEAD
|
||
|
nonce []byte
|
||
|
src io.Reader
|
||
|
buf *bytes.Buffer
|
||
|
}
|
||
|
|
||
|
func (reader *gcmEncryptReader) Read(data []byte) (int, error) {
|
||
|
if reader.buf == nil {
|
||
|
b, err := ioutil.ReadAll(reader.src)
|
||
|
if err != nil {
|
||
|
return len(b), err
|
||
|
}
|
||
|
b = reader.encrypter.Seal(b[:0], reader.nonce, b, nil)
|
||
|
reader.buf = bytes.NewBuffer(b)
|
||
|
}
|
||
|
|
||
|
return reader.buf.Read(data)
|
||
|
}
|
||
|
|
||
|
// Decrypt will decrypt the data using AES GCM
|
||
|
func (c *aesGCM) Decrypt(src io.Reader) io.Reader {
|
||
|
return &gcmDecryptReader{
|
||
|
decrypter: c.aead,
|
||
|
nonce: c.nonce,
|
||
|
src: src,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type gcmDecryptReader struct {
|
||
|
decrypter cipher.AEAD
|
||
|
nonce []byte
|
||
|
src io.Reader
|
||
|
buf *bytes.Buffer
|
||
|
}
|
||
|
|
||
|
func (reader *gcmDecryptReader) Read(data []byte) (int, error) {
|
||
|
if reader.buf == nil {
|
||
|
b, err := ioutil.ReadAll(reader.src)
|
||
|
if err != nil {
|
||
|
return len(b), err
|
||
|
}
|
||
|
b, err = reader.decrypter.Open(b[:0], reader.nonce, b, nil)
|
||
|
if err != nil {
|
||
|
return len(b), err
|
||
|
}
|
||
|
|
||
|
reader.buf = bytes.NewBuffer(b)
|
||
|
}
|
||
|
|
||
|
return reader.buf.Read(data)
|
||
|
}
|