storj/pkg/eestream/secretbox.go

108 lines
3.0 KiB
Go

// Copyright (C) 2018 Storj Labs, Inc.
// See LICENSE for copying information.
package eestream
import (
"golang.org/x/crypto/nacl/secretbox"
)
type secretboxEncrypter struct {
blockSize int
key [32]byte
startingNonce [24]byte
}
// NewSecretboxEncrypter 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 NewSecretboxEncrypter(key *[32]byte, startingNonce *[24]byte,
encryptedBlockSize int) (Transformer, error) {
if encryptedBlockSize <= secretbox.Overhead {
return nil, Error.New("block size too small")
}
return &secretboxEncrypter{
blockSize: encryptedBlockSize - secretbox.Overhead,
key: *key,
startingNonce: *startingNonce,
}, nil
}
func (s *secretboxEncrypter) InBlockSize() int {
return s.blockSize
}
func (s *secretboxEncrypter) OutBlockSize() int {
return s.blockSize + secretbox.Overhead
}
func calcNonce(startingNonce *[24]byte, blockNum int64) (rv [24]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 *secretboxEncrypter) Transform(out, in []byte, blockNum int64) (
[]byte, error) {
n, err := calcNonce(&s.startingNonce, blockNum)
if err != nil {
return nil, err
}
return secretbox.Seal(out, in, &n, &s.key), nil
}
type secretboxDecrypter struct {
blockSize int
key [32]byte
startingNonce [24]byte
}
// NewSecretboxDecrypter returns a Transformer that decrypts the data passing
// through with key. See the comments for NewSecretboxEncrypter about
// startingNonce.
func NewSecretboxDecrypter(key *[32]byte, startingNonce *[24]byte,
encryptedBlockSize int) (Transformer, error) {
if encryptedBlockSize <= secretbox.Overhead {
return nil, Error.New("block size too small")
}
return &secretboxDecrypter{
blockSize: encryptedBlockSize - secretbox.Overhead,
key: *key,
startingNonce: *startingNonce,
}, nil
}
func (s *secretboxDecrypter) InBlockSize() int {
return s.blockSize + secretbox.Overhead
}
func (s *secretboxDecrypter) OutBlockSize() int {
return s.blockSize
}
func (s *secretboxDecrypter) Transform(out, in []byte, blockNum int64) (
[]byte, error) {
n, err := calcNonce(&s.startingNonce, blockNum)
if err != nil {
return nil, err
}
rv, success := secretbox.Open(out, in, &n, &s.key)
if !success {
return nil, Error.New("failed decrypting")
}
return rv, nil
}