From dacbde7d774716a095877f727c4fb050c4784171 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sun, 18 Feb 2018 10:57:05 +0100 Subject: [PATCH] Extend the security of snapshots (#367) * extend security * fix lint --- hassio/snapshots/snapshot.py | 8 +++++--- hassio/snapshots/utils.py | 11 +++++++++-- hassio/utils/tar.py | 18 ++++++++++++++---- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/hassio/snapshots/snapshot.py b/hassio/snapshots/snapshot.py index da3019553..0ee11a6f6 100644 --- a/hassio/snapshots/snapshot.py +++ b/hassio/snapshots/snapshot.py @@ -13,7 +13,8 @@ import voluptuous as vol from voluptuous.humanize import humanize_error from .validate import SCHEMA_SNAPSHOT, ALL_FOLDERS -from .utils import remove_folder, password_to_key, password_for_validating +from .utils import ( + remove_folder, password_to_key, password_for_validating, key_to_iv) from ..const import ( ATTR_SLUG, ATTR_NAME, ATTR_DATE, ATTR_ADDONS, ATTR_REPOSITORIES, ATTR_HOMEASSISTANT, ATTR_FOLDERS, ATTR_VERSION, ATTR_TYPE, ATTR_IMAGE, @@ -130,7 +131,8 @@ class Snapshot(CoreSysAttributes): # Set password if password: self._key = password_to_key(password) - self._aes = AES.new(self._key, AES.MODE_ECB) + self._aes = AES.new( + self._key, AES.MODE_CBC, iv=key_to_iv(self._key)) self._data[ATTR_PROTECTED] = password_for_validating(password) self._data[ATTR_CRYPTO] = CRYPTO_AES128 @@ -144,7 +146,7 @@ class Snapshot(CoreSysAttributes): return False self._key = password_to_key(password) - self._aes = AES.new(self._key, AES.MODE_ECB) + self._aes = AES.new(self._key, AES.MODE_CBC, iv=key_to_iv(self._key)) return True def _encrypt_data(self, data): diff --git a/hassio/snapshots/utils.py b/hassio/snapshots/utils.py index 64b334f57..64b15185d 100644 --- a/hassio/snapshots/utils.py +++ b/hassio/snapshots/utils.py @@ -4,7 +4,7 @@ import shutil def password_to_key(password): - """Generate a AES Key from password""" + """Generate a AES Key from password.""" password = password.encode() for _ in range(100): password = hashlib.sha256(password).digest() @@ -12,12 +12,19 @@ def password_to_key(password): def password_for_validating(password): - """Generate a SHA256 hash from password""" + """Generate a SHA256 hash from password.""" for _ in range(100): password = hashlib.sha256(password.encode()).hexdigest() return password +def key_to_iv(key): + """Generate a iv from Key.""" + for _ in range(100): + key = hashlib.sha256(key).digest() + return key[:16] + + def create_slug(name, date_str): """Generate a hash from repository.""" key = "{} - {}".format(date_str, name).lower().encode() diff --git a/hassio/utils/tar.py b/hassio/utils/tar.py index 60c139293..a1f23537c 100644 --- a/hassio/utils/tar.py +++ b/hassio/utils/tar.py @@ -1,5 +1,6 @@ """Tarfile fileobject handler for encrypted files.""" import tarfile +import hashlib from Crypto.Cipher import AES from Crypto.Random import get_random_bytes @@ -39,11 +40,12 @@ class SecureTarFile(object): # Extract IV for CBC if self._mode == MOD_READ: - cbc_iv = self._file.read(16) + cbc_rand = self._file.read(16) else: - cbc_iv = get_random_bytes(16) - self._file.write(cbc_iv) - self._aes = AES.new(self._key, AES.MODE_CBC, iv=cbc_iv) + cbc_rand = get_random_bytes(16) + self._file.write(cbc_rand) + self._aes = AES.new( + self._key, AES.MODE_CBC, iv=_generate_iv(self._key, cbc_rand)) self._tar = tarfile.open(fileobj=self, mode=self._tar_mode) return self._tar @@ -76,3 +78,11 @@ class SecureTarFile(object): if not self._name.is_file(): return 0 return round(self._name.stat().st_size / 1048576, 2) # calc mbyte + + +def _generate_iv(key, salt): + """Generate a iv from data.""" + temp_iv = key + salt + for _ in range(100): + temp_iv = hashlib.sha256(temp_iv).digest() + return temp_iv[:16]