浏览代码

Rename Key.passphrase_protected -> logically_encrypted & document

Marian Beermann 8 年之前
父节点
当前提交
848df38d08
共有 3 个文件被更改,包括 32 次插入12 次删除
  1. 6 3
      docs/changes.rst
  2. 1 1
      src/borg/cache.py
  3. 25 8
      src/borg/crypto/key.py

+ 6 - 3
docs/changes.rst

@@ -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.
 

+ 1 - 1
src/borg/cache.py

@@ -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.",

+ 25 - 8
src/borg/crypto/key.py

@@ -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)