Files
kopia/internal/cacheprot/storage_protection.go
Jarek Kowalski fe55dcb6a2 feat(repository): added hard size limit to the on-disk cache (#3238)
* test(providers): added capacity limits to blobtesting.mapStorage

* refactor(general): added mutex map which dynamically allocates and releases named mutexes

* refactor(repository): refactored cache cleanup and limit enforcement

* refactor(repository): plumb through cache size limits in the repository

* feat(cli): added CLI options to set cache size limits

* unified flag setting and field naming

* Update cli/command_cache_set.go

Co-authored-by: Shikhar Mall <mall.shikhar.in@gmail.com>

* pr feedback

---------

Co-authored-by: Shikhar Mall <mall.shikhar.in@gmail.com>
2023-08-24 09:38:56 -07:00

118 lines
3.4 KiB
Go

// Package cacheprot provides utilities for protection of cache entries.
package cacheprot
import (
"crypto/sha256"
"github.com/pkg/errors"
"github.com/kopia/kopia/internal/gather"
"github.com/kopia/kopia/internal/hmac"
"github.com/kopia/kopia/internal/impossible"
"github.com/kopia/kopia/repo/encryption"
)
// encryptionProtectionAlgorithm is the authenticated encryption algorithm used by authenticatedEncryptionProtection.
const encryptionProtectionAlgorithm = "AES256-GCM-HMAC-SHA256"
// StorageProtection encapsulates protection (HMAC and/or encryption) applied to local cache items.
type StorageProtection interface {
Protect(id string, input gather.Bytes, output *gather.WriteBuffer)
Verify(id string, input gather.Bytes, output *gather.WriteBuffer) error
OverheadBytes() int
}
type nullStorageProtection struct{}
func (nullStorageProtection) Protect(_ string, input gather.Bytes, output *gather.WriteBuffer) {
output.Reset()
input.WriteTo(output) //nolint:errcheck
}
func (nullStorageProtection) Verify(_ string, input gather.Bytes, output *gather.WriteBuffer) error {
output.Reset()
input.WriteTo(output) //nolint:errcheck
return nil
}
func (nullStorageProtection) OverheadBytes() int {
return 0
}
// NoProtection returns implementation of StorageProtection that offers no protection.
func NoProtection() StorageProtection {
return nullStorageProtection{}
}
type checksumProtection struct {
Secret []byte
}
func (p checksumProtection) Protect(_ string, input gather.Bytes, output *gather.WriteBuffer) {
output.Reset()
hmac.Append(input, p.Secret, output)
}
func (p checksumProtection) Verify(_ string, input gather.Bytes, output *gather.WriteBuffer) error {
output.Reset()
//nolint:wrapcheck
return hmac.VerifyAndStrip(input, p.Secret, output)
}
func (p checksumProtection) OverheadBytes() int {
return sha256.Size
}
// ChecksumProtection returns StorageProtection that protects cached data using HMAC checksums without encryption.
func ChecksumProtection(key []byte) StorageProtection {
return checksumProtection{key}
}
type authenticatedEncryptionProtection struct {
e encryption.Encryptor
}
func (p authenticatedEncryptionProtection) deriveIV(id string) []byte {
contentID := sha256.Sum256([]byte(id))
return contentID[:]
}
func (p authenticatedEncryptionProtection) Protect(id string, input gather.Bytes, output *gather.WriteBuffer) {
output.Reset()
impossible.PanicOnError(p.e.Encrypt(input, p.deriveIV(id), output))
}
func (p authenticatedEncryptionProtection) Verify(id string, input gather.Bytes, output *gather.WriteBuffer) error {
output.Reset()
if err := p.e.Decrypt(input, p.deriveIV(id), output); err != nil {
return errors.Wrap(err, "unable to decrypt cache content")
}
return nil
}
func (p authenticatedEncryptionProtection) OverheadBytes() int {
return p.e.Overhead()
}
type authenticatedEncryptionProtectionKey []byte
func (k authenticatedEncryptionProtectionKey) GetEncryptionAlgorithm() string {
return encryptionProtectionAlgorithm
}
func (k authenticatedEncryptionProtectionKey) GetMasterKey() []byte {
return k
}
// AuthenticatedEncryptionProtection returns StorageProtection that protects cached data using authenticated encryption.
func AuthenticatedEncryptionProtection(key []byte) (StorageProtection, error) {
e, err := encryption.CreateEncryptor(authenticatedEncryptionProtectionKey(key))
impossible.PanicOnError(err)
return authenticatedEncryptionProtection{e}, nil
}