def decrypt_file(self, path, password=None): try: with open(path, 'rb') as f: salt = f.read(self._salt_len) iv = f.read(self._iv_len) f.seek(file_size(path) - self._mac_len) mac = f.read(self._mac_len) aes_key, mac_key = self._keys(salt, password) self._verify_file(path, mac, mac_key) cipher = self._cipher(aes_key, iv) new_path = re_sub(r'\.'+settings.EXTENSION_AES_ENCRYPTION+'$', '', path) with open(new_path, 'wb') as f: chunks = self._file_chunks( path, self._salt_len + self._iv_len, self._mac_len ) for chunk, is_last in chunks: data = cipher.decrypt(chunk) if self._mode == 'CBC' and is_last: data = unpad(data, AES.block_size) f.write(data) return new_path except (TypeError, ValueError, IOError) as e: self._error_handler(e)
def _file_chunks(self, path, beg=0, end=0): size = 1024 end = file_size(path) - end with open(path, 'rb') as f: pos = (len(f.read(beg))) while pos < end: size = size if end - pos > size else end - pos data = f.read(size) pos += len(data) yield (data, pos == end)
def _file_chunks(self, path, beg=0, end=0): ''' A generator that reads a file and yields chunks of data. The chunk size should be a multiple of 16 in CBC mode. ''' size = 1024 end = file_size(path) - end with open(path, 'rb') as f: pos = (len(f.read(beg))) while pos < end: size = size if end - pos > size else end - pos data = f.read(size) pos += len(data) yield (data, pos == end)
def decrypt_file(self, path, password = None): ''' Decrypts files using the supplied password or a master key. The password is not required if a master key has been set - either with `random_key_gen` or with `set_master_key`. If a password is supplied, it will be used to create a key with PBKDF2. The original file is not modified; a new decrypted file is created. :param path: str The file path. :param password: str or bytes Optional, the password. :return: str The new file path. ''' try: with open(path, 'rb') as f: salt = f.read(self._salt_len) iv = f.read(self._iv_len) f.seek(file_size(path) - self._mac_len) mac = f.read(self._mac_len) aes_key, mac_key = self._keys(salt, password) self._verify_file(path, mac, mac_key) cipher = self._cipher(aes_key, iv) new_path = re_sub(r'\.enc$', '.dec', path) with open(new_path, 'wb') as f: chunks = self._file_chunks( path, self._salt_len + self._iv_len, self._mac_len ) for chunk, is_last in chunks: data = cipher.decrypt(chunk) if self._mode == 'CBC' and is_last: data = unpad(data, AES.block_size) f.write(data) return new_path except (TypeError, ValueError, IOError) as e: self._error_handler(e)