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)
Beispiel #3
0
    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)
Beispiel #4
0
    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)