1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 |
- // Package blobcrypto performs whole-blob crypto operations.
- package blobcrypto
- import (
- "crypto/aes"
- "encoding/hex"
- "strings"
- "github.com/pkg/errors"
- "github.com/kopia/kopia/internal/gather"
- "github.com/kopia/kopia/repo/blob"
- "github.com/kopia/kopia/repo/encryption"
- "github.com/kopia/kopia/repo/hashing"
- )
- // Crypter encapsulates 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 getIndexBlobIV(s blob.ID) ([]byte, error) {
- if p := strings.Index(string(s), "-"); p >= 0 { //nolint:gocritic
- s = s[0:p]
- }
- if len(s) < 2*aes.BlockSize {
- return nil, errors.Errorf("blob id too short: %v", s)
- }
- v, err := hex.DecodeString(string(s[len(s)-(aes.BlockSize*2):])) //nolint:mnd
- if err != nil {
- return nil, errors.Errorf("invalid blob ID: %v", s)
- }
- return v, nil
- }
- // Encrypt encrypts the given data using crypter-defined key and returns a name that should
- // be used to save the blob in the repository.
- func Encrypt(c Crypter, payload gather.Bytes, prefix, suffix blob.ID, output *gather.WriteBuffer) (blob.ID, error) {
- var hashOutput [hashing.MaxHashSize]byte
- hash := c.HashFunc()(hashOutput[:0], payload)
- blobID := prefix + blob.ID(hex.EncodeToString(hash))
- if suffix != "" {
- blobID += "-" + suffix
- }
- iv, err := getIndexBlobIV(blobID)
- if err != nil {
- return "", err
- }
- output.Reset()
- if err := c.Encryptor().Encrypt(payload, iv, output); err != nil {
- return "", errors.Wrapf(err, "error encrypting BLOB %v", blobID)
- }
- return blobID, nil
- }
- // Decrypt decrypts the provided data using provided blobID to derive initialization vector.
- func Decrypt(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")
- }
- output.Reset()
- // Decrypt will verify the payload.
- if err := c.Encryptor().Decrypt(payload, iv, output); err != nil {
- return errors.Wrapf(err, "error decrypting BLOB %v", blobID)
- }
- return nil
- }
|