summaryrefslogtreecommitdiffstats
path: root/src/lib/Bcfg2/Server/Encryption.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/Bcfg2/Server/Encryption.py')
-rwxr-xr-xsrc/lib/Bcfg2/Server/Encryption.py32
1 files changed, 25 insertions, 7 deletions
diff --git a/src/lib/Bcfg2/Server/Encryption.py b/src/lib/Bcfg2/Server/Encryption.py
index f8b602d90..b60302871 100755
--- a/src/lib/Bcfg2/Server/Encryption.py
+++ b/src/lib/Bcfg2/Server/Encryption.py
@@ -173,6 +173,17 @@ def ssl_encrypt(plaintext, passwd, algorithm=None, salt=None):
return b64encode("Salted__" + salt + crypted) + "\n"
+def is_encrypted(val):
+ """ Make a best guess if the value is encrypted or not. This just
+ checks to see if ``val`` is a base64-encoded string whose content
+ starts with "Salted__", so it may have (rare) false positives. It
+ will not have false negatives. """
+ try:
+ return b64decode(val).startswith("Salted__")
+ except: # pylint: disable=W0702
+ return False
+
+
def bruteforce_decrypt(crypted, passphrases=None, algorithm=None):
""" Convenience method to decrypt the given encrypted string by
trying the given passphrases or all passphrases sequentially until
@@ -233,6 +244,10 @@ class DecryptError(Exception):
""" Exception raised when decryption fails. """
+class EncryptError(Exception):
+ """ Exception raised when encryption fails. """
+
+
class CryptoTool(object):
""" Generic decryption/encryption interface base object """
@@ -319,6 +334,8 @@ class CfgEncryptor(Encryptor):
Bcfg2.Options.setup.config)
def encrypt(self):
+ if is_encrypted(self.data):
+ raise EncryptError("Data is alraedy encrypted")
return ssl_encrypt(self.data, self.passphrase)
def get_destination_filename(self, original_filename):
@@ -355,7 +372,7 @@ class CfgDecryptor(Decryptor):
class PropertiesCryptoMixin(object):
""" Mixin to provide some common methods for Properties crypto """
- default_xpath = '//*'
+ default_xpath = '//*[@encrypted]'
def _get_elements(self, xdata):
""" Get the list of elements to encrypt or decrypt """
@@ -425,11 +442,13 @@ class PropertiesEncryptor(Encryptor, PropertiesCryptoMixin):
def encrypt(self):
xdata = lxml.etree.XML(self.data, parser=XMLParser)
for elt in self._get_elements(xdata):
+ if is_encrypted(elt.text):
+ raise EncryptError("Element is already encrypted: %s" %
+ print_xml(elt))
try:
pname, passphrase = self._get_element_passphrase(elt)
except PassphraseError:
- self.logger.error(str(sys.exc_info()[1]))
- return False
+ raise EncryptError(str(sys.exc_info()[1]))
self.logger.debug("Encrypting %s" % print_xml(elt))
elt.text = ssl_encrypt(elt.text, passphrase).strip()
elt.set("encrypted", pname)
@@ -441,7 +460,6 @@ class PropertiesEncryptor(Encryptor, PropertiesCryptoMixin):
class PropertiesDecryptor(Decryptor, PropertiesCryptoMixin):
""" decryptor class for Properties files """
- default_xpath = '//*[@encrypted]'
def decrypt(self):
decrypted_any = False
@@ -640,9 +658,9 @@ class CLI(object):
if data is None:
try:
data = getattr(tool, mode)()
- except DecryptError:
- self.logger.error("Failed to %s %s, skipping" % (mode,
- fname))
+ except (EncryptError, DecryptError):
+ self.logger.error("Failed to %s %s, skipping: %s" %
+ (mode, fname, sys.exc_info()[1]))
continue
if Bcfg2.Options.setup.stdout:
if len(Bcfg2.Options.setup.files) > 1: