mirror of
https://github.com/jkl1337/duplicacy.git
synced 2026-01-02 03:34:39 -06:00
Fixed a bug that disabled RSA when copying from a non RSA-encrypted storage.
When copying to an RSA-encrypted storage, we relied on the RSA encryption version to determine if a chunk is a snapshot chunk or a file chunk. This is wrong when the source storage is not encrypted or not RSA-encrypted. There is a more reliable to determine if a chunk is a snapshot chunk or not.
This commit is contained in:
@@ -1626,6 +1626,9 @@ func (manager *BackupManager) CopySnapshots(otherManager *BackupManager, snapsho
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These two maps store hashes of chunks in the source and destination storages, respectively. Note that
|
||||||
|
// the value of 'chunks' is used to indicated if the chunk is a snapshot chunk, while the value of 'otherChunks'
|
||||||
|
// is not used.
|
||||||
chunks := make(map[string]bool)
|
chunks := make(map[string]bool)
|
||||||
otherChunks := make(map[string]bool)
|
otherChunks := make(map[string]bool)
|
||||||
|
|
||||||
@@ -1638,21 +1641,15 @@ func (manager *BackupManager) CopySnapshots(otherManager *BackupManager, snapsho
|
|||||||
LOG_TRACE("SNAPSHOT_COPY", "Copying snapshot %s at revision %d", snapshot.ID, snapshot.Revision)
|
LOG_TRACE("SNAPSHOT_COPY", "Copying snapshot %s at revision %d", snapshot.ID, snapshot.Revision)
|
||||||
|
|
||||||
for _, chunkHash := range snapshot.FileSequence {
|
for _, chunkHash := range snapshot.FileSequence {
|
||||||
if _, found := chunks[chunkHash]; !found {
|
chunks[chunkHash] = true // The chunk is a snapshot chunk
|
||||||
chunks[chunkHash] = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, chunkHash := range snapshot.ChunkSequence {
|
for _, chunkHash := range snapshot.ChunkSequence {
|
||||||
if _, found := chunks[chunkHash]; !found {
|
chunks[chunkHash] = true // The chunk is a snapshot chunk
|
||||||
chunks[chunkHash] = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, chunkHash := range snapshot.LengthSequence {
|
for _, chunkHash := range snapshot.LengthSequence {
|
||||||
if _, found := chunks[chunkHash]; !found {
|
chunks[chunkHash] = true // The chunk is a snapshot chunk
|
||||||
chunks[chunkHash] = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
description := manager.SnapshotManager.DownloadSequence(snapshot.ChunkSequence)
|
description := manager.SnapshotManager.DownloadSequence(snapshot.ChunkSequence)
|
||||||
@@ -1665,7 +1662,7 @@ func (manager *BackupManager) CopySnapshots(otherManager *BackupManager, snapsho
|
|||||||
|
|
||||||
for _, chunkHash := range snapshot.ChunkHashes {
|
for _, chunkHash := range snapshot.ChunkHashes {
|
||||||
if _, found := chunks[chunkHash]; !found {
|
if _, found := chunks[chunkHash]; !found {
|
||||||
chunks[chunkHash] = true
|
chunks[chunkHash] = false // The chunk is a file chunk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1721,7 +1718,7 @@ func (manager *BackupManager) CopySnapshots(otherManager *BackupManager, snapsho
|
|||||||
totalSkipped := 0
|
totalSkipped := 0
|
||||||
chunkIndex := 0
|
chunkIndex := 0
|
||||||
|
|
||||||
for chunkHash := range chunks {
|
for chunkHash, isSnapshot := range chunks {
|
||||||
chunkIndex++
|
chunkIndex++
|
||||||
chunkID := manager.config.GetChunkIDFromHash(chunkHash)
|
chunkID := manager.config.GetChunkIDFromHash(chunkHash)
|
||||||
newChunkID := otherManager.config.GetChunkIDFromHash(chunkHash)
|
newChunkID := otherManager.config.GetChunkIDFromHash(chunkHash)
|
||||||
@@ -1732,11 +1729,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())
|
||||||
if chunk.encryptionVersion == ENCRYPTION_VERSION_RSA {
|
newChunk.isSnapshot = isSnapshot
|
||||||
newChunk.encryptionVersion = CHUNK_RSA_ENCRYPTION_ENABLED
|
|
||||||
} else {
|
|
||||||
newChunk.encryptionVersion = CHUNK_RSA_ENCRYPTION_DISABLED
|
|
||||||
}
|
|
||||||
chunkUploader.StartChunk(newChunk, chunkIndex)
|
chunkUploader.StartChunk(newChunk, chunkIndex)
|
||||||
totalCopied++
|
totalCopied++
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -63,8 +63,8 @@ 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; for a chunk to be copied, this field contains
|
isSnapshot bool // Indicates if the chunk is a snapshot chunk (instead of a file chunk). This is only used by RSA
|
||||||
// one of the CHUNK_RSA_ENCRYPTION_* constants to indicate how the new chunk should be encrypted
|
// encryption, where a snapshot chunk is not encrypted by RSA
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
@@ -73,11 +73,6 @@ var ENCRYPTION_HEADER = "duplicacy\000"
|
|||||||
// RSA encrypted chunks start with "duplicacy\002"
|
// RSA encrypted chunks start with "duplicacy\002"
|
||||||
var ENCRYPTION_VERSION_RSA byte = 2
|
var ENCRYPTION_VERSION_RSA byte = 2
|
||||||
|
|
||||||
// These constants are used to control how a new chunk should be encrypted by the copy command
|
|
||||||
var CHUNK_RSA_ENCRYPTION_DEFAULT byte = 0 // No RSA encryption explicitly requested
|
|
||||||
var CHUNK_RSA_ENCRYPTION_DISABLED byte = 1 // The RSA encryption should be turned off
|
|
||||||
var CHUNK_RSA_ENCRYPTION_ENABLED byte = 2 // The RSA encryption should be forced on
|
|
||||||
|
|
||||||
// CreateChunk creates a new chunk.
|
// CreateChunk creates a new chunk.
|
||||||
func CreateChunk(config *Config, bufferNeeded bool) *Chunk {
|
func CreateChunk(config *Config, bufferNeeded bool) *Chunk {
|
||||||
|
|
||||||
@@ -126,6 +121,7 @@ func (chunk *Chunk) Reset(hashNeeded bool) {
|
|||||||
chunk.hash = nil
|
chunk.hash = nil
|
||||||
chunk.id = ""
|
chunk.id = ""
|
||||||
chunk.size = 0
|
chunk.size = 0
|
||||||
|
chunk.isSnapshot = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write implements the Writer interface.
|
// Write implements the Writer interface.
|
||||||
@@ -200,11 +196,8 @@ func (chunk *Chunk) Encrypt(encryptionKey []byte, derivationKey string, isSnapsh
|
|||||||
|
|
||||||
key := encryptionKey
|
key := encryptionKey
|
||||||
usingRSA := false
|
usingRSA := false
|
||||||
// If encryptionVersion is not set, use the default setting (RSA for file chunks only);
|
// Enable RSA encryption only when the chunk is not a snapshot chunk
|
||||||
// otherwise, enable RSA encryption only when explicitly requested
|
if chunk.config.rsaPublicKey != nil && !isSnapshot && !chunk.isSnapshot {
|
||||||
if chunk.config.rsaPublicKey != nil &&
|
|
||||||
((!isSnapshot && chunk.encryptionVersion == CHUNK_RSA_ENCRYPTION_DEFAULT) || chunk.encryptionVersion == CHUNK_RSA_ENCRYPTION_ENABLED) {
|
|
||||||
// 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)
|
randomKey := make([]byte, 32)
|
||||||
_, err := rand.Read(randomKey)
|
_, err := rand.Read(randomKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -331,8 +324,6 @@ 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)
|
headerLength := len(ENCRYPTION_HEADER)
|
||||||
|
|
||||||
chunk.encryptionVersion = 0
|
|
||||||
|
|
||||||
if len(encryptionKey) > 0 {
|
if len(encryptionKey) > 0 {
|
||||||
|
|
||||||
key := encryptionKey
|
key := encryptionKey
|
||||||
@@ -357,12 +348,12 @@ func (chunk *Chunk) Decrypt(encryptionKey []byte, derivationKey string) (err err
|
|||||||
return fmt.Errorf("The storage doesn't seem to be encrypted")
|
return fmt.Errorf("The storage doesn't seem to be encrypted")
|
||||||
}
|
}
|
||||||
|
|
||||||
chunk.encryptionVersion = encryptedBuffer.Bytes()[headerLength-1]
|
encryptionVersion := encryptedBuffer.Bytes()[headerLength-1]
|
||||||
if chunk.encryptionVersion != 0 && chunk.encryptionVersion != ENCRYPTION_VERSION_RSA {
|
if encryptionVersion != 0 && encryptionVersion != ENCRYPTION_VERSION_RSA {
|
||||||
return fmt.Errorf("Unsupported encryption version %d", chunk.encryptionVersion)
|
return fmt.Errorf("Unsupported encryption version %d", encryptionVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
if chunk.encryptionVersion == ENCRYPTION_VERSION_RSA {
|
if encryptionVersion == ENCRYPTION_VERSION_RSA {
|
||||||
if chunk.config.rsaPrivateKey == nil {
|
if chunk.config.rsaPrivateKey == nil {
|
||||||
LOG_ERROR("CHUNK_DECRYPT", "An RSA private key is required to decrypt the chunk")
|
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")
|
return fmt.Errorf("An RSA private key is required to decrypt the chunk")
|
||||||
|
|||||||
Reference in New Issue
Block a user