mirror of
https://github.com/gilbertchen/duplicacy
synced 2025-12-18 09:13:17 +00:00
Merge pull request #575 from gilbertchen/rsa_encryption
Implement RSA encryption
This commit is contained in:
@@ -208,6 +208,17 @@ func runScript(context *cli.Context, storageName string, phase string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadRSAPrivateKey(keyFile string, preference *duplicacy.Preference, backupManager *duplicacy.BackupManager, resetPasswords bool) {
|
||||||
|
if keyFile == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt := fmt.Sprintf("Enter the passphrase for %s:", keyFile)
|
||||||
|
passphrase := duplicacy.GetPassword(*preference, "rsa_passphrase", prompt, false, resetPasswords)
|
||||||
|
backupManager.LoadRSAPrivateKey(keyFile, passphrase)
|
||||||
|
duplicacy.SavePassword(*preference, "rsa_passphrase", passphrase)
|
||||||
|
}
|
||||||
|
|
||||||
func initRepository(context *cli.Context) {
|
func initRepository(context *cli.Context) {
|
||||||
configRepository(context, true)
|
configRepository(context, true)
|
||||||
}
|
}
|
||||||
@@ -319,6 +330,11 @@ func configRepository(context *cli.Context, init bool) {
|
|||||||
if preference.Encrypted {
|
if preference.Encrypted {
|
||||||
prompt := fmt.Sprintf("Enter storage password for %s:", preference.StorageURL)
|
prompt := fmt.Sprintf("Enter storage password for %s:", preference.StorageURL)
|
||||||
storagePassword = duplicacy.GetPassword(preference, "password", prompt, false, true)
|
storagePassword = duplicacy.GetPassword(preference, "password", prompt, false, true)
|
||||||
|
} else {
|
||||||
|
if context.String("key") != "" {
|
||||||
|
duplicacy.LOG_ERROR("STORAGE_CONFIG", "RSA encryption can't be enabled with an unencrypted storage")
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
existingConfig, _, err := duplicacy.DownloadConfig(storage, storagePassword)
|
existingConfig, _, err := duplicacy.DownloadConfig(storage, storagePassword)
|
||||||
@@ -434,7 +450,7 @@ func configRepository(context *cli.Context, init bool) {
|
|||||||
iterations = duplicacy.CONFIG_DEFAULT_ITERATIONS
|
iterations = duplicacy.CONFIG_DEFAULT_ITERATIONS
|
||||||
}
|
}
|
||||||
duplicacy.ConfigStorage(storage, iterations, compressionLevel, averageChunkSize, maximumChunkSize,
|
duplicacy.ConfigStorage(storage, iterations, compressionLevel, averageChunkSize, maximumChunkSize,
|
||||||
minimumChunkSize, storagePassword, otherConfig, bitCopy)
|
minimumChunkSize, storagePassword, otherConfig, bitCopy, context.String("key"))
|
||||||
}
|
}
|
||||||
|
|
||||||
duplicacy.Preferences = append(duplicacy.Preferences, preference)
|
duplicacy.Preferences = append(duplicacy.Preferences, preference)
|
||||||
@@ -783,10 +799,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 +811,8 @@ 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)
|
||||||
|
|
||||||
|
loadRSAPrivateKey(context.String("key"), preference, backupManager, false)
|
||||||
|
|
||||||
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 +863,9 @@ 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
|
||||||
|
loadRSAPrivateKey(context.String("key"), preference, backupManager, resetPassword)
|
||||||
|
|
||||||
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 +904,8 @@ 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)
|
||||||
|
|
||||||
|
loadRSAPrivateKey(context.String("key"), preference, backupManager, false)
|
||||||
|
|
||||||
id := preference.SnapshotID
|
id := preference.SnapshotID
|
||||||
if context.Bool("all") {
|
if context.Bool("all") {
|
||||||
id = ""
|
id = ""
|
||||||
@@ -940,6 +961,8 @@ 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)
|
||||||
|
|
||||||
|
loadRSAPrivateKey(context.String("key"), preference, backupManager, false)
|
||||||
|
|
||||||
backupManager.SetupSnapshotCache(preference.Name)
|
backupManager.SetupSnapshotCache(preference.Name)
|
||||||
|
|
||||||
file := ""
|
file := ""
|
||||||
@@ -996,6 +1019,8 @@ 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)
|
||||||
|
|
||||||
|
loadRSAPrivateKey(context.String("key"), preference, backupManager, false)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
@@ -1143,6 +1168,8 @@ func copySnapshots(context *cli.Context) {
|
|||||||
sourceManager.SetupSnapshotCache(source.Name)
|
sourceManager.SetupSnapshotCache(source.Name)
|
||||||
duplicacy.SavePassword(*source, "password", sourcePassword)
|
duplicacy.SavePassword(*source, "password", sourcePassword)
|
||||||
|
|
||||||
|
loadRSAPrivateKey(context.String("key"), source, sourceManager, false)
|
||||||
|
|
||||||
_, destination := getRepositoryPreference(context, context.String("to"))
|
_, destination := getRepositoryPreference(context, context.String("to"))
|
||||||
|
|
||||||
if destination.Name == source.Name {
|
if destination.Name == source.Name {
|
||||||
@@ -1350,6 +1377,11 @@ func main() {
|
|||||||
Usage: "initialize a new repository at the specified path rather than the current working directory",
|
Usage: "initialize a new repository at the specified path rather than the current working directory",
|
||||||
Argument: "<path>",
|
Argument: "<path>",
|
||||||
},
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "key",
|
||||||
|
Usage: "the RSA public key to encrypt file chunks",
|
||||||
|
Argument: "<public key>",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Usage: "Initialize the storage if necessary and the current directory as the repository",
|
Usage: "Initialize the storage if necessary and the current directory as the repository",
|
||||||
ArgsUsage: "<snapshot id> <storage url>",
|
ArgsUsage: "<snapshot id> <storage url>",
|
||||||
@@ -1457,6 +1489,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 +1539,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 +1596,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 +1624,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 +1657,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>]",
|
||||||
@@ -1769,6 +1826,11 @@ func main() {
|
|||||||
Usage: "specify the path of the repository (instead of the current working directory)",
|
Usage: "specify the path of the repository (instead of the current working directory)",
|
||||||
Argument: "<path>",
|
Argument: "<path>",
|
||||||
},
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "key",
|
||||||
|
Usage: "the RSA public key to encrypt file chunks",
|
||||||
|
Argument: "<public key>",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Usage: "Add an additional storage to be used for the existing repository",
|
Usage: "Add an additional storage to be used for the existing repository",
|
||||||
ArgsUsage: "<storage name> <snapshot id> <storage url>",
|
ArgsUsage: "<storage name> <snapshot id> <storage url>",
|
||||||
@@ -1867,6 +1929,11 @@ func main() {
|
|||||||
Usage: "number of uploading threads",
|
Usage: "number of uploading threads",
|
||||||
Argument: "<n>",
|
Argument: "<n>",
|
||||||
},
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "key",
|
||||||
|
Usage: "the RSA private key to decrypt file chunks from the source storage",
|
||||||
|
Argument: "<public key>",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Usage: "Copy snapshots between compatible storages",
|
Usage: "Copy snapshots between compatible storages",
|
||||||
ArgsUsage: " ",
|
ArgsUsage: " ",
|
||||||
|
|||||||
@@ -76,6 +76,11 @@ func CreateBackupManager(snapshotID string, storage Storage, top string, passwor
|
|||||||
return backupManager
|
return backupManager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// loadRSAPrivateKey loads the specifed private key file for decrypting file chunks
|
||||||
|
func (manager *BackupManager) LoadRSAPrivateKey(keyFile string, passphrase string) {
|
||||||
|
manager.config.loadRSAPrivateKey(keyFile, passphrase)
|
||||||
|
}
|
||||||
|
|
||||||
// SetupSnapshotCache creates the snapshot cache, which is merely a local storage under the default .duplicacy
|
// SetupSnapshotCache creates the snapshot cache, which is merely a local storage under the default .duplicacy
|
||||||
// directory
|
// directory
|
||||||
func (manager *BackupManager) SetupSnapshotCache(storageName string) bool {
|
func (manager *BackupManager) SetupSnapshotCache(storageName string) bool {
|
||||||
@@ -103,6 +108,7 @@ func (manager *BackupManager) SetupSnapshotCache(storageName string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 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.
|
||||||
@@ -176,6 +182,10 @@ func (manager *BackupManager) Backup(top string, quickMode bool, threads int, ta
|
|||||||
|
|
||||||
LOG_DEBUG("BACKUP_PARAMETERS", "top: %s, quick: %t, tag: %s", top, quickMode, tag)
|
LOG_DEBUG("BACKUP_PARAMETERS", "top: %s, quick: %t, tag: %s", top, quickMode, tag)
|
||||||
|
|
||||||
|
if manager.config.rsaPublicKey != nil && len(manager.config.FileKey) > 0 {
|
||||||
|
LOG_INFO("BACKUP_KEY", "RSA encryption is enabled" )
|
||||||
|
}
|
||||||
|
|
||||||
remoteSnapshot := manager.SnapshotManager.downloadLatestSnapshot(manager.snapshotID)
|
remoteSnapshot := manager.SnapshotManager.downloadLatestSnapshot(manager.snapshotID)
|
||||||
if remoteSnapshot == nil {
|
if remoteSnapshot == nil {
|
||||||
remoteSnapshot = CreateEmptySnapshot(manager.snapshotID)
|
remoteSnapshot = CreateEmptySnapshot(manager.snapshotID)
|
||||||
@@ -1716,6 +1726,7 @@ func (manager *BackupManager) CopySnapshots(otherManager *BackupManager, snapsho
|
|||||||
newChunk := otherManager.config.GetChunk()
|
newChunk := otherManager.config.GetChunk()
|
||||||
newChunk.Reset(true)
|
newChunk.Reset(true)
|
||||||
newChunk.Write(chunk.GetBytes())
|
newChunk.Write(chunk.GetBytes())
|
||||||
|
newChunk.encryptionVersion = chunk.encryptionVersion
|
||||||
chunkUploader.StartChunk(newChunk, chunkIndex)
|
chunkUploader.StartChunk(newChunk, chunkIndex)
|
||||||
totalCopied++
|
totalCopied++
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
@@ -60,11 +62,15 @@ type Chunk struct {
|
|||||||
|
|
||||||
config *Config // Every chunk is associated with a Config object. Which hashing algorithm to use is determined
|
config *Config // Every chunk is associated with a Config object. Which hashing algorithm to use is determined
|
||||||
// by the config
|
// by the config
|
||||||
|
|
||||||
|
encryptionVersion byte // The version type in the encrytion header
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 +176,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 +192,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 chunk.config.rsaPublicKey != nil && (!isSnapshot || chunk.encryptionVersion == ENCRYPTION_VERSION_RSA) {
|
||||||
|
// 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 +219,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.
|
||||||
encryptedBuffer.Write([]byte(ENCRYPTION_HEADER))
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
// Followed by the nonce
|
// Followed by the nonce
|
||||||
nonce = make([]byte, gcm.NonceSize())
|
nonce = make([]byte, gcm.NonceSize())
|
||||||
@@ -214,7 +243,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 +319,9 @@ 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)
|
||||||
|
|
||||||
|
chunk.encryptionVersion = 0
|
||||||
|
|
||||||
if len(encryptionKey) > 0 {
|
if len(encryptionKey) > 0 {
|
||||||
|
|
||||||
@@ -308,6 +339,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")
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk.encryptionVersion = encryptedBuffer.Bytes()[headerLength-1]
|
||||||
|
if chunk.encryptionVersion != 0 && chunk.encryptionVersion != ENCRYPTION_VERSION_RSA {
|
||||||
|
return fmt.Errorf("Unsupported encryption version %d", chunk.encryptionVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
if chunk.encryptionVersion == 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 +384,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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -9,15 +9,20 @@ import (
|
|||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash"
|
"hash"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
"io/ioutil"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
blake2 "github.com/minio/blake2b-simd"
|
blake2 "github.com/minio/blake2b-simd"
|
||||||
)
|
)
|
||||||
@@ -65,6 +70,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
|
||||||
@@ -80,10 +89,15 @@ type jsonableConfig struct {
|
|||||||
IDKey string `json:"id-key"`
|
IDKey string `json:"id-key"`
|
||||||
ChunkKey string `json:"chunk-key"`
|
ChunkKey string `json:"chunk-key"`
|
||||||
FileKey string `json:"file-key"`
|
FileKey string `json:"file-key"`
|
||||||
|
RSAPublicKey string `json:"rsa-public-key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (config *Config) MarshalJSON() ([]byte, error) {
|
func (config *Config) MarshalJSON() ([]byte, error) {
|
||||||
|
|
||||||
|
publicKey := []byte {}
|
||||||
|
if config.rsaPublicKey != nil {
|
||||||
|
publicKey, _ = x509.MarshalPKIXPublicKey(config.rsaPublicKey)
|
||||||
|
}
|
||||||
return json.Marshal(&jsonableConfig{
|
return json.Marshal(&jsonableConfig{
|
||||||
aliasedConfig: (*aliasedConfig)(config),
|
aliasedConfig: (*aliasedConfig)(config),
|
||||||
ChunkSeed: hex.EncodeToString(config.ChunkSeed),
|
ChunkSeed: hex.EncodeToString(config.ChunkSeed),
|
||||||
@@ -91,6 +105,7 @@ func (config *Config) MarshalJSON() ([]byte, error) {
|
|||||||
IDKey: hex.EncodeToString(config.IDKey),
|
IDKey: hex.EncodeToString(config.IDKey),
|
||||||
ChunkKey: hex.EncodeToString(config.ChunkKey),
|
ChunkKey: hex.EncodeToString(config.ChunkKey),
|
||||||
FileKey: hex.EncodeToString(config.FileKey),
|
FileKey: hex.EncodeToString(config.FileKey),
|
||||||
|
RSAPublicKey: hex.EncodeToString(publicKey),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,6 +135,19 @@ func (config *Config) UnmarshalJSON(description []byte) (err error) {
|
|||||||
return fmt.Errorf("Invalid representation of the file key in the config")
|
return fmt.Errorf("Invalid representation of the file key in the config")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if publicKey, err := hex.DecodeString(aliased.RSAPublicKey); err != nil {
|
||||||
|
return fmt.Errorf("Invalid hex encoding of the RSA public key in the config")
|
||||||
|
} else if len(publicKey) > 0 {
|
||||||
|
parsedKey, err := x509.ParsePKIXPublicKey(publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Invalid RSA public key in the config: %v", err)
|
||||||
|
}
|
||||||
|
config.rsaPublicKey = parsedKey.(*rsa.PublicKey)
|
||||||
|
if config.rsaPublicKey == nil {
|
||||||
|
return fmt.Errorf("Unsupported public key type %s in the config", reflect.TypeOf(parsedKey))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,6 +168,29 @@ func (config *Config) Print() {
|
|||||||
LOG_INFO("CONFIG_INFO", "Maximum chunk size: %d", config.MaximumChunkSize)
|
LOG_INFO("CONFIG_INFO", "Maximum chunk size: %d", config.MaximumChunkSize)
|
||||||
LOG_INFO("CONFIG_INFO", "Minimum chunk size: %d", config.MinimumChunkSize)
|
LOG_INFO("CONFIG_INFO", "Minimum chunk size: %d", config.MinimumChunkSize)
|
||||||
LOG_INFO("CONFIG_INFO", "Chunk seed: %x", config.ChunkSeed)
|
LOG_INFO("CONFIG_INFO", "Chunk seed: %x", config.ChunkSeed)
|
||||||
|
|
||||||
|
LOG_TRACE("CONFIG_INFO", "Hash key: %x", config.HashKey)
|
||||||
|
LOG_TRACE("CONFIG_INFO", "ID key: %x", config.IDKey)
|
||||||
|
|
||||||
|
if len(config.ChunkKey) >= 0 {
|
||||||
|
LOG_TRACE("CONFIG_INFO", "File chunks are encrypted")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(config.FileKey) >= 0 {
|
||||||
|
LOG_TRACE("CONFIG_INFO", "Metadata chunks are encrypted")
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.rsaPublicKey != nil {
|
||||||
|
pkisPublicKey, _ := x509.MarshalPKIXPublicKey(config.rsaPublicKey)
|
||||||
|
|
||||||
|
publicKey := pem.EncodeToMemory(&pem.Block{
|
||||||
|
Type: "PUBLIC KEY",
|
||||||
|
Bytes: pkisPublicKey,
|
||||||
|
})
|
||||||
|
|
||||||
|
LOG_TRACE("CONFIG_INFO", "RSA public key: %s", publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateConfigFromParameters(compressionLevel int, averageChunkSize int, maximumChunkSize int, mininumChunkSize int,
|
func CreateConfigFromParameters(compressionLevel int, averageChunkSize int, maximumChunkSize int, mininumChunkSize int,
|
||||||
@@ -430,7 +481,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
|
||||||
@@ -477,7 +528,7 @@ func UploadConfig(storage Storage, config *Config, password string, iterations i
|
|||||||
// it simply creates a file named 'config' that stores various parameters as well as a set of keys if encryption
|
// it simply creates a file named 'config' that stores various parameters as well as a set of keys if encryption
|
||||||
// is enabled.
|
// is enabled.
|
||||||
func ConfigStorage(storage Storage, iterations int, compressionLevel int, averageChunkSize int, maximumChunkSize int,
|
func ConfigStorage(storage Storage, iterations int, compressionLevel int, averageChunkSize int, maximumChunkSize int,
|
||||||
minimumChunkSize int, password string, copyFrom *Config, bitCopy bool) bool {
|
minimumChunkSize int, password string, copyFrom *Config, bitCopy bool, keyFile string) bool {
|
||||||
|
|
||||||
exist, _, _, err := storage.GetFileInfo(0, "config")
|
exist, _, _, err := storage.GetFileInfo(0, "config")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -496,5 +547,108 @@ func ConfigStorage(storage Storage, iterations int, compressionLevel int, averag
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if keyFile != "" {
|
||||||
|
config.loadRSAPublicKey(keyFile)
|
||||||
|
}
|
||||||
return UploadConfig(storage, config, password, iterations)
|
return UploadConfig(storage, config, password, iterations)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (config *Config) loadRSAPublicKey(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("RSA_PUBLIC", "unrecognized public key in %s", keyFile)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if decodedKey.Type != "PUBLIC KEY" {
|
||||||
|
LOG_ERROR("RSA_PUBLIC", "Unsupported public key type %s in %s", decodedKey.Type, keyFile)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedKey, err := x509.ParsePKIXPublicKey(decodedKey.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
LOG_ERROR("RSA_PUBLIC", "Failed to parse the public key in %s: %v", keyFile, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
key, ok := parsedKey.(*rsa.PublicKey)
|
||||||
|
if !ok {
|
||||||
|
LOG_ERROR("RSA_PUBLIC", "Unsupported public key type %s in %s", reflect.TypeOf(parsedKey), keyFile)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config.rsaPublicKey = key
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadRSAPrivateKey loads the specifed private key file for decrypting file chunks
|
||||||
|
func (config *Config) loadRSAPrivateKey(keyFile string, passphrase string) {
|
||||||
|
|
||||||
|
encodedKey, err := ioutil.ReadFile(keyFile)
|
||||||
|
if err != nil {
|
||||||
|
LOG_ERROR("RSA_PRIVATE", "Failed to read the private key file: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
decodedKey, _ := pem.Decode(encodedKey)
|
||||||
|
if decodedKey == nil {
|
||||||
|
LOG_ERROR("RSA_PRIVATE", "unrecognized private key in %s", keyFile)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if decodedKey.Type != "RSA PRIVATE KEY" {
|
||||||
|
LOG_ERROR("RSA_PRIVATE", "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("RSA_PRIVATE", "Failed to parse the private key in %s: %v", keyFile, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
key, ok := parsedKey.(*rsa.PrivateKey)
|
||||||
|
if !ok {
|
||||||
|
LOG_ERROR("RSA_PRIVATE", "Unsupported private key type %s in %s", reflect.TypeOf(parsedKey), keyFile)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data := make([]byte, 32)
|
||||||
|
_, err = rand.Read(data)
|
||||||
|
if err != nil {
|
||||||
|
LOG_ERROR("RSA_PRIVATE", "Failed to generate random data for testing the private key: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now test if the private key matches the public key
|
||||||
|
encryptedData, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, config.rsaPublicKey, data, nil)
|
||||||
|
if err != nil {
|
||||||
|
LOG_ERROR("RSA_PRIVATE", "Failed to encrypt random data with the public key: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
decryptedData, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, key, encryptedData, nil)
|
||||||
|
if err != nil {
|
||||||
|
LOG_ERROR("RSA_PRIVATE", "Incorrect private key: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(data, decryptedData) {
|
||||||
|
LOG_ERROR("RSA_PRIVATE", "Decrypted data do not match the original data")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config.rsaPrivateKey = key
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user