2018-05-15 16:11:03 +01:00
|
|
|
// Copyright (C) 2018 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package eestream
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/aes"
|
|
|
|
"crypto/cipher"
|
2018-09-26 14:32:23 +01:00
|
|
|
|
|
|
|
"github.com/zeebo/errs"
|
2018-05-15 16:11:03 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
type aesgcmEncrypter struct {
|
|
|
|
blockSize int
|
2018-09-26 14:32:23 +01:00
|
|
|
key Key
|
|
|
|
startingNonce AESGCMNonce
|
2018-05-15 16:11:03 +01:00
|
|
|
overhead int
|
|
|
|
aesgcm cipher.AEAD
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewAESGCMEncrypter returns a Transformer that encrypts the data passing
|
|
|
|
// through with key.
|
|
|
|
//
|
|
|
|
// startingNonce is treated as a big-endian encoded unsigned
|
|
|
|
// integer, and as blocks pass through, their block number and the starting
|
|
|
|
// nonce is added together to come up with that block's nonce. Encrypting
|
|
|
|
// different data with the same key and the same nonce is a huge security
|
|
|
|
// issue. It's safe to always encode new data with a random key and random
|
|
|
|
// startingNonce. The monotonically-increasing nonce (that rolls over) is to
|
|
|
|
// protect against data reordering.
|
|
|
|
//
|
|
|
|
// When in doubt, generate a new key from crypto/rand and a startingNonce
|
|
|
|
// from crypto/rand as often as possible.
|
2018-09-26 14:32:23 +01:00
|
|
|
func NewAESGCMEncrypter(key *Key, startingNonce *AESGCMNonce, encryptedBlockSize int) (Transformer, error) {
|
2018-05-15 16:11:03 +01:00
|
|
|
block, err := aes.NewCipher((*key)[:])
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
aesgcmEncrypt, err := cipher.NewGCM(block)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if encryptedBlockSize <= aesgcmEncrypt.Overhead() {
|
|
|
|
return nil, Error.New("block size too small")
|
|
|
|
}
|
|
|
|
return &aesgcmEncrypter{
|
|
|
|
blockSize: encryptedBlockSize - aesgcmEncrypt.Overhead(),
|
|
|
|
key: *key,
|
|
|
|
startingNonce: *startingNonce,
|
|
|
|
overhead: aesgcmEncrypt.Overhead(),
|
|
|
|
aesgcm: aesgcmEncrypt,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *aesgcmEncrypter) InBlockSize() int {
|
|
|
|
return s.blockSize
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *aesgcmEncrypter) OutBlockSize() int {
|
|
|
|
return s.blockSize + s.overhead
|
|
|
|
}
|
|
|
|
|
2018-09-26 14:32:23 +01:00
|
|
|
func calcGCMNonce(startingNonce *AESGCMNonce, blockNum int64) (rv [12]byte, err error) {
|
2018-05-15 16:11:03 +01:00
|
|
|
if copy(rv[:], (*startingNonce)[:]) != len(rv) {
|
|
|
|
return rv, Error.New("didn't copy memory?!")
|
|
|
|
}
|
|
|
|
_, err = incrementBytes(rv[:], blockNum)
|
|
|
|
return rv, err
|
|
|
|
}
|
|
|
|
|
2018-09-26 14:32:23 +01:00
|
|
|
func (s *aesgcmEncrypter) Transform(out, in []byte, blockNum int64) ([]byte, error) {
|
2018-05-15 16:11:03 +01:00
|
|
|
n, err := calcGCMNonce(&s.startingNonce, blockNum)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
ciphertext := s.aesgcm.Seal(out, n[:], in, nil)
|
|
|
|
return ciphertext, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type aesgcmDecrypter struct {
|
|
|
|
blockSize int
|
2018-09-26 14:32:23 +01:00
|
|
|
key Key
|
|
|
|
startingNonce AESGCMNonce
|
2018-05-15 16:11:03 +01:00
|
|
|
overhead int
|
|
|
|
aesgcm cipher.AEAD
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewAESGCMDecrypter returns a Transformer that decrypts the data passing
|
|
|
|
// through with key. See the comments for NewAESGCMEncrypter about
|
|
|
|
// startingNonce.
|
2018-09-26 14:32:23 +01:00
|
|
|
func NewAESGCMDecrypter(key *Key, startingNonce *AESGCMNonce, encryptedBlockSize int) (Transformer, error) {
|
2018-10-03 14:05:40 +01:00
|
|
|
block, err := aes.NewCipher(key[:])
|
2018-05-15 16:11:03 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
aesgcmDecrypt, err := cipher.NewGCM(block)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if encryptedBlockSize <= aesgcmDecrypt.Overhead() {
|
|
|
|
return nil, Error.New("block size too small")
|
|
|
|
}
|
|
|
|
return &aesgcmDecrypter{
|
|
|
|
blockSize: encryptedBlockSize - aesgcmDecrypt.Overhead(),
|
|
|
|
key: *key,
|
|
|
|
startingNonce: *startingNonce,
|
|
|
|
overhead: aesgcmDecrypt.Overhead(),
|
|
|
|
aesgcm: aesgcmDecrypt,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
func (s *aesgcmDecrypter) InBlockSize() int {
|
|
|
|
return s.blockSize + s.overhead
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *aesgcmDecrypter) OutBlockSize() int {
|
|
|
|
return s.blockSize
|
|
|
|
}
|
|
|
|
|
2018-09-26 14:32:23 +01:00
|
|
|
func (s *aesgcmDecrypter) Transform(out, in []byte, blockNum int64) ([]byte, error) {
|
2018-05-15 16:11:03 +01:00
|
|
|
n, err := calcGCMNonce(&s.startingNonce, blockNum)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.aesgcm.Open(out, n[:], in, nil)
|
|
|
|
}
|
2018-09-26 14:32:23 +01:00
|
|
|
|
|
|
|
// EncryptAESGCM encrypts byte data with a key and nonce. The cipher data is returned
|
2018-10-03 14:05:40 +01:00
|
|
|
func EncryptAESGCM(data []byte, key *Key, nonce *AESGCMNonce) (cipherData []byte, err error) {
|
|
|
|
block, err := aes.NewCipher(key[:])
|
2018-09-26 14:32:23 +01:00
|
|
|
if err != nil {
|
|
|
|
return []byte{}, errs.Wrap(err)
|
|
|
|
}
|
|
|
|
aesgcm, err := cipher.NewGCM(block)
|
|
|
|
if err != nil {
|
|
|
|
return []byte{}, errs.Wrap(err)
|
|
|
|
}
|
2018-10-03 14:05:40 +01:00
|
|
|
cipherData = aesgcm.Seal(nil, nonce[:], data, nil)
|
2018-09-26 14:32:23 +01:00
|
|
|
return cipherData, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// DecryptAESGCM decrypts byte data with a key and nonce. The plain data is returned
|
2018-10-03 14:05:40 +01:00
|
|
|
func DecryptAESGCM(cipherData []byte, key *Key, nonce *AESGCMNonce) (data []byte, err error) {
|
2018-09-26 14:32:23 +01:00
|
|
|
if len(cipherData) == 0 {
|
|
|
|
return []byte{}, errs.New("empty cipher data")
|
|
|
|
}
|
2018-10-03 14:05:40 +01:00
|
|
|
block, err := aes.NewCipher(key[:])
|
2018-09-26 14:32:23 +01:00
|
|
|
if err != nil {
|
|
|
|
return []byte{}, errs.Wrap(err)
|
|
|
|
}
|
|
|
|
aesgcm, err := cipher.NewGCM(block)
|
|
|
|
if err != nil {
|
|
|
|
return []byte{}, errs.Wrap(err)
|
|
|
|
}
|
2018-10-03 14:05:40 +01:00
|
|
|
decrypted, err := aesgcm.Open(nil, nonce[:], cipherData, nil)
|
2018-09-26 14:32:23 +01:00
|
|
|
if err != nil {
|
|
|
|
return []byte{}, errs.Wrap(err)
|
|
|
|
}
|
|
|
|
return decrypted, nil
|
|
|
|
}
|