def generate_key_file(filename, size=DEFAULT_KEY_SIZE, context=None): """ Generate a file with random contents that can be used as a key file. :param filename: The pathname of the key file (a string). :param size: How large the key file should be (see :func:`.coerce_size()`, defaults to :data:`DEFAULT_KEY_SIZE`). :param context: An execution context created by :mod:`executor.contexts` (coerced using :func:`.coerce_context()`). :raises: :exc:`~executor.ExternalCommandFailed` when the command fails. """ context = coerce_context(context) size = coerce_size(size) logger.debug("Creating key file of %i bytes: %s", size, filename) context.execute( 'dd', 'if=/dev/urandom', 'of=%s' % filename, 'bs=%i' % size, 'count=1', # I'd rather use `status=none' then silent=True, however the # `status=none' flag isn't supported on Ubuntu 12.04 which # currently runs on Travis CI, so there you go :-p. silent=True, sudo=True, ) context.execute('chown', 'root:root', filename, sudo=True) context.execute('chmod', '400', filename, sudo=True)
def cryptdisks_start_helper(self, emulated): """ Test cryptdisks_start integration and emulation. This test requires the following line to be present in ``/etc/crypttab``:: linux-utils /tmp/linux-utils.img /tmp/linux-utils.key discard,luks,noauto,readonly,tries=1 """ if not any(entry.target == TEST_TARGET_NAME and entry.source == TEST_IMAGE_FILE and entry.key_file == TEST_KEY_FILE and 'luks' in entry.options for entry in parse_crypttab()): return self.skipTest( "/etc/crypttab isn't set up to test cryptdisks_start!") context = LocalContext() if emulated: # Disable the use of the `cryptdisks_start' program. context.find_program = MagicMock(return_value=[]) # Generate the key file. with TemporaryKeyFile(filename=TEST_KEY_FILE): # Create the image file and the encrypted filesystem. create_image_file(filename=TEST_IMAGE_FILE, size=coerce_size('10 MiB')) create_encrypted_filesystem(device_file=TEST_IMAGE_FILE, key_file=TEST_KEY_FILE) # Make sure the mapped device file doesn't exist yet. assert not os.path.exists(TEST_TARGET_DEVICE) # Unlock the encrypted filesystem using `cryptdisks_start'. if emulated: cryptdisks_start(context=context, target=TEST_TARGET_NAME) else: returncode, output = run_cli(cryptdisks_start_cli, TEST_TARGET_NAME) assert returncode == 0 # Make sure the mapped device file has appeared. assert os.path.exists(TEST_TARGET_DEVICE) # Unlock the encrypted filesystem again (this should be a no-op). cryptdisks_start(context=context, target=TEST_TARGET_NAME) # Make sure the mapped device file still exists. assert os.path.exists(TEST_TARGET_DEVICE) # Lock the filesystem before we finish. if emulated: cryptdisks_stop(context=context, target=TEST_TARGET_NAME) else: returncode, output = run_cli(cryptdisks_stop_cli, TEST_TARGET_NAME) assert returncode == 0 # Make sure the mapped device file has disappeared. assert not os.path.exists(TEST_TARGET_DEVICE) # Lock the filesystem again (this should be a no-op). cryptdisks_stop(context=context, target=TEST_TARGET_NAME) # Make sure the mapped device file is still gone. assert not os.path.exists(TEST_TARGET_DEVICE) # Test the error handling. for function in cryptdisks_start, cryptdisks_stop: self.assertRaises( ValueError if emulated else ExternalCommandFailed, function, context=context, target=TEST_UNKNOWN_TARGET, )
def test_create_encrypted_filesystem(self): """Test creation of encrypted filesystems.""" with TemporaryKeyFile(filename=TEST_KEY_FILE): create_image_file(filename=TEST_IMAGE_FILE, size=coerce_size('10 MiB')) create_encrypted_filesystem(device_file=TEST_IMAGE_FILE, key_file=TEST_KEY_FILE) assert 'LUKS' in execute('file', TEST_IMAGE_FILE, capture=True)
def test_create_image_file(self): """Test image file creation.""" size = coerce_size('1 MiB') create_image_file(TEST_IMAGE_FILE, size) # Make sure the image file was created with the correct size. assert os.path.getsize(TEST_IMAGE_FILE) == size # Make sure the contents of the image file are zero bytes. with open(TEST_IMAGE_FILE, 'rb') as handle: for byte in iter(functools.partial(handle.read, 1), b''): assert byte == b'\x00'
def test_unlock_encrypted_filesystem(self): """Test unlocking of encrypted filesystems.""" with TemporaryKeyFile(filename=TEST_KEY_FILE): create_image_file(filename=TEST_IMAGE_FILE, size=coerce_size('10 MiB')) create_encrypted_filesystem(device_file=TEST_IMAGE_FILE, key_file=TEST_KEY_FILE) unlock_filesystem(device_file=TEST_IMAGE_FILE, target=TEST_TARGET_NAME, key_file=TEST_KEY_FILE) assert os.path.exists(os.path.join('/dev/mapper', TEST_TARGET_NAME)) lock_filesystem(target=TEST_TARGET_NAME) assert not os.path.exists( os.path.join('/dev/mapper', TEST_TARGET_NAME))
def test_generate_key_file(self): """Test key file generation.""" context = LocalContext(sudo=True) size = coerce_size('4 KiB') with TemporaryKeyFile(context=context, filename=TEST_KEY_FILE, size=size): # Make sure the key file was created with the correct size. assert os.path.getsize(TEST_KEY_FILE) == size # Ensure that the key file contains some randomness. cat = context.execute('cat', TEST_KEY_FILE, capture=True) random_bytes = set(cat.stdout) # Although I know that (by definition of randomness) the following # assertion can fail I nevertheless feel that it adds value :-p. assert len(random_bytes) > 10
def create_image_file(filename, size, context=None): r""" Create an image file filled with bytes containing zero (``\0``). :param filename: The pathname of the image file (a string). :param size: How large the image file should be (see :func:`.coerce_size()`). :param context: See :func:`.coerce_context()` for details. :raises: :exc:`~exceptions.ValueError` when `size` is invalid, :exc:`~executor.ExternalCommandFailed` when the command fails. """ context = coerce_context(context) size = coerce_size(size) logger.debug("Creating image file of %i bytes: %s", size, filename) head_command = 'head --bytes=%i /dev/zero > %s' context.execute(head_command % (size, quote(filename)), shell=True, tty=False)
def test_coerce_size(self): """Test coercion of data sizes.""" assert coerce_size(1) == 1 assert coerce_size('5 KiB') == 5120 self.assertRaises(ValueError, coerce_size, None)