1
0
mirror of https://github.com/gilbertchen/duplicacy synced 2025-12-15 07:43:21 +00:00

Implement RSA encryption

This is to support public key encryption in the backup operation.  You can use
the -key option to supply the public key to the backup command, and then the
same option to supply the private key when restoring a previous revision.

The storage must be encrypted for this to work.
This commit is contained in:
Gilbert Chen
2019-09-20 14:19:18 -04:00
parent 58387c0951
commit 90833f9d86
8 changed files with 248 additions and 28 deletions

View File

@@ -718,6 +718,10 @@ func backupRepository(context *cli.Context) {
backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile) backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile)
duplicacy.SavePassword(*preference, "password", password) duplicacy.SavePassword(*preference, "password", password)
if context.String("key") != "" {
backupManager.SetupRSAPublicKey(context.String("key"))
}
backupManager.SetupSnapshotCache(preference.Name) backupManager.SetupSnapshotCache(preference.Name)
backupManager.SetDryRun(dryRun) backupManager.SetDryRun(dryRun)
backupManager.Backup(repository, quickMode, threads, context.String("t"), showStatistics, enableVSS, vssTimeout, enumOnly) backupManager.Backup(repository, quickMode, threads, context.String("t"), showStatistics, enableVSS, vssTimeout, enumOnly)
@@ -783,10 +787,8 @@ func restoreRepository(context *cli.Context) {
} }
patterns = append(patterns, pattern) patterns = append(patterns, pattern)
} }
patterns = duplicacy.ProcessFilterLines(patterns, make([]string, 0)) patterns = duplicacy.ProcessFilterLines(patterns, make([]string, 0))
duplicacy.LOG_DEBUG("REGEX_DEBUG", "There are %d compiled regular expressions stored", len(duplicacy.RegexMap)) duplicacy.LOG_DEBUG("REGEX_DEBUG", "There are %d compiled regular expressions stored", len(duplicacy.RegexMap))
@@ -797,6 +799,13 @@ func restoreRepository(context *cli.Context) {
backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile) backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile)
duplicacy.SavePassword(*preference, "password", password) duplicacy.SavePassword(*preference, "password", password)
if context.String("key") != "" {
prompt := fmt.Sprintf("Enter the passphrase for %s:", context.String("key"))
passphrase := duplicacy.GetPassword(*preference, "rsa_passphrase", prompt, false, false)
backupManager.SetupRSAPrivateKey(context.String("key"), passphrase)
duplicacy.SavePassword(*preference, "rsa_passphrase", passphrase)
}
backupManager.SetupSnapshotCache(preference.Name) backupManager.SetupSnapshotCache(preference.Name)
backupManager.Restore(repository, revision, true, quickMode, threads, overwrite, deleteMode, setOwner, showStatistics, patterns) backupManager.Restore(repository, revision, true, quickMode, threads, overwrite, deleteMode, setOwner, showStatistics, patterns)
@@ -847,6 +856,14 @@ func listSnapshots(context *cli.Context) {
showFiles := context.Bool("files") showFiles := context.Bool("files")
showChunks := context.Bool("chunks") showChunks := context.Bool("chunks")
// list doesn't need to decrypt file chunks; but we need -key here so we can reset the passphrase for the private key
if context.String("key") != "" {
prompt := fmt.Sprintf("Enter the passphrase for %s:", context.String("key"))
passphrase := duplicacy.GetPassword(*preference, "rsa_passphrase", prompt, false, resetPassword)
backupManager.SetupRSAPrivateKey(context.String("key"), passphrase)
duplicacy.SavePassword(*preference, "rsa_passphrase", passphrase)
}
backupManager.SetupSnapshotCache(preference.Name) backupManager.SetupSnapshotCache(preference.Name)
backupManager.SnapshotManager.ListSnapshots(id, revisions, tag, showFiles, showChunks) backupManager.SnapshotManager.ListSnapshots(id, revisions, tag, showFiles, showChunks)
@@ -885,6 +902,13 @@ func checkSnapshots(context *cli.Context) {
backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile) backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile)
duplicacy.SavePassword(*preference, "password", password) duplicacy.SavePassword(*preference, "password", password)
if context.String("key") != "" {
prompt := fmt.Sprintf("Enter the passphrase for %s:", context.String("key"))
passphrase := duplicacy.GetPassword(*preference, "rsa_passphrase", prompt, false, false)
backupManager.SetupRSAPrivateKey(context.String("key"), passphrase)
duplicacy.SavePassword(*preference, "rsa_passphrase", passphrase)
}
id := preference.SnapshotID id := preference.SnapshotID
if context.Bool("all") { if context.Bool("all") {
id = "" id = ""
@@ -940,6 +964,13 @@ func printFile(context *cli.Context) {
backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile) backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile)
duplicacy.SavePassword(*preference, "password", password) duplicacy.SavePassword(*preference, "password", password)
if context.String("key") != "" {
prompt := fmt.Sprintf("Enter the passphrase for %s:", context.String("key"))
passphrase := duplicacy.GetPassword(*preference, "rsa_passphrase", prompt, false, false)
backupManager.SetupRSAPrivateKey(context.String("key"), passphrase)
duplicacy.SavePassword(*preference, "rsa_passphrase", passphrase)
}
backupManager.SetupSnapshotCache(preference.Name) backupManager.SetupSnapshotCache(preference.Name)
file := "" file := ""
@@ -996,6 +1027,13 @@ func diff(context *cli.Context) {
backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile) backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile)
duplicacy.SavePassword(*preference, "password", password) duplicacy.SavePassword(*preference, "password", password)
if context.String("key") != "" {
prompt := fmt.Sprintf("Enter the passphrase for %s:", context.String("key"))
passphrase := duplicacy.GetPassword(*preference, "rsa_passphrase", prompt, false, false)
backupManager.SetupRSAPrivateKey(context.String("key"), passphrase)
duplicacy.SavePassword(*preference, "rsa_passphrase", passphrase)
}
backupManager.SetupSnapshotCache(preference.Name) backupManager.SetupSnapshotCache(preference.Name)
backupManager.SnapshotManager.Diff(repository, snapshotID, revisions, path, compareByHash, preference.NobackupFile) backupManager.SnapshotManager.Diff(repository, snapshotID, revisions, path, compareByHash, preference.NobackupFile)
@@ -1406,6 +1444,11 @@ func main() {
Name: "enum-only", Name: "enum-only",
Usage: "enumerate the repository recursively and then exit", Usage: "enumerate the repository recursively and then exit",
}, },
cli.StringFlag{
Name: "key",
Usage: "the RSA public key to encrypt file chunks",
Argument: "<public key>",
},
}, },
Usage: "Save a snapshot of the repository to the storage", Usage: "Save a snapshot of the repository to the storage",
ArgsUsage: " ", ArgsUsage: " ",
@@ -1457,6 +1500,11 @@ func main() {
Usage: "restore from the specified storage instead of the default one", Usage: "restore from the specified storage instead of the default one",
Argument: "<storage name>", Argument: "<storage name>",
}, },
cli.StringFlag{
Name: "key",
Usage: "the RSA private key to decrypt file chunks",
Argument: "<private key>",
},
}, },
Usage: "Restore the repository to a previously saved snapshot", Usage: "Restore the repository to a previously saved snapshot",
ArgsUsage: "[--] [pattern] ...", ArgsUsage: "[--] [pattern] ...",
@@ -1502,6 +1550,11 @@ func main() {
Usage: "retrieve snapshots from the specified storage", Usage: "retrieve snapshots from the specified storage",
Argument: "<storage name>", Argument: "<storage name>",
}, },
cli.StringFlag{
Name: "key",
Usage: "the RSA private key to decrypt file chunks",
Argument: "<private key>",
},
}, },
Usage: "List snapshots", Usage: "List snapshots",
ArgsUsage: " ", ArgsUsage: " ",
@@ -1554,6 +1607,11 @@ func main() {
Usage: "retrieve snapshots from the specified storage", Usage: "retrieve snapshots from the specified storage",
Argument: "<storage name>", Argument: "<storage name>",
}, },
cli.StringFlag{
Name: "key",
Usage: "the RSA private key to decrypt file chunks",
Argument: "<private key>",
},
}, },
Usage: "Check the integrity of snapshots", Usage: "Check the integrity of snapshots",
ArgsUsage: " ", ArgsUsage: " ",
@@ -1577,6 +1635,11 @@ func main() {
Usage: "retrieve the file from the specified storage", Usage: "retrieve the file from the specified storage",
Argument: "<storage name>", Argument: "<storage name>",
}, },
cli.StringFlag{
Name: "key",
Usage: "the RSA private key to decrypt file chunks",
Argument: "<private key>",
},
}, },
Usage: "Print to stdout the specified file, or the snapshot content if no file is specified", Usage: "Print to stdout the specified file, or the snapshot content if no file is specified",
ArgsUsage: "[<file>]", ArgsUsage: "[<file>]",
@@ -1605,6 +1668,11 @@ func main() {
Usage: "retrieve files from the specified storage", Usage: "retrieve files from the specified storage",
Argument: "<storage name>", Argument: "<storage name>",
}, },
cli.StringFlag{
Name: "key",
Usage: "the RSA private key to decrypt file chunks",
Argument: "<private key>",
},
}, },
Usage: "Compare two snapshots or two revisions of a file", Usage: "Compare two snapshots or two revisions of a file",
ArgsUsage: "[<file>]", ArgsUsage: "[<file>]",

View File

@@ -20,6 +20,11 @@ import (
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"io/ioutil"
"reflect"
) )
// BackupManager performs the two major operations, backup and restore, and passes other operations, mostly related to // BackupManager performs the two major operations, backup and restore, and passes other operations, mostly related to
@@ -103,6 +108,81 @@ func (manager *BackupManager) SetupSnapshotCache(storageName string) bool {
return true return true
} }
// SetupRSAPublicKey loads the specifed public key file for encrypting file chunks
func (manager *BackupManager) SetupRSAPublicKey(keyFile string) {
encodedKey, err := ioutil.ReadFile(keyFile)
if err != nil {
LOG_ERROR("BACKUP_KEY", "Failed to read the public key file: %v", err)
return
}
decodedKey, _ := pem.Decode(encodedKey)
if decodedKey == nil {
LOG_ERROR("RESTORE_KEY", "unrecognized public key in %s", keyFile)
return
}
if decodedKey.Type != "PUBLIC KEY" {
LOG_ERROR("BACKUP_KEY", "Unsupported public key type %s in %s", decodedKey.Type, keyFile)
return
}
parsedKey, err := x509.ParsePKIXPublicKey(decodedKey.Bytes)
if err != nil {
LOG_ERROR("BACKUP_KEY", "Failed to parse the public key in %s: %v", keyFile, err)
return
}
key, ok := parsedKey.(*rsa.PublicKey)
if !ok {
LOG_ERROR("BACKUP_KEY", "Unsupported public key type %s in %s", reflect.TypeOf(parsedKey), keyFile)
return
}
manager.config.rsaPublicKey = key
}
// SetupRSAPrivateKey loads the specifed private key file for decrypting file chunks
func (manager *BackupManager) SetupRSAPrivateKey(keyFile string, passphrase string) {
encodedKey, err := ioutil.ReadFile(keyFile)
if err != nil {
LOG_ERROR("RESTORE_KEY", "Failed to read the private key file: %v", err)
}
decodedKey, _ := pem.Decode(encodedKey)
if decodedKey == nil {
LOG_ERROR("RESTORE_KEY", "unrecognized private key in %s", keyFile)
return
}
if decodedKey.Type != "RSA PRIVATE KEY" {
LOG_ERROR("RESTORE_KEY", "Unsupported private key type %s in %s", decodedKey.Type, keyFile)
return
}
var decodedKeyBytes []byte
if passphrase != "" {
decodedKeyBytes, err = x509.DecryptPEMBlock(decodedKey, []byte(passphrase))
} else {
decodedKeyBytes = decodedKey.Bytes
}
var parsedKey interface{}
if parsedKey, err = x509.ParsePKCS1PrivateKey(decodedKeyBytes); err != nil {
if parsedKey, err = x509.ParsePKCS8PrivateKey(decodedKeyBytes); err != nil {
LOG_ERROR("RESTORE_KEY", "Failed to parse the private key in %s: %v", keyFile, err)
return
}
}
key, ok := parsedKey.(*rsa.PrivateKey)
if !ok {
LOG_ERROR("RESTORE_KEY", "Unsupported private key type %s in %s", reflect.TypeOf(parsedKey), keyFile)
return
}
manager.config.rsaPrivateKey = key
}
// setEntryContent sets the 4 content pointers for each entry in 'entries'. 'offset' indicates the value // setEntryContent sets the 4 content pointers for each entry in 'entries'. 'offset' indicates the value
// to be added to the StartChunk and EndChunk points, used when intending to append 'entries' to the // to be added to the StartChunk and EndChunk points, used when intending to append 'entries' to the
// original unchanged entry list. // original unchanged entry list.

View File

@@ -41,7 +41,7 @@ func benchmarkSplit(reader *bytes.Reader, fileSize int64, chunkSize int, compres
if encryption { if encryption {
key = "0123456789abcdef0123456789abcdef" key = "0123456789abcdef0123456789abcdef"
} }
err := chunk.Encrypt([]byte(key), "") err := chunk.Encrypt([]byte(key), "", false)
if err != nil { if err != nil {
LOG_ERROR("BENCHMARK_ENCRYPT", "Failed to encrypt the chunk: %v", err) LOG_ERROR("BENCHMARK_ENCRYPT", "Failed to encrypt the chunk: %v", err)
} }

View File

@@ -8,11 +8,13 @@ import (
"bytes" "bytes"
"compress/zlib" "compress/zlib"
"crypto/aes" "crypto/aes"
"crypto/rsa"
"crypto/cipher" "crypto/cipher"
"crypto/hmac" "crypto/hmac"
"crypto/rand" "crypto/rand"
"crypto/sha256" "crypto/sha256"
"encoding/hex" "encoding/hex"
"encoding/binary"
"fmt" "fmt"
"hash" "hash"
"io" "io"
@@ -65,6 +67,8 @@ type Chunk struct {
// Magic word to identify a duplicacy format encrypted file, plus a version number. // Magic word to identify a duplicacy format encrypted file, plus a version number.
var ENCRYPTION_HEADER = "duplicacy\000" var ENCRYPTION_HEADER = "duplicacy\000"
var ENCRYPTION_VERSION_RSA byte = 2
// CreateChunk creates a new chunk. // CreateChunk creates a new chunk.
func CreateChunk(config *Config, bufferNeeded bool) *Chunk { func CreateChunk(config *Config, bufferNeeded bool) *Chunk {
@@ -170,7 +174,7 @@ func (chunk *Chunk) VerifyID() {
// Encrypt encrypts the plain data stored in the chunk buffer. If derivationKey is not nil, the actual // Encrypt encrypts the plain data stored in the chunk buffer. If derivationKey is not nil, the actual
// encryption key will be HMAC-SHA256(encryptionKey, derivationKey). // encryption key will be HMAC-SHA256(encryptionKey, derivationKey).
func (chunk *Chunk) Encrypt(encryptionKey []byte, derivationKey string) (err error) { func (chunk *Chunk) Encrypt(encryptionKey []byte, derivationKey string, isSnapshot bool) (err error) {
var aesBlock cipher.Block var aesBlock cipher.Block
var gcm cipher.AEAD var gcm cipher.AEAD
@@ -186,8 +190,17 @@ func (chunk *Chunk) Encrypt(encryptionKey []byte, derivationKey string) (err err
if len(encryptionKey) > 0 { if len(encryptionKey) > 0 {
key := encryptionKey key := encryptionKey
usingRSA := false
if len(derivationKey) > 0 { if !isSnapshot && chunk.config.rsaPublicKey != nil {
// If the chunk is not a snpashot chunk, we attempt to encrypt it with the RSA publick key if there is one
randomKey := make([]byte, 32)
_, err := rand.Read(randomKey)
if err != nil {
return err
}
key = randomKey
usingRSA = true
} else if len(derivationKey) > 0 {
hasher := chunk.config.NewKeyedHasher([]byte(derivationKey)) hasher := chunk.config.NewKeyedHasher([]byte(derivationKey))
hasher.Write(encryptionKey) hasher.Write(encryptionKey)
key = hasher.Sum(nil) key = hasher.Sum(nil)
@@ -204,7 +217,21 @@ func (chunk *Chunk) Encrypt(encryptionKey []byte, derivationKey string) (err err
} }
// Start with the magic number and the version number. // Start with the magic number and the version number.
if usingRSA {
// RSA encryption starts "duplicacy\002"
encryptedBuffer.Write([]byte(ENCRYPTION_HEADER)[:len(ENCRYPTION_HEADER) - 1])
encryptedBuffer.Write([]byte{ENCRYPTION_VERSION_RSA})
// Then the encrypted key
encryptedKey, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, chunk.config.rsaPublicKey, key, nil)
if err != nil {
return err
}
binary.Write(encryptedBuffer, binary.LittleEndian, uint16(len(encryptedKey)))
encryptedBuffer.Write(encryptedKey)
} else {
encryptedBuffer.Write([]byte(ENCRYPTION_HEADER)) encryptedBuffer.Write([]byte(ENCRYPTION_HEADER))
}
// Followed by the nonce // Followed by the nonce
nonce = make([]byte, gcm.NonceSize()) nonce = make([]byte, gcm.NonceSize())
@@ -214,7 +241,6 @@ func (chunk *Chunk) Encrypt(encryptionKey []byte, derivationKey string) (err err
} }
encryptedBuffer.Write(nonce) encryptedBuffer.Write(nonce)
offset = encryptedBuffer.Len() offset = encryptedBuffer.Len()
} }
// offset is either 0 or the length of header + nonce // offset is either 0 or the length of header + nonce
@@ -291,6 +317,7 @@ func (chunk *Chunk) Decrypt(encryptionKey []byte, derivationKey string) (err err
}() }()
chunk.buffer, encryptedBuffer = encryptedBuffer, chunk.buffer chunk.buffer, encryptedBuffer = encryptedBuffer, chunk.buffer
headerLength := len(ENCRYPTION_HEADER)
if len(encryptionKey) > 0 { if len(encryptionKey) > 0 {
@@ -308,6 +335,41 @@ func (chunk *Chunk) Decrypt(encryptionKey []byte, derivationKey string) (err err
key = hasher.Sum(nil) key = hasher.Sum(nil)
} }
if len(encryptedBuffer.Bytes()) < headerLength + 12 {
return fmt.Errorf("No enough encrypted data (%d bytes) provided", len(encryptedBuffer.Bytes()))
}
if string(encryptedBuffer.Bytes()[:headerLength-1]) != ENCRYPTION_HEADER[:headerLength-1] {
return fmt.Errorf("The storage doesn't seem to be encrypted")
}
version := encryptedBuffer.Bytes()[headerLength-1]
if version != 0 && version != ENCRYPTION_VERSION_RSA {
return fmt.Errorf("Unsupported encryption version %d", version)
}
if version == ENCRYPTION_VERSION_RSA {
if chunk.config.rsaPrivateKey == nil {
LOG_ERROR("CHUNK_DECRYPT", "An RSA private key is required to decrypt the chunk")
return fmt.Errorf("An RSA private key is required to decrypt the chunk")
}
encryptedKeyLength := binary.LittleEndian.Uint16(encryptedBuffer.Bytes()[headerLength:headerLength+2])
if len(encryptedBuffer.Bytes()) < headerLength + 14 + int(encryptedKeyLength) {
return fmt.Errorf("No enough encrypted data (%d bytes) provided", len(encryptedBuffer.Bytes()))
}
encryptedKey := encryptedBuffer.Bytes()[headerLength + 2:headerLength + 2 + int(encryptedKeyLength)]
headerLength += 2 + int(encryptedKeyLength)
decryptedKey, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, chunk.config.rsaPrivateKey, encryptedKey, nil)
if err != nil {
return err
}
key = decryptedKey
}
aesBlock, err := aes.NewCipher(key) aesBlock, err := aes.NewCipher(key)
if err != nil { if err != nil {
return err return err
@@ -318,21 +380,7 @@ func (chunk *Chunk) Decrypt(encryptionKey []byte, derivationKey string) (err err
return err return err
} }
headerLength := len(ENCRYPTION_HEADER)
offset = headerLength + gcm.NonceSize() offset = headerLength + gcm.NonceSize()
if len(encryptedBuffer.Bytes()) < offset {
return fmt.Errorf("No enough encrypted data (%d bytes) provided", len(encryptedBuffer.Bytes()))
}
if string(encryptedBuffer.Bytes()[:headerLength-1]) != ENCRYPTION_HEADER[:headerLength-1] {
return fmt.Errorf("The storage doesn't seem to be encrypted")
}
if encryptedBuffer.Bytes()[headerLength-1] != 0 {
return fmt.Errorf("Unsupported encryption version %d", encryptedBuffer.Bytes()[headerLength-1])
}
nonce := encryptedBuffer.Bytes()[headerLength:offset] nonce := encryptedBuffer.Bytes()[headerLength:offset]
decryptedBytes, err := gcm.Open(encryptedBuffer.Bytes()[:offset], nonce, decryptedBytes, err := gcm.Open(encryptedBuffer.Bytes()[:offset], nonce,

View File

@@ -5,12 +5,22 @@
package duplicacy package duplicacy
import ( import (
"flag"
"bytes" "bytes"
crypto_rand "crypto/rand" crypto_rand "crypto/rand"
"crypto/rsa"
"math/rand" "math/rand"
"testing" "testing"
) )
var testRSAEncryption bool
func init() {
flag.BoolVar(&testRSAEncryption, "rsa", false, "enable RSA encryption")
flag.Parse()
}
func TestChunk(t *testing.T) { func TestChunk(t *testing.T) {
key := []byte("duplicacydefault") key := []byte("duplicacydefault")
@@ -22,6 +32,15 @@ func TestChunk(t *testing.T) {
config.CompressionLevel = DEFAULT_COMPRESSION_LEVEL config.CompressionLevel = DEFAULT_COMPRESSION_LEVEL
maxSize := 1000000 maxSize := 1000000
if testRSAEncryption {
privateKey, err := rsa.GenerateKey(crypto_rand.Reader, 2048)
if err != nil {
t.Errorf("Failed to generate a random private key: %v", err)
}
config.rsaPrivateKey = privateKey
config.rsaPublicKey = privateKey.Public().(*rsa.PublicKey)
}
remainderLength := -1 remainderLength := -1
for i := 0; i < 500; i++ { for i := 0; i < 500; i++ {
@@ -37,7 +56,7 @@ func TestChunk(t *testing.T) {
hash := chunk.GetHash() hash := chunk.GetHash()
id := chunk.GetID() id := chunk.GetID()
err := chunk.Encrypt(key, "") err := chunk.Encrypt(key, "", false)
if err != nil { if err != nil {
t.Errorf("Failed to encrypt the data: %v", err) t.Errorf("Failed to encrypt the data: %v", err)
continue continue

View File

@@ -128,7 +128,7 @@ func (uploader *ChunkUploader) Upload(threadIndex int, task ChunkUploadTask) boo
} }
// Encrypt the chunk only after we know that it must be uploaded. // Encrypt the chunk only after we know that it must be uploaded.
err = chunk.Encrypt(uploader.config.ChunkKey, chunk.GetHash()) err = chunk.Encrypt(uploader.config.ChunkKey, chunk.GetHash(), uploader.snapshotCache != nil)
if err != nil { if err != nil {
LOG_ERROR("UPLOAD_CHUNK", "Failed to encrypt the chunk %s: %v", chunkID, err) LOG_ERROR("UPLOAD_CHUNK", "Failed to encrypt the chunk %s: %v", chunkID, err)
return false return false

View File

@@ -9,6 +9,7 @@ import (
"crypto/hmac" "crypto/hmac"
"crypto/rand" "crypto/rand"
"crypto/sha256" "crypto/sha256"
"crypto/rsa"
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
@@ -65,6 +66,10 @@ type Config struct {
// for encrypting a non-chunk file // for encrypting a non-chunk file
FileKey []byte `json:"-"` FileKey []byte `json:"-"`
// for RSA encryption
rsaPrivateKey *rsa.PrivateKey
rsaPublicKey *rsa.PublicKey
chunkPool chan *Chunk chunkPool chan *Chunk
numberOfChunks int32 numberOfChunks int32
dryRun bool dryRun bool
@@ -430,7 +435,7 @@ func UploadConfig(storage Storage, config *Config, password string, iterations i
if len(password) > 0 { if len(password) > 0 {
// Encrypt the config file with masterKey. If masterKey is nil then no encryption is performed. // Encrypt the config file with masterKey. If masterKey is nil then no encryption is performed.
err = chunk.Encrypt(masterKey, "") err = chunk.Encrypt(masterKey, "", true)
if err != nil { if err != nil {
LOG_ERROR("CONFIG_CREATE", "Failed to create the config file: %v", err) LOG_ERROR("CONFIG_CREATE", "Failed to create the config file: %v", err)
return false return false

View File

@@ -1858,7 +1858,7 @@ func (manager *SnapshotManager) PruneSnapshots(selfID string, snapshotID string,
if _, found := newChunks[chunk]; found { if _, found := newChunks[chunk]; found {
// The fossil is referenced so it can't be deleted. // The fossil is referenced so it can't be deleted.
if dryRun { if dryRun {
LOG_INFO("FOSSIL_RESURRECT", "Fossil %s would be resurrected: %v", chunk) LOG_INFO("FOSSIL_RESURRECT", "Fossil %s would be resurrected", chunk)
continue continue
} }
@@ -2466,7 +2466,7 @@ func (manager *SnapshotManager) UploadFile(path string, derivationKey string, co
derivationKey = derivationKey[len(derivationKey)-64:] derivationKey = derivationKey[len(derivationKey)-64:]
} }
err := manager.fileChunk.Encrypt(manager.config.FileKey, derivationKey) err := manager.fileChunk.Encrypt(manager.config.FileKey, derivationKey, true)
if err != nil { if err != nil {
LOG_ERROR("UPLOAD_File", "Failed to encrypt the file %s: %v", path, err) LOG_ERROR("UPLOAD_File", "Failed to encrypt the file %s: %v", path, err)
return false return false