Files
kopia/repo/encryption/encryption.go

103 lines
2.7 KiB
Go

// Package encryption manages content encryption algorithms.
package encryption
import (
"crypto/sha256"
"io"
"sort"
"github.com/pkg/errors"
"golang.org/x/crypto/hkdf"
)
const (
minDerivedKeyLength = 32
purposeEncryptionKey = "encryption"
)
// Encryptor performs encryption and decryption of contents of data.
type Encryptor interface {
// Encrypt appends the encrypted bytes corresponding to the given plaintext to a given slice.
// Must not clobber the input slice and return ciphertext with additional padding and checksum.
Encrypt(output, plainText, contentID []byte) ([]byte, error)
// Decrypt appends the unencrypted bytes corresponding to the given ciphertext to a given slice.
// Must not clobber the input slice. If IsAuthenticated() == true, Decrypt will perform
// authenticity check before decrypting.
Decrypt(output, cipherText, contentID []byte) ([]byte, error)
// Overhead is the number of bytes of overhead added by Encrypt()
Overhead() int
}
// Parameters encapsulates all encryption parameters.
type Parameters interface {
GetEncryptionAlgorithm() string
GetMasterKey() []byte
}
// CreateEncryptor creates an Encryptor for given parameters.
func CreateEncryptor(p Parameters) (Encryptor, error) {
e := encryptors[p.GetEncryptionAlgorithm()]
if e == nil {
return nil, errors.Errorf("unknown encryption algorithm: %v", p.GetEncryptionAlgorithm())
}
return e.newEncryptor(p)
}
// EncryptorFactory creates new Encryptor for given parameters.
type EncryptorFactory func(p Parameters) (Encryptor, error)
// DefaultAlgorithm is the name of the default encryption algorithm.
const DefaultAlgorithm = "AES256-GCM-HMAC-SHA256"
// SupportedAlgorithms returns the names of the supported encryption
// methods.
func SupportedAlgorithms(includeDeprecated bool) []string {
var result []string
for k, e := range encryptors {
if e.deprecated && !includeDeprecated {
continue
}
result = append(result, k)
}
sort.Strings(result)
return result
}
// Register registers new encryption algorithm.
func Register(name, description string, deprecated bool, newEncryptor EncryptorFactory) {
encryptors[name] = &encryptorInfo{
description,
deprecated,
newEncryptor,
}
}
type encryptorInfo struct {
description string
deprecated bool
newEncryptor EncryptorFactory
}
var encryptors = map[string]*encryptorInfo{}
// deriveKey uses HKDF to derive a key of a given length and a given purpose from parameters.
func deriveKey(p Parameters, purpose []byte, length int) ([]byte, error) {
if length < minDerivedKeyLength {
return nil, errors.Errorf("derived key must be at least 32 bytes, was %v", length)
}
key := make([]byte, length)
k := hkdf.New(sha256.New, p.GetMasterKey(), purpose, nil)
io.ReadFull(k, key) //nolint:errcheck
return key, nil
}