refactor(repository): refactored Crypter to an unexported interface (#2251)

This commit is contained in:
Jarek Kowalski
2022-07-30 07:57:56 -07:00
committed by GitHub
parent 80dd5a7f7e
commit 30456d13e7
23 changed files with 141 additions and 190 deletions

View File

@@ -67,12 +67,19 @@ func (c *commandBenchmarkCrypto) runBenchmark(ctx context.Context) []cryptoBench
for _, ha := range hashing.SupportedAlgorithms() {
for _, ea := range encryption.SupportedAlgorithms(c.deprecatedAlgorithms) {
cr, err := content.CreateCrypter(&content.FormattingOptions{
fo := &content.FormattingOptions{
Encryption: ea,
Hash: ha,
MasterKey: make([]byte, 32), // nolint:gomnd
HMACSecret: make([]byte, 32), // nolint:gomnd
})
}
hf, err := hashing.CreateHashFunc(fo)
if err != nil {
continue
}
enc, err := encryption.CreateEncryptor(fo)
if err != nil {
continue
}
@@ -91,9 +98,9 @@ func (c *commandBenchmarkCrypto) runBenchmark(ctx context.Context) []cryptoBench
defer encryptOutput.Close()
for i := 0; i < hashCount; i++ {
contentID := cr.HashFunction(hashOutput[:0], input)
contentID := hf(hashOutput[:0], input)
if encerr := cr.Encryptor.Encrypt(input, contentID, &encryptOutput); encerr != nil {
if encerr := enc.Encrypt(input, contentID, &encryptOutput); encerr != nil {
log(ctx).Errorf("encryption failed: %v", encerr)
break
}

View File

@@ -66,7 +66,7 @@ func (c *commandBenchmarkEncryption) runBenchmark(ctx context.Context) []cryptoB
data := make([]byte, c.blockSize)
for _, ea := range encryption.SupportedAlgorithms(c.deprecatedAlgorithms) {
cr, err := content.CreateCrypter(&content.FormattingOptions{
enc, err := encryption.CreateEncryptor(&content.FormattingOptions{
Encryption: ea,
Hash: hashing.DefaultAlgorithm,
MasterKey: make([]byte, 32), // nolint:gomnd
@@ -90,7 +90,7 @@ func (c *commandBenchmarkEncryption) runBenchmark(ctx context.Context) []cryptoB
defer encryptOutput.Close()
for i := 0; i < hashCount; i++ {
if encerr := cr.Encryptor.Encrypt(input, hashOutput[:32], &encryptOutput); encerr != nil {
if encerr := enc.Encrypt(input, hashOutput[:32], &encryptOutput); encerr != nil {
log(ctx).Errorf("encryption failed: %v", encerr)
break
}

View File

@@ -10,7 +10,6 @@
"github.com/kopia/kopia/internal/timetrack"
"github.com/kopia/kopia/internal/units"
"github.com/kopia/kopia/repo/content"
"github.com/kopia/kopia/repo/encryption"
"github.com/kopia/kopia/repo/hashing"
)
@@ -64,10 +63,8 @@ func (c *commandBenchmarkHashing) runBenchmark(ctx context.Context) []cryptoBenc
data := make([]byte, c.blockSize)
for _, ha := range hashing.SupportedAlgorithms() {
cr, err := content.CreateCrypter(&content.FormattingOptions{
Encryption: encryption.DefaultAlgorithm,
hf, err := hashing.CreateHashFunc(&content.FormattingOptions{
Hash: ha,
MasterKey: make([]byte, 32), // nolint:gomnd
HMACSecret: make([]byte, 32), // nolint:gomnd
})
if err != nil {
@@ -85,7 +82,7 @@ func (c *commandBenchmarkHashing) runBenchmark(ctx context.Context) []cryptoBenc
var hashOutput [hashing.MaxHashSize]byte
for i := 0; i < hashCount; i++ {
cr.HashFunction(hashOutput[:0], input)
hf(hashOutput[:0], input)
}
return nil

View File

@@ -12,6 +12,7 @@
"github.com/kopia/kopia/internal/iocopy"
"github.com/kopia/kopia/repo"
"github.com/kopia/kopia/repo/blob"
"github.com/kopia/kopia/repo/content"
)
type commandBlobShow struct {
@@ -56,7 +57,7 @@ func (c *commandBlobShow) maybeDecryptBlob(ctx context.Context, w io.Writer, rep
var tmp gather.WriteBuffer
defer tmp.Close()
if err := rep.Crypter().DecryptBLOB(b, blobID, &tmp); err != nil {
if err := content.DecryptBLOB(rep.ContentReader().ContentFormat(), b, blobID, &tmp); err != nil {
return errors.Wrap(err, "error decrypting blob")
}

View File

@@ -162,7 +162,7 @@ func (c *commandIndexInspect) inspectSingleIndexBlob(ctx context.Context, rep re
return errors.Wrapf(err, "unable to get data for %v", blobID)
}
entries, err := content.ParseIndexBlob(ctx, blobID, data.Bytes(), rep.Crypter())
entries, err := content.ParseIndexBlob(ctx, blobID, data.Bytes(), rep.ContentReader().ContentFormat())
if err != nil {
return errors.Wrapf(err, "unable to recover index from %v", blobID)
}

View File

@@ -7,6 +7,7 @@
"github.com/kopia/kopia/internal/gather"
"github.com/kopia/kopia/repo"
"github.com/kopia/kopia/repo/content"
)
type commandLogsShow struct {
@@ -69,7 +70,7 @@ func (c *commandLogsShow) run(ctx context.Context, rep repo.DirectRepository) er
return errors.Wrap(err, "error getting log")
}
if err := rep.Crypter().DecryptBLOB(data.Bytes(), bm.BlobID, &decrypted); err != nil {
if err := content.DecryptBLOB(rep.ContentReader().ContentFormat(), data.Bytes(), bm.BlobID, &decrypted); err != nil {
return errors.Wrap(err, "error decrypting log")
}

View File

@@ -124,7 +124,7 @@ func (c *commandRepositorySetParameters) setRetentionModeParameter(ctx context.C
func (c *commandRepositorySetParameters) run(ctx context.Context, rep repo.DirectRepositoryWriter) error {
var anyChange bool
mp := rep.ContentReader().ContentFormat().GetMutableParameters()
mp := rep.ContentReader().ContentFormat().Struct().MutableParameters
blobcfg := rep.BlobCfg()
requiredFeatures, err := rep.RequiredFeatures()

View File

@@ -13,25 +13,15 @@
"github.com/kopia/kopia/repo/hashing"
)
// Crypter ecapsulates hashing and encryption and provides utilities for whole-BLOB encryption.
// Whole-BLOB encryption relies on BLOB identifiers formatted as:
//
// <prefix><hash>[-optionalSuffix]
//
// Where:
// 'prefix' is arbitrary string without dashes
// 'hash' is base16-encoded 128-bit hash of contents, used as initialization vector (IV)
// for the encryption. In case of longer hash functions, we use last 16 bytes of
// their outputs.
// 'optionalSuffix' can be any string
type Crypter struct {
HashFunction hashing.HashFunc
Encryptor encryption.Encryptor
// crypter ecapsulates hashing and encryption.
type crypter interface {
HashFunc() hashing.HashFunc
Encryptor() encryption.Encryptor
}
// getIndexBlobIV gets the initialization vector from the provided blob ID by taking
// 32 characters immediately preceding the first dash ('-') and decoding them using base16.
func (c *Crypter) getIndexBlobIV(s blob.ID) ([]byte, error) {
func getIndexBlobIV(s blob.ID) ([]byte, error) {
if p := strings.Index(string(s), "-"); p >= 0 { // nolint:gocritic
s = s[0:p]
}
@@ -50,24 +40,24 @@ func (c *Crypter) getIndexBlobIV(s blob.ID) ([]byte, error) {
// EncryptBLOB encrypts the given data using crypter-defined key and returns a name that should
// be used to save the blob in thre repository.
func (c *Crypter) EncryptBLOB(payload gather.Bytes, prefix blob.ID, sessionID SessionID, output *gather.WriteBuffer) (blob.ID, error) {
func EncryptBLOB(c crypter, payload gather.Bytes, prefix blob.ID, sessionID SessionID, output *gather.WriteBuffer) (blob.ID, error) {
var hashOutput [hashing.MaxHashSize]byte
hash := c.HashFunction(hashOutput[:0], payload)
hash := c.HashFunc()(hashOutput[:0], payload)
blobID := prefix + blob.ID(hex.EncodeToString(hash))
if sessionID != "" {
blobID += blob.ID("-" + sessionID)
}
iv, err := c.getIndexBlobIV(blobID)
iv, err := getIndexBlobIV(blobID)
if err != nil {
return "", err
}
output.Reset()
if err := c.Encryptor.Encrypt(payload, iv, output); err != nil {
if err := c.Encryptor().Encrypt(payload, iv, output); err != nil {
return "", errors.Wrapf(err, "error encrypting BLOB %v", blobID)
}
@@ -75,8 +65,8 @@ func (c *Crypter) EncryptBLOB(payload gather.Bytes, prefix blob.ID, sessionID Se
}
// DecryptBLOB decrypts the provided data using provided blobID to derive initialization vector.
func (c *Crypter) DecryptBLOB(payload gather.Bytes, blobID blob.ID, output *gather.WriteBuffer) error {
iv, err := c.getIndexBlobIV(blobID)
func DecryptBLOB(c crypter, payload gather.Bytes, blobID blob.ID, output *gather.WriteBuffer) error {
iv, err := getIndexBlobIV(blobID)
if err != nil {
return errors.Wrap(err, "unable to get index blob IV")
}
@@ -84,7 +74,7 @@ func (c *Crypter) DecryptBLOB(payload gather.Bytes, blobID blob.ID, output *gath
output.Reset()
// Decrypt will verify the payload.
if err := c.Encryptor.Decrypt(payload, iv, output); err != nil {
if err := c.Encryptor().Decrypt(payload, iv, output); err != nil {
return errors.Wrapf(err, "error decrypting BLOB %v", blobID)
}

View File

@@ -1,4 +1,4 @@
package content_test
package content
import (
"strings"
@@ -8,13 +8,12 @@
"github.com/stretchr/testify/require"
"github.com/kopia/kopia/internal/gather"
"github.com/kopia/kopia/repo/content"
"github.com/kopia/kopia/repo/encryption"
"github.com/kopia/kopia/repo/hashing"
)
func TestBlobCrypto(t *testing.T) {
f := &content.FormattingOptions{
f := &FormattingOptions{
Hash: hashing.DefaultAlgorithm,
Encryption: encryption.DefaultAlgorithm,
}
@@ -23,41 +22,38 @@ func TestBlobCrypto(t *testing.T) {
enc, err := encryption.CreateEncryptor(f)
require.NoError(t, err)
cr := &content.Crypter{
HashFunction: hf,
Encryptor: enc,
}
cr := staticCrypter{hf, enc}
var tmp, tmp2, tmp3 gather.WriteBuffer
defer tmp.Close()
defer tmp2.Close()
defer tmp3.Close()
id, err := cr.EncryptBLOB(gather.FromSlice([]byte{1, 2, 3}), "n", "mysessionid", &tmp)
id, err := EncryptBLOB(cr, gather.FromSlice([]byte{1, 2, 3}), "n", "mysessionid", &tmp)
require.NoError(t, err)
id2, err := cr.EncryptBLOB(gather.FromSlice([]byte{1, 2, 4}), "n", "mysessionid", &tmp2)
id2, err := EncryptBLOB(cr, gather.FromSlice([]byte{1, 2, 4}), "n", "mysessionid", &tmp2)
require.NoError(t, err)
require.NotEqual(t, id, id2)
require.NoError(t, cr.DecryptBLOB(tmp.Bytes(), id, &tmp3))
require.NoError(t, DecryptBLOB(cr, tmp.Bytes(), id, &tmp3))
require.Equal(t, []byte{1, 2, 3}, tmp3.ToByteSlice())
require.NoError(t, cr.DecryptBLOB(tmp2.Bytes(), id2, &tmp3))
require.NoError(t, DecryptBLOB(cr, tmp2.Bytes(), id2, &tmp3))
require.Equal(t, []byte{1, 2, 4}, tmp3.ToByteSlice())
// decrypting using invalid ID fails
require.Error(t, cr.DecryptBLOB(tmp.Bytes(), id2, &tmp3))
require.Error(t, cr.DecryptBLOB(tmp2.Bytes(), id, &tmp3))
require.Error(t, DecryptBLOB(cr, tmp.Bytes(), id2, &tmp3))
require.Error(t, DecryptBLOB(cr, tmp2.Bytes(), id, &tmp3))
require.True(t, strings.HasPrefix(string(id), "n"))
require.True(t, strings.HasSuffix(string(id), "-mysessionid"), id)
// negative cases
require.Error(t, cr.DecryptBLOB(tmp.Bytes(), "invalid-blob-id", &tmp3))
require.Error(t, cr.DecryptBLOB(tmp.Bytes(), "zzz0123456789abcdef0123456789abcde-suffix", &tmp3))
require.Error(t, cr.DecryptBLOB(tmp.Bytes(), id2, &tmp3))
require.Error(t, cr.DecryptBLOB(gather.FromSlice([]byte{2, 3, 4}), id, &tmp2))
require.Error(t, DecryptBLOB(cr, tmp.Bytes(), "invalid-blob-id", &tmp3))
require.Error(t, DecryptBLOB(cr, tmp.Bytes(), "zzz0123456789abcdef0123456789abcde-suffix", &tmp3))
require.Error(t, DecryptBLOB(cr, tmp.Bytes(), id2, &tmp3))
require.Error(t, DecryptBLOB(cr, gather.FromSlice([]byte{2, 3, 4}), id, &tmp2))
}
type badEncryptor struct{}
@@ -73,12 +69,12 @@ func (badEncryptor) Decrypt(input gather.Bytes, contentID []byte, output *gather
func (badEncryptor) Overhead() int { return 0 }
func TestBlobCrypto_Invalid(t *testing.T) {
cr := &content.Crypter{
HashFunction: func(output []byte, data gather.Bytes) []byte {
cr := staticCrypter{
func(output []byte, data gather.Bytes) []byte {
// invalid hash
return append(output, 9, 9, 9, 9)
},
Encryptor: badEncryptor{},
badEncryptor{},
}
var tmp, tmp2, tmp3 gather.WriteBuffer
@@ -86,10 +82,10 @@ func TestBlobCrypto_Invalid(t *testing.T) {
defer tmp2.Close()
defer tmp3.Close()
_, err := cr.EncryptBLOB(gather.FromSlice([]byte{1, 2, 3}), "n", "mysessionid", &tmp)
_, err := EncryptBLOB(cr, gather.FromSlice([]byte{1, 2, 3}), "n", "mysessionid", &tmp)
require.Error(t, err)
f := &content.FormattingOptions{
f := &FormattingOptions{
Hash: hashing.DefaultAlgorithm,
Encryption: encryption.DefaultAlgorithm,
}
@@ -98,8 +94,8 @@ func TestBlobCrypto_Invalid(t *testing.T) {
hf, err := hashing.CreateHashFunc(f)
require.NoError(t, err)
cr.HashFunction = hf
cr.h = hf
_, err = cr.EncryptBLOB(gather.FromSlice([]byte{1, 2, 3}), "n", "mysessionid", &tmp)
_, err = EncryptBLOB(cr, gather.FromSlice([]byte{1, 2, 3}), "n", "mysessionid", &tmp)
require.Error(t, err)
}

View File

@@ -69,11 +69,6 @@ type indexBlobManager interface {
invalidate(ctx context.Context)
}
// CrypterProvider returns the crypter to use for encrypting contents and blobs.
type CrypterProvider interface {
Crypter() *Crypter
}
// SharedManager is responsible for read-only access to committed data.
type SharedManager struct {
// +checkatomic
@@ -119,11 +114,6 @@ type SharedManager struct {
internalLogger *zap.SugaredLogger // backing logger for 'sharedBaseLogger'
}
// Crypter returns the crypter.
func (sm *SharedManager) Crypter() *Crypter {
return sm.format.Crypter()
}
func (sm *SharedManager) readPackFileLocalIndex(ctx context.Context, packFile blob.ID, packFileLength int64, output *gather.WriteBuffer) error {
var err error
@@ -291,7 +281,7 @@ func (sm *SharedManager) decryptContentAndVerify(payload gather.Bytes, bi Info,
}
func (sm *SharedManager) decryptAndVerify(encrypted gather.Bytes, iv []byte, output *gather.WriteBuffer) error {
if err := sm.format.Crypter().Encryptor.Decrypt(encrypted, iv, output); err != nil {
if err := sm.format.Encryptor().Decrypt(encrypted, iv, output); err != nil {
sm.Stats.foundInvalidContent()
return errors.Wrap(err, "decrypt")
}
@@ -435,10 +425,10 @@ func (sm *SharedManager) setupReadManagerCaches(ctx context.Context, caching *Ca
}
sm.enc = &encryptedBlobMgr{
st: cachedSt,
crypterProvider: sm.format,
indexBlobCache: indexBlobCache,
log: sm.namedLogger("encrypted-blob-manager"),
st: cachedSt,
crypter: sm.format,
indexBlobCache: indexBlobCache,
log: sm.namedLogger("encrypted-blob-manager"),
}
// set up legacy index blob manager
@@ -466,7 +456,7 @@ func (sm *SharedManager) setupReadManagerCaches(ctx context.Context, caching *Ca
sm.metadataCache = metadataCache
sm.indexBlobCache = indexBlobCache
sm.committedContents = newCommittedContentIndex(caching,
uint32(sm.format.Crypter().Encryptor.Overhead()),
uint32(sm.format.Encryptor().Overhead()),
sm.format.WriteIndexVersion(),
sm.enc.getEncryptedBlob,
sm.namedLogger("committed-content-index"),

View File

@@ -5,7 +5,6 @@
"context"
cryptorand "crypto/rand"
"crypto/sha1"
"strings"
"testing"
"time"
@@ -19,18 +18,6 @@
"github.com/kopia/kopia/repo/hashing"
)
// combinations of hash and encryption that are not compatible.
var incompatibleAlgorithms = map[string]string{
"BLAKE2B-256-128/XSALSA20": "expected >=24 bytes, got 16",
"BLAKE2S-128/XSALSA20": "expected >=24 bytes, got 16",
"HMAC-RIPEMD-160/XSALSA20": "expected >=24 bytes, got 20",
"HMAC-SHA256-128/XSALSA20": "expected >=24 bytes, got 16",
"BLAKE2B-256-128/XSALSA20-HMAC": "expected >=24 bytes, got 16",
"BLAKE2S-128/XSALSA20-HMAC": "expected >=24 bytes, got 16",
"HMAC-RIPEMD-160/XSALSA20-HMAC": "expected >=24 bytes, got 20",
"HMAC-SHA256-128/XSALSA20-HMAC": "expected >=24 bytes, got 16",
}
func TestFormatters(t *testing.T) {
secret := []byte("secret")
@@ -46,40 +33,30 @@ func TestFormatters(t *testing.T) {
t.Run(encryptionAlgo, func(t *testing.T) {
ctx := testlogging.Context(t)
cr, err := CreateCrypter(&FormattingOptions{
fo := &FormattingOptions{
HMACSecret: secret,
MasterKey: make([]byte, 32),
Hash: hashAlgo,
Encryption: encryptionAlgo,
})
if err != nil {
key := hashAlgo + "/" + encryptionAlgo
errmsg := incompatibleAlgorithms[key]
if errmsg == "" {
t.Errorf("Algorithm %v not marked as incompatible and failed with %v", key, err)
return
}
if !strings.HasSuffix(err.Error(), errmsg) {
t.Errorf("unexpected error message %v, wanted %v", err.Error(), errmsg)
return
}
return
}
contentID := cr.HashFunction(nil, gather.FromSlice(data))
hf, err := hashing.CreateHashFunc(fo)
require.NoError(t, err)
enc, err := encryption.CreateEncryptor(fo)
require.NoError(t, err)
contentID := hf(nil, gather.FromSlice(data))
var cipherText gather.WriteBuffer
defer cipherText.Close()
require.NoError(t, cr.Encryptor.Encrypt(gather.FromSlice(data), contentID, &cipherText))
require.NoError(t, enc.Encrypt(gather.FromSlice(data), contentID, &cipherText))
var plainText gather.WriteBuffer
defer plainText.Close()
require.NoError(t, cr.Encryptor.Decrypt(cipherText.Bytes(), contentID, &plainText))
require.NoError(t, enc.Decrypt(cipherText.Bytes(), contentID, &plainText))
h1 := sha1.Sum(plainText.ToByteSlice())

View File

@@ -6,6 +6,7 @@
"github.com/pkg/errors"
"github.com/kopia/kopia/internal/epoch"
"github.com/kopia/kopia/internal/gather"
"github.com/kopia/kopia/internal/units"
"github.com/kopia/kopia/repo/blob"
"github.com/kopia/kopia/repo/content/index"
@@ -127,12 +128,17 @@ func (f *FormattingOptions) GetHmacSecret() []byte {
// should not be cached for more than a few seconds as they are subject to change.
type FormattingOptionsProvider interface {
epoch.ParametersProvider
IndexFormattingOptions
CrypterProvider
MaxIndexBlobSize() int64
WriteIndexVersion() int
IndexShardSize() int
encryption.Parameters
hashing.Parameters
HashFunc() hashing.HashFunc
Encryptor() encryption.Encryptor
GetMutableParameters() MutableParameters
GetMasterKey() []byte
SupportsPasswordChange() bool
@@ -145,7 +151,8 @@ type FormattingOptionsProvider interface {
type formattingOptionsProvider struct {
*FormattingOptions
crypter *Crypter
h hashing.HashFunc
e encryption.Encryptor
actualFormatVersion FormatVersion
actualIndexVersion int
formatBytes []byte
@@ -221,23 +228,43 @@ func NewFormattingOptionsProvider(f *FormattingOptions, formatBytes []byte) (For
return nil, errors.Errorf("index version %v is not supported", actualIndexVersion)
}
crypter, err := CreateCrypter(f)
h, err := hashing.CreateHashFunc(f)
if err != nil {
return nil, errors.Wrap(err, "unable to create crypter")
return nil, errors.Wrap(err, "unable to create hash")
}
e, err := encryption.CreateEncryptor(f)
if err != nil {
return nil, errors.Wrap(err, "unable to create encryptor")
}
contentID := h(nil, gather.FromSlice(nil))
var tmp gather.WriteBuffer
defer tmp.Close()
err = e.Encrypt(gather.FromSlice(nil), contentID, &tmp)
if err != nil {
return nil, errors.Wrap(err, "invalid encryptor")
}
return &formattingOptionsProvider{
FormattingOptions: f,
crypter: crypter,
h: h,
e: e,
actualIndexVersion: actualIndexVersion,
actualFormatVersion: f.Version,
formatBytes: formatBytes,
}, nil
}
func (f *formattingOptionsProvider) Crypter() *Crypter {
return f.crypter
func (f *formattingOptionsProvider) Encryptor() encryption.Encryptor {
return f.e
}
func (f *formattingOptionsProvider) HashFunc() hashing.HashFunc {
return f.h
}
func (f *formattingOptionsProvider) WriteIndexVersion() int {

View File

@@ -22,7 +22,7 @@ func (bm *WriteManager) RecoverIndexFromPackBlob(ctx context.Context, packFile b
return nil, err
}
ndx, err := index.Open(localIndexBytes.Bytes().ToByteSlice(), nil, uint32(bm.format.Crypter().Encryptor.Overhead()))
ndx, err := index.Open(localIndexBytes.Bytes().ToByteSlice(), nil, uint32(bm.format.Encryptor().Overhead()))
if err != nil {
return nil, errors.Errorf("unable to open index in file %v", packFile)
}
@@ -195,7 +195,7 @@ func (sm *SharedManager) appendPackFileIndexRecoveryData(pending index.Builder,
var encryptedLocalIndex gather.WriteBuffer
defer encryptedLocalIndex.Close()
if err := sm.format.Crypter().Encryptor.Encrypt(localIndex.Bytes(), localIndexIV, &encryptedLocalIndex); err != nil {
if err := sm.format.Encryptor().Encrypt(localIndex.Bytes(), localIndexIV, &encryptedLocalIndex); err != nil {
return errors.Wrap(err, "encryption error")
}

View File

@@ -70,15 +70,15 @@ func (sm *SharedManager) CompactIndexes(ctx context.Context, opt CompactOptions)
}
// ParseIndexBlob loads entries in a given index blob and returns them.
func ParseIndexBlob(ctx context.Context, blobID blob.ID, encrypted gather.Bytes, crypter *Crypter) ([]Info, error) {
func ParseIndexBlob(ctx context.Context, blobID blob.ID, encrypted gather.Bytes, crypter crypter) ([]Info, error) {
var data gather.WriteBuffer
defer data.Close()
if err := crypter.DecryptBLOB(encrypted, blobID, &data); err != nil {
if err := DecryptBLOB(crypter, encrypted, blobID, &data); err != nil {
return nil, errors.Wrap(err, "unable to decrypt index blob")
}
ndx, err := index.Open(data.Bytes().ToByteSlice(), nil, uint32(crypter.Encryptor.Overhead()))
ndx, err := index.Open(data.Bytes().ToByteSlice(), nil, uint32(crypter.Encryptor().Overhead()))
if err != nil {
return nil, errors.Wrapf(err, "unable to open index blob")
}

View File

@@ -16,7 +16,6 @@
"github.com/kopia/kopia/repo/blob"
"github.com/kopia/kopia/repo/compression"
"github.com/kopia/kopia/repo/content/index"
"github.com/kopia/kopia/repo/encryption"
"github.com/kopia/kopia/repo/hashing"
"github.com/kopia/kopia/repo/logging"
)
@@ -62,7 +61,7 @@ func (sm *SharedManager) maybeCompressAndEncryptDataForPacking(data gather.Bytes
}
}
if err := sm.Crypter().Encryptor.Encrypt(data, iv, output); err != nil {
if err := sm.format.Encryptor().Encrypt(data, iv, output); err != nil {
return NoCompression, errors.Wrap(err, "unable to encrypt")
}
@@ -181,33 +180,8 @@ func (sm *SharedManager) writePackFileNotLocked(ctx context.Context, packFile bl
func (sm *SharedManager) hashData(output []byte, data gather.Bytes) []byte {
// Hash the content and compute encryption key.
contentID := sm.format.Crypter().HashFunction(output, data)
contentID := sm.format.HashFunc()(output, data)
sm.Stats.hashedContent(data.Length())
return contentID
}
// CreateCrypter returns a Crypter based on the specified formatting options.
func CreateCrypter(f *FormattingOptions) (*Crypter, error) {
h, err := hashing.CreateHashFunc(f)
if err != nil {
return nil, errors.Wrap(err, "unable to create hash")
}
e, err := encryption.CreateEncryptor(f)
if err != nil {
return nil, errors.Wrap(err, "unable to create encryptor")
}
contentID := h(nil, gather.FromSlice(nil))
var tmp gather.WriteBuffer
defer tmp.Close()
err = e.Encrypt(gather.FromSlice(nil), contentID, &tmp)
if err != nil {
return nil, errors.Wrap(err, "invalid encryptor")
}
return &Crypter{h, e}, nil
}

View File

@@ -12,10 +12,10 @@
)
type encryptedBlobMgr struct {
st blob.Storage
crypterProvider CrypterProvider
indexBlobCache *cache.PersistentCache
log logging.Logger
st blob.Storage
crypter crypter
indexBlobCache *cache.PersistentCache
log logging.Logger
}
func (m *encryptedBlobMgr) getEncryptedBlob(ctx context.Context, blobID blob.ID, output *gather.WriteBuffer) error {
@@ -29,14 +29,14 @@ func (m *encryptedBlobMgr) getEncryptedBlob(ctx context.Context, blobID blob.ID,
return errors.Wrap(err, "getContent")
}
return m.crypterProvider.Crypter().DecryptBLOB(payload.Bytes(), blobID, output)
return DecryptBLOB(m.crypter, payload.Bytes(), blobID, output)
}
func (m *encryptedBlobMgr) encryptAndWriteBlob(ctx context.Context, data gather.Bytes, prefix blob.ID, sessionID SessionID) (blob.Metadata, error) {
var data2 gather.WriteBuffer
defer data2.Close()
blobID, err := m.crypterProvider.Crypter().EncryptBLOB(data, prefix, sessionID, &data2)
blobID, err := EncryptBLOB(m.crypter, data, prefix, sessionID, &data2)
if err != nil {
return blob.Metadata{}, errors.Wrap(err, "error encrypting")
}

View File

@@ -37,16 +37,11 @@ func TestEncryptedBlobManager(t *testing.T) {
enc, err := encryption.CreateEncryptor(f)
require.NoError(t, err)
cr := &Crypter{
HashFunction: hf,
Encryptor: enc,
}
ebm := encryptedBlobMgr{
st: fs,
crypterProvider: staticCrypterProvider{cr},
indexBlobCache: nil,
log: logging.NullLogger,
st: fs,
crypter: staticCrypter{hf, enc},
indexBlobCache: nil,
log: logging.NullLogger,
}
ctx := testlogging.Context(t)
@@ -80,16 +75,21 @@ func TestEncryptedBlobManager(t *testing.T) {
someError2 := errors.Errorf("some error 2")
cr.Encryptor = failingEncryptor{nil, someError2}
ebm.crypter = staticCrypter{hf, failingEncryptor{nil, someError2}}
_, err = ebm.encryptAndWriteBlob(ctx, gather.FromSlice([]byte{1, 2, 3, 4}), "x", "session1")
require.ErrorIs(t, err, someError2)
}
type staticCrypterProvider struct {
theCrypter *Crypter
type staticCrypter struct {
h hashing.HashFunc
e encryption.Encryptor
}
func (p staticCrypterProvider) Crypter() *Crypter {
return p.theCrypter
func (p staticCrypter) Encryptor() encryption.Encryptor {
return p.e
}
func (p staticCrypter) HashFunc() hashing.HashFunc {
return p.h
}

View File

@@ -543,7 +543,7 @@ func addIndexBlobsToBuilder(ctx context.Context, enc *encryptedBlobMgr, bld inde
return errors.Wrapf(err, "error getting index %q", indexBlobID)
}
ndx, err := index.Open(data.ToByteSlice(), nil, uint32(enc.crypterProvider.Crypter().Encryptor.Overhead()))
ndx, err := index.Open(data.ToByteSlice(), nil, uint32(enc.crypter.Encryptor().Overhead()))
if err != nil {
return errors.Wrapf(err, "unable to open index blob %q", indexBlobID)
}

View File

@@ -794,11 +794,8 @@ func newIndexBlobManagerForTesting(t *testing.T, st blob.Storage, localTimeNow f
enc: &encryptedBlobMgr{
st: st,
indexBlobCache: nil,
crypterProvider: staticCrypterProvider{&Crypter{
HashFunction: hf,
Encryptor: enc,
}},
log: log,
crypter: staticCrypter{hf, enc},
log: log,
},
timeNow: localTimeNow,
log: log,

View File

@@ -89,7 +89,7 @@ func (m *indexBlobManagerV1) compactEpoch(ctx context.Context, blobIDs []blob.ID
for _, data := range dataShards {
data2.Reset()
blobID, err := m.enc.crypterProvider.Crypter().EncryptBLOB(data, outputPrefix, SessionID(sessionID), &data2)
blobID, err := EncryptBLOB(m.enc.crypter, data, outputPrefix, SessionID(sessionID), &data2)
if err != nil {
return errors.Wrap(err, "error encrypting")
}
@@ -113,7 +113,7 @@ func (m *indexBlobManagerV1) writeIndexBlobs(ctx context.Context, dataShards []g
data2 := gather.NewWriteBuffer()
defer data2.Close() //nolint:gocritic
unprefixedBlobID, err := m.enc.crypterProvider.Crypter().EncryptBLOB(data, "", sessionID, data2)
unprefixedBlobID, err := EncryptBLOB(m.enc.crypter, data, "", sessionID, data2)
if err != nil {
return nil, errors.Wrap(err, "error encrypting")
}

View File

@@ -33,7 +33,7 @@ type internalLogManager struct {
ctx context.Context // nolint:containedctx
st blob.Storage
bc CrypterProvider
bc crypter
wg sync.WaitGroup
timeFunc func() time.Time
flushThreshold int
@@ -48,7 +48,7 @@ func (m *internalLogManager) encryptAndWriteLogBlob(prefix blob.ID, data gather.
encrypted := gather.NewWriteBuffer()
// Close happens in a goroutine
blobID, err := m.bc.Crypter().EncryptBLOB(data, prefix, "", encrypted)
blobID, err := EncryptBLOB(m.bc, data, prefix, "", encrypted)
if err != nil {
encrypted.Close()
@@ -208,7 +208,7 @@ func (l *internalLogger) Sync() error {
}
// newInternalLogManager creates a new blobLogManager that will emit logs as repository blobs with a given prefix.
func newInternalLogManager(ctx context.Context, st blob.Storage, bc CrypterProvider) *internalLogManager {
func newInternalLogManager(ctx context.Context, st blob.Storage, bc crypter) *internalLogManager {
return &internalLogManager{
ctx: ctx,
st: st,

View File

@@ -111,7 +111,7 @@ func (bm *WriteManager) writeSessionMarkerLocked(ctx context.Context) error {
var encrypted gather.WriteBuffer
defer encrypted.Close()
sessionBlobID, err := bm.format.Crypter().EncryptBLOB(gather.FromSlice(js), BlobIDPrefixSession, bm.currentSessionInfo.ID, &encrypted)
sessionBlobID, err := EncryptBLOB(bm.format, gather.FromSlice(js), BlobIDPrefixSession, bm.currentSessionInfo.ID, &encrypted)
if err != nil {
return errors.Wrap(err, "unable to encrypt session marker")
}
@@ -178,7 +178,7 @@ func (bm *WriteManager) ListActiveSessions(ctx context.Context) (map[SessionID]*
return nil, errors.Wrapf(err, "error loading session: %v", b.BlobID)
}
err = bm.format.Crypter().DecryptBLOB(payload.Bytes(), b.BlobID, &decrypted)
err = DecryptBLOB(bm.format, payload.Bytes(), b.BlobID, &decrypted)
if err != nil {
return nil, errors.Wrapf(err, "error decrypting session: %v", b.BlobID)
}

View File

@@ -58,7 +58,6 @@ type DirectRepository interface {
BlobVolume() blob.Volume
ContentReader() content.Reader
IndexBlobs(ctx context.Context, includeInactive bool) ([]content.IndexBlobInfo, error)
Crypter() *content.Crypter
NewDirectWriter(ctx context.Context, opt WriteSessionOptions) (context.Context, DirectRepositoryWriter, error)
AlsoLogToContentLog(ctx context.Context) context.Context
UniqueID() []byte
@@ -147,11 +146,6 @@ func (r *directRepository) ConfigFilename() string {
return r.configFile
}
// Crypter returns a Crypter object.
func (r *directRepository) Crypter() *content.Crypter {
return r.sm.Crypter()
}
// NewObjectWriter creates an object writer.
func (r *directRepository) NewObjectWriter(ctx context.Context, opt object.WriterOptions) object.Writer {
return r.omgr.NewWriter(ctx, opt)