storj/pkg/eestream/aesgcm.go
aligeti 0376dc4bd2 AES GCM implementation and unit test code (#19)
* AES GCM implementation and unit test code

* modified and tested per the code review comments

* modified and tested per the code review comments

* updated to return err

* removed the debug printf commented code

* support of aes-gcm

* updated the renaming convention per GOLANG coding standards

* Initial Go & C biniding with libstorj

* Initial GO & C bindings with libstorj

* fixing the callback

* moved a millimeter :-) on c to go to gone....

*  added error condition, per review comment

* removed the .idea directory and also movie.avi file

* deleting files not to be in this pull request

* Revert "deleting files not to be in this pull request"

This reverts commit 026b834fe00f6b20a7566e71973fe224c12f533f.

* deleting files not to be in this pull request

* resolving conflicts

* syncing the file to master

* Use aes gcm in eestream rs tests

* Use aes gcm in serve example

* Fixed comment
2018-05-15 18:11:03 +03:00

131 lines
3.4 KiB
Go

// Copyright (C) 2018 Storj Labs, Inc.
// See LICENSE for copying information.
package eestream
import (
"crypto/aes"
"crypto/cipher"
)
type aesgcmEncrypter struct {
blockSize int
key [32]byte
startingNonce [12]byte
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.
func NewAESGCMEncrypter(key *[32]byte, startingNonce *[12]byte,
encryptedBlockSize int) (Transformer, error) {
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
}
func calcGCMNonce(startingNonce *[12]byte, blockNum int64) (rv [12]byte,
err error) {
if copy(rv[:], (*startingNonce)[:]) != len(rv) {
return rv, Error.New("didn't copy memory?!")
}
_, err = incrementBytes(rv[:], blockNum)
return rv, err
}
func (s *aesgcmEncrypter) Transform(out, in []byte, blockNum int64) (
[]byte, error) {
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
key [32]byte
startingNonce [12]byte
overhead int
aesgcm cipher.AEAD
}
// NewAESGCMDecrypter returns a Transformer that decrypts the data passing
// through with key. See the comments for NewAESGCMEncrypter about
// startingNonce.
func NewAESGCMDecrypter(key *[32]byte, startingNonce *[12]byte,
encryptedBlockSize int) (Transformer, error) {
block, err := aes.NewCipher((*key)[:])
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
}
func (s *aesgcmDecrypter) Transform(out, in []byte, blockNum int64) (
[]byte, error) {
n, err := calcGCMNonce(&s.startingNonce, blockNum)
if err != nil {
return nil, err
}
return s.aesgcm.Open(out, n[:], in, nil)
}