Rename Key.passphrase_protected -> logically_encrypted & document

This commit is contained in:
Marian Beermann 2017-05-11 21:03:32 +02:00
parent cad49b844e
commit 848df38d08
3 changed files with 32 additions and 12 deletions

View file

@ -133,15 +133,18 @@ Version 1.1.0b6 (unreleased)
Compatibility notes:
- Repositories in a repokey mode (including "authenticated" mode) with a
blank passphrase are now treated as unencrypted repositories for security checks
- Repositories in the "repokey" and "repokey-blake2" modes with an empty passphrase
are now treated as unencrypted repositories for security checks
(e.g. BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK).
- Running "borg init" via a "borg serve --append-only" server will *not* create
an append-only repository anymore. Use "borg init --append-only" to initialize
an append-only repository.
Repositories in the "authenticated" mode are now treated as the unencrypted repositories
they are.
Previously there would be no prompts nor messages if an unknown repository
in one of these modes with a blank passphrase was encountered. This would
in one of these modes with an empty passphrase was encountered. This would
allow an attacker to swap a repository, if one assumed that the lack of
password prompts was due to a set BORG_PASSPHRASE.

View file

@ -130,7 +130,7 @@ class SecurityManager:
self.save(manifest, key, cache)
def assert_access_unknown(self, warn_if_unencrypted, key):
if warn_if_unencrypted and not key.passphrase_protected and not self.known():
if warn_if_unencrypted and not key.logically_encrypted and not self.known():
msg = ("Warning: Attempting to access a previously unknown unencrypted repository!\n" +
"Do you want to continue? [yN] ")
if not yes(msg, false_msg="Aborting.", invalid_msg="Invalid answer, aborting.",

View file

@ -129,15 +129,31 @@ def tam_required(repository):
class KeyBase:
# Numeric key type ID, must fit in one byte.
TYPE = None # override in subclasses
# Human-readable name
NAME = 'UNDEFINED'
# Name used in command line / API (e.g. borg init --encryption=...)
ARG_NAME = 'UNDEFINED'
# Storage type (no key blob storage / keyfile / repo)
STORAGE = KeyBlobStorage.NO_STORAGE
# Seed for the buzhash chunker (borg.algorithms.chunker.Chunker)
# type: int
chunk_seed = None
# Whether this *particular instance* is encrypted from a practical point of view,
# i.e. when it's using encryption with a empty passphrase, then
# that may be *technically* called encryption, but for all intents and purposes
# that's as good as not encrypting in the first place, and this member should be False.
#
# The empty passphrase is also special because Borg tries it first when no passphrase
# was supplied, and if an empty passphrase works, then Borg won't ask for one.
logically_encrypted = False
def __init__(self, repository):
self.TYPE_STR = bytes([self.TYPE])
self.repository = repository
@ -234,7 +250,7 @@ class PlaintextKey(KeyBase):
STORAGE = KeyBlobStorage.NO_STORAGE
chunk_seed = 0
passphrase_protected = False
logically_encrypted = False
def __init__(self, repository):
super().__init__(repository)
@ -314,7 +330,8 @@ class ID_HMAC_SHA_256:
class AESKeyBase(KeyBase):
"""Common base class shared by KeyfileKey and PassphraseKey
"""
Common base class shared by KeyfileKey and PassphraseKey
Chunks are encrypted using 256bit AES in Counter Mode (CTR)
@ -330,7 +347,7 @@ class AESKeyBase(KeyBase):
MAC = hmac_sha256
passphrase_protected = True
logically_encrypted = True
def encrypt(self, chunk):
data = self.compressor.compress(chunk)
@ -705,7 +722,7 @@ class RepoKey(ID_HMAC_SHA_256, KeyfileKeyBase):
def load(self, target, passphrase):
# While the repository is encrypted, we consider a repokey repository with a blank
# passphrase an unencrypted repository.
self.passphrase_protected = passphrase != ''
self.logically_encrypted = passphrase != ''
# what we get in target is just a repo location, but we already have the repo obj:
target = self.repository
@ -717,7 +734,7 @@ class RepoKey(ID_HMAC_SHA_256, KeyfileKeyBase):
return success
def save(self, target, passphrase):
self.passphrase_protected = passphrase != ''
self.logically_encrypted = passphrase != ''
key_data = self._save(passphrase)
key_data = key_data.encode('utf-8') # remote repo: msgpack issue #99, giving bytes
target.save_key(key_data)
@ -750,16 +767,16 @@ class AuthenticatedKey(ID_BLAKE2b_256, RepoKey):
STORAGE = KeyBlobStorage.REPO
# It's only authenticated, not encrypted.
passphrase_protected = False
logically_encrypted = False
def load(self, target, passphrase):
success = super().load(target, passphrase)
self.passphrase_protected = False
self.logically_encrypted = False
return success
def save(self, target, passphrase):
super().save(target, passphrase)
self.passphrase_protected = False
self.logically_encrypted = False
def encrypt(self, chunk):
data = self.compressor.compress(chunk)