Ejemplo n.º 1
0
def unlock_manifest(
    manifest_filename: str,
    private_key_filename: str,
    load: Callable[[str, IOIter], IOIter],
    options: OptionsDict,
) -> Manifest:
    """ Load a manifest into local storage and unencrypt it

    :param manifest_filename: the name of the manifest to unlock
    :param private_key_filename: the private key file in PEM format used to encrypt the
        manifest's keypair
    :param load: the _load function from the backup store
    :param options: backup store options
    :returns: the requested Manifest
    """
    local_manifest_filename = path_join(get_scratch_dir(), manifest_filename)
    logger.debug(f'Unlocking manifest at {local_manifest_filename}')

    # First use the private key to read the AES key and nonce used to encrypt the manifest
    key_pair = b''
    if options['use_encryption']:
        key_pair = get_manifest_keypair(manifest_filename,
                                        private_key_filename, load)

    # Now use the key and nonce to decrypt the manifest
    with IOIter() as encrypted_local_manifest, \
            IOIter(local_manifest_filename, check_mtime=False) as local_manifest:
        load(manifest_filename, encrypted_local_manifest)
        decrypt_and_unpack(encrypted_local_manifest, local_manifest, key_pair,
                           options)

    return Manifest(local_manifest_filename)
Ejemplo n.º 2
0
def test_decrypt_and_unpack_no_compression_no_encryption(
        caplog, mock_open_streams):
    orig, new, _ = mock_open_streams
    decrypt_and_unpack(orig, new, b'',
                       dict(use_compression=False, use_encryption=False))
    assert new._fd.getvalue() == orig._fd.getvalue()
    assert count_matching_log_lines('read 2 bytes from /orig', caplog) == 4
    assert count_matching_log_lines('wrote 2 bytes to /new', caplog) == 4
Ejemplo n.º 3
0
 def load(
     self,
     src: str,
     dest: IOIter,
     key_pair: Optional[bytes],
 ) -> IOIter:
     """ Wrapper around the _load function that converts the SHA to a path """
     src = sha_to_path(src)
     with IOIter() as encrypted_load_file:
         self._load(src, encrypted_load_file)
         decrypt_and_unpack(encrypted_load_file, dest, key_pair,
                            self.options)
     dest.fd.seek(0)
     return dest
Ejemplo n.º 4
0
def test_decrypt_and_unpack_no_encryption(caplog, mock_open_streams):
    orig, new, _ = mock_open_streams
    orig_contents = orig._fd.getvalue()
    cobj = zlib.compressobj()
    orig._fd.write(cobj.compress(orig_contents[:4]))
    orig._fd.write(cobj.compress(orig_contents[4:]))
    orig._fd.write(cobj.flush())
    decrypt_and_unpack(orig, new, b'',
                       dict(use_compression=True, use_encryption=False))

    assert new._fd.getvalue() == orig_contents
    assert count_matching_log_lines('read 2 bytes from /orig', caplog) == 7
    assert count_matching_log_lines('wrote 1 bytes to /new', caplog) == 1
    assert count_matching_log_lines('wrote 2 bytes to /new', caplog) == 2
    assert count_matching_log_lines('wrote 4 bytes to /new', caplog) == 1
Ejemplo n.º 5
0
def test_decrypt_and_unpack_bad_signature(caplog, mock_open_streams):
    orig, new, _ = mock_open_streams
    orig_contents = orig._fd.getvalue()
    cipher = Cipher(AES(TMP_KEY), CTR(TMP_NONCE),
                    backend=default_backend()).encryptor()
    ct = cipher.update(zlib.compress(orig_contents))
    hmac = HMAC(TMP_KEY, SHA256(), default_backend())
    hmac.update(ct)
    signature = hmac.finalize()
    orig._fd.write(ct)
    with pytest.raises(BackupCorruptedError):
        decrypt_and_unpack(
            orig,
            new,
            TMP_KEYPAIR + signature[:-2] + b'f',
            dict(use_compression=True, use_encryption=True),
        )
Ejemplo n.º 6
0
def test_decrypt_and_unpack_no_compression(caplog, mock_open_streams):
    orig, new, _ = mock_open_streams
    orig_contents = orig._fd.getvalue()
    cipher = Cipher(AES(TMP_KEY), CTR(TMP_NONCE),
                    backend=default_backend()).encryptor()
    ct = cipher.update(orig_contents)
    hmac = HMAC(TMP_KEY, SHA256(), default_backend())
    hmac.update(ct)
    signature = hmac.finalize()
    orig._fd.write(ct)
    decrypt_and_unpack(
        orig,
        new,
        TMP_KEYPAIR + signature,
        dict(use_compression=False, use_encryption=True),
    )

    assert new._fd.getvalue() == orig_contents
    assert count_matching_log_lines('read 2 bytes from /orig', caplog) == 4
    assert count_matching_log_lines('wrote 2 bytes to /new', caplog) == 4