Skip to content
Snippets Groups Projects
encryption_functions.c 5.33 KiB
Newer Older
/**
 * Use cryptsetup to initialise the luks container.
 * It will not be opened (decrypted) yet, but it does check if the container
 * seems usable.
 * @param crypt_device struct to store crypt device context
 * @param path         path to the encrypted container
 * @param debug        whether to print debug messages
 * @return             status code
static int container_initialise(struct crypt_device ** cd, const char * path,
    // Check if the device exists.
    if (! path_exists(path))
        y_log_message(Y_LOG_LEVEL_ERROR, "device does not exist: %s.", path);
    // Let LUKS initialise the encrypted device.
    int r = crypt_init(cd, path);
    if (r < 0)
    {
        if (debug)
        {
                "crypt_init() failed for '%s', status: %d.", path, r);
        return r;
    }

    // Load the LUKS header from the block device into the crypt device context.
    r = crypt_load(*cd, CRYPT_LUKS1, NULL);
    if (r < 0)
    {
        if (debug)
        {
                "crypt_load() failed on device %s.",
                crypt_get_device_name(*cd));
        }
/**
 * Check if the given device is actually an encrypted container.
 * @param path path to the encrypted container
 */
static bool is_encrypted_device(const char * path)
{
    // Let LUKS initialise the encrypted device.
    struct crypt_device * cd;
    int r = container_initialise(&cd, path, false);
    crypt_free(cd);
    return (r >= 0);
/**
 * Use cryptsetup to unlock the luks container.
 * This will create `/dev/mapper/$device_name`.
 * @param path        path to the encrypted container
 * @param device_name name of the mapping
 * @param password    encryption password of the container
 * @return            status code
static int encryption_unlock(const char * path, const char * device_name,
    const char * password)
{
    // Let LUKS initialise the encrypted device.
    struct crypt_device * cd;
    int r = container_initialise(&cd, path, true);
    if (r < 0)
    {
        crypt_free(cd);
    // Create device mapping with name device_name.
    r = crypt_activate_by_passphrase(cd, device_name, CRYPT_ANY_SLOT,
        password, strlen(password), 0);
    if (r < 0)
    {
            "Device %s activation failed.", device_name);
        crypt_free(cd);
        return r;
    }

        "LUKS device %s/%s is active.", crypt_get_dir(), device_name);
    y_log_message(Y_LOG_LEVEL_DEBUG, "\tcipher used: %s",
    y_log_message(Y_LOG_LEVEL_DEBUG, "\tcipher mode: %s",
    y_log_message(Y_LOG_LEVEL_DEBUG, "\tdevice UUID: %s",

    crypt_free(cd);
    return 0;
}

/**
 * Use cryptsetup to lock the luks container again.
 * @param device_name name of the mapping
 * @return            status code
 */
static int encryption_lock(const char * device_name)
    struct crypt_device * cd;
    int r;

    r = crypt_init_by_name(&cd, device_name);
    if (r < 0)
    {
        y_log_message(Y_LOG_LEVEL_ERROR, "crypt_init_by_name() failed for %s.", device_name);
        return r;
    }

    if (crypt_status(cd, device_name) == CRYPT_ACTIVE)
    {
        y_log_message(Y_LOG_LEVEL_ERROR, "Device %s is still active.", device_name);
        y_log_message(Y_LOG_LEVEL_ERROR, "Something failed perhaps, device %s is not active.",
            device_name);
        crypt_free(cd);
        return -1;
    }

    r = crypt_deactivate(cd, device_name);
    if (r < 0)
    {
        y_log_message(Y_LOG_LEVEL_ERROR, "crypt_deactivate() failed.");
        crypt_free(cd);
        return r;
    }

    y_log_message(Y_LOG_LEVEL_DEBUG, "Device %s is now deactivated.", device_name);
    crypt_free(cd);
    return 0;
}

/**
 * Create a new encrypted container on a given device.
 * This overwrites the current contents of the device.
 * @param path     path to the device
 * @param password password of the new container
 * @return         status code
 */
static int create_encrypted_device(const char * path, const char * password)
{
    struct crypt_device * cd;
    struct crypt_params_luks1 params;
    int r;

    r = crypt_init(&cd, path);
    if (r < 0 )
    {
        y_log_message(Y_LOG_LEVEL_ERROR, "crypt_init() failed for %s.", path);
    y_log_message(Y_LOG_LEVEL_DEBUG, "Context is attached to block device %s.",
        crypt_get_device_name(cd));

    params.hash = "sha1";
    params.data_alignment = 0;
    params.data_device = NULL;
    r = crypt_format(cd, CRYPT_LUKS1, "aes", "xts-plain64", NULL, NULL, 256 / 8,
        &params);

    if (r < 0)
    {
        y_log_message(Y_LOG_LEVEL_ERROR, "crypt_format() failed on device %s",
            crypt_get_device_name(cd));
        crypt_free(cd);
        return r;
    }

    r = crypt_keyslot_add_by_volume_key(cd, CRYPT_ANY_SLOT, NULL, 0, password,
        strlen(password));
    if (r < 0)
    {
        y_log_message(Y_LOG_LEVEL_ERROR, "Adding keyslot failed.");
        crypt_free(cd);
        return r;
    }
    y_log_message(Y_LOG_LEVEL_DEBUG, "The first keyslot is initialized.");

    crypt_free(cd);
    return 0;
}