diff --git a/src/api/encryption_add.c b/src/api/encryption_add.c
new file mode 100644
index 0000000000000000000000000000000000000000..57132fb1ff29eadda9d8f725886cc606ff1e98a5
--- /dev/null
+++ b/src/api/encryption_add.c
@@ -0,0 +1,145 @@
+/**
+ * Callback function for encrypting an unencrypted device.
+ * @param[in]   request   incoming HTTP request
+ * @param[out]  response  HTTP response to the request
+ * @param[in]   user_data extra data to pass between main thread and callbacks
+ * @return                internal status code
+ */
+int callback_encryption_add(const struct _u_request * request,
+    struct _u_response * response, void * user_data)
+{
+    int r;
+
+    // Read the encryption password from the request body.
+    json_t * json_input = ulfius_get_json_body_request(request, NULL);
+    const char * password = password = json_string_value(
+        json_object_get(json_input, "password"));
+    if (password == NULL)
+    {
+        return send_simple_response(response, 400, "error", "missing password");
+    }
+ 
+    // Check if the device isn't already encrypted.
+    bool device_encrypted = is_encrypted_device(CONTAINER_DEVICE);
+    if (device_encrypted)
+    {
+        // The device is already encrypted; we don't want to encrypt it again.
+        return send_simple_response(response, 500, "error",
+           "already encrypted");
+    }
+
+    // Create temporary mountpoint.
+    r = temporary_mount(CONTAINER_DEVICE, UNENCRYPTED_MOUNTPOINT,
+        FILESYSTEM_TYPE);
+    if (r != 0)
+    {
+        return send_simple_response(response, 500, "error",
+           "mounting root disk failed");
+    }
+
+    // Determine the filesystem usage of the device to be encrypted.
+    unsigned long size = filesystem_usage(UNENCRYPTED_MOUNTPOINT);
+    printf("root disk usage: %lu bytes\n", size);
+
+    // Determine the available memory.
+    unsigned long memory = available_memory();
+
+    double projected_usage = (double)size / (double)memory;
+    printf("projected memory usage: %.3f\n", projected_usage);
+    if (projected_usage > MEMORY_USAGE)
+    {
+        // Projected memory usage is really high, so abort.
+        return send_simple_response(response, 500, "error",
+           "device too large");
+    }
+
+    // Copy device contents to temporary filesystem.
+    printf("copying existing root disk contents to memory\n");
+    char * command = NULL;
+    asprintf(&command, "rsync -a %s/ %s", UNENCRYPTED_MOUNTPOINT, TMP_LOCATION);
+    r = system(command);
+    if(r != 0)
+    {
+        return send_simple_response(response, 500, "error",
+           "copying rootdisk contents into memory failed");
+    }
+
+    // Unmount unencrypted device.
+    printf("unmounting unencrypted device at %s\n", UNENCRYPTED_MOUNTPOINT);
+    r = umount(UNENCRYPTED_MOUNTPOINT);
+    if (r != 0)
+    {
+        return send_simple_response(response, 500, "error",
+           "unmounting unencrypted disk failed");
+    }
+
+    // Initialise encrypted container, overwriting existing device.
+    printf("creating encrypted device at %s\n", CONTAINER_DEVICE);
+    r = create_encrypted_device(CONTAINER_DEVICE, password);
+    if(r != 0)
+    {
+        return send_simple_response(response, 500, "error",
+           "creating encryption container failed");
+    }
+
+    // Unlock the new container.
+    printf("unlocking encrypted device\n");
+    r = encryption_unlock(CONTAINER_DEVICE, MAPPED_DEVICE_NAME, password);
+    if(r != 0)
+    {
+        return send_simple_response(response, 500, "error",
+           "unlocking new encryption container failed");
+    }
+
+    // Create filesystem in the new container.
+    printf("creating filesystem in new container\n");
+    command = NULL;
+    asprintf(&command, "mkfs -t %s %s", FILESYSTEM_TYPE, MAPPED_DEVICE_PATH);
+    r = system(command);
+    if(r != 0)
+    {
+        return send_simple_response(response, 500, "error",
+           "creating filesystem inside encrypted container failed");
+    }
+
+    // Mount the unlocked container.
+    printf("mounting new filesystem\n");
+    r = temporary_mount(MAPPED_DEVICE_PATH, ENCRYPTED_MOUNTPOINT,
+        FILESYSTEM_TYPE);
+    if (r != 0)
+    {
+        return send_simple_response(response, 500, "error",
+           "mounting encrypted root disk failed");
+    }
+
+    // Copy device contents from temporary filesystem to encrypted container.
+    printf("copying root disk contents from memory\n");
+    command = NULL;
+    asprintf(&command, "rsync -a %s/ %s", TMP_LOCATION, ENCRYPTED_MOUNTPOINT);
+    r = system(command);
+    if(r != 0)
+    {
+        return send_simple_response(response, 500, "error",
+           "copying rootdisk contents from memory failed");
+    }
+
+    // Unmount encrypted device.
+    printf("unmounting encrypted device at %s\n", ENCRYPTED_MOUNTPOINT);
+    r = umount(ENCRYPTED_MOUNTPOINT);
+    if (r != 0)
+    {
+        return send_simple_response(response, 500, "error",
+           "unmounting encrypted disk failed");
+    }
+
+    // Lock the container.
+    printf("locking encrypted device\n");
+    r = encryption_lock(MAPPED_DEVICE_NAME);
+    if(r != 0)
+    {
+        return send_simple_response(response, 500, "error",
+           "locking container failed");
+    }
+
+    return send_simple_response(response, 200, "status", "ok");
+}
diff --git a/src/auxiliary.c b/src/auxiliary.c
index b025dddd734718554a07a9c363fdd7df5106a5ae..722b3589d408adccfa47fffce012ef5a7765a702 100644
--- a/src/auxiliary.c
+++ b/src/auxiliary.c
@@ -61,3 +61,69 @@ int send_simple_response(struct _u_response * response, int http_status,
     json_decref(json_body);
     return U_CALLBACK_CONTINUE;
 }
+
+/**
+ * Determine the size of a block device.
+ * @param  device_path Path to the block device.
+ * @return             Size of the device in bytes.
+ */
+unsigned long device_size(char * device_path)
+{
+    int fd;
+    unsigned long numblocks = 0;
+
+    fd = open(device_path, O_RDONLY);
+    ioctl(fd, BLKGETSIZE, &numblocks);
+    close(fd);
+    printf("Number of blocks: %lu, this makes %.3f GB\n",
+        numblocks, (double)numblocks * 512.0 / (1024 * 1024 * 1024));
+    return (numblocks * 512);
+}
+
+/**
+ * Determine available memory.
+ * @return Available memory in bytes.
+ */
+unsigned long available_memory()
+{
+  struct sysinfo myinfo;
+  unsigned long free_bytes;
+  sysinfo(&myinfo);
+  free_bytes = myinfo.mem_unit * myinfo.freeram;
+  printf("Free memory: %lu B, %lu MB\n",
+      free_bytes, free_bytes / 1024 / 1024);
+  return free_bytes;
+}
+
+/**
+ * Determine the usage of the given filesystem.
+ * @param  path Path of the mounted filesystem.
+ * @return      Number of bytes used.
+ */
+unsigned long filesystem_usage(const char * path)
+{
+    struct statvfs s;
+    statvfs(path, &s);
+    return (s.f_blocks - s.f_bfree) * s.f_bsize;
+}
+
+/**
+ * Mount a filesystem; create the mount target if it doesn't exist.
+ * @param  device_path Path to the device to mount.
+ * @param  mount_path  Path to the mount target.
+ * @return             Status code.
+ */
+int temporary_mount(char * device_path, char * mount_path,
+    char * filesystem_type)
+{
+    struct stat st = {0};
+    if (stat(mount_path, &st) == -1)
+    {
+        mkdir(mount_path, 0700);
+    }
+    // Mount the device.
+    unsigned long mount_flags = MS_NOATIME | MS_NODEV | MS_NOEXEC;
+    int r = mount(device_path, mount_path, filesystem_type,
+        mount_flags, "");
+    return r;
+}
diff --git a/src/cryptops-api.c b/src/cryptops-api.c
index 3ae3b6de924276b46f58954bdc81350f604281c5..e9c560f220c3262fbfc6477181690376d1a5c441 100644
--- a/src/cryptops-api.c
+++ b/src/cryptops-api.c
@@ -6,6 +6,7 @@
 #include <auxiliary.c>
 #include <encryption_functions.c>
 #include <api/default.c>
+#include <api/encryption_add.c>
 #include <api/encryption_unlock.c>
 
 int main(int argc, char ** argv)
@@ -26,6 +27,8 @@ int main(int argc, char ** argv)
     instance.max_post_body_size = 1024;
 
     // Add api endpoints.
+    ulfius_add_endpoint_by_val(&instance, "POST", PREFIX, "/encryption/add",
+        0, &callback_encryption_add, NULL);
     ulfius_add_endpoint_by_val(&instance, "POST", PREFIX, "/encryption/unlock",
         0, &callback_encryption_unlock, NULL);
 
diff --git a/src/encryption_functions.c b/src/encryption_functions.c
index 3f5502d9216c1b3356246ad71f8eea993ffd4473..313b65cbf69452d34f4d59c53d2b9db8448e1a5f 100644
--- a/src/encryption_functions.c
+++ b/src/encryption_functions.c
@@ -28,6 +28,24 @@ static int container_initialise(struct crypt_device **cd, const char *path)
     return r;
 }
 
+/**
+ * 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);
+    crypt_free(cd);
+    if (r < 0)
+    {
+        return false;
+    }
+
+    return true;
+}
+
 /**
  * Use cryptsetup to unlock the luks container.
  * This will create `/dev/mapper/$device_name`.
@@ -68,3 +86,96 @@ static int encryption_unlock(const char *path, const char *device_name,
     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)
+    {
+        printf("crypt_init_by_name() failed for %s.\n", device_name);
+        return r;
+    }
+
+    if (crypt_status(cd, device_name) == CRYPT_ACTIVE)
+    {
+        printf("Device %s is still active.\n", device_name);
+    }
+    else
+    {
+        printf("Something failed perhaps, device %s is not active.\n",
+            device_name);
+        crypt_free(cd);
+        return -1;
+    }
+
+    r = crypt_deactivate(cd, device_name);
+    if (r < 0)
+    {
+        printf("crypt_deactivate() failed.\n");
+        crypt_free(cd);
+        return r;
+    }
+
+    printf("Device %s is now deactivated.\n", 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 )
+    {
+        printf("crypt_init() failed for %s.\n", path);
+        return r;
+    }
+
+    printf("Context is attached to block device %s.\n",
+        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)
+    {
+        printf("crypt_format() failed on device %s\n",
+            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)
+    {
+        printf("Adding keyslot failed.\n");
+        crypt_free(cd);
+        return r;
+    }
+    printf("The first keyslot is initialized.\n");
+
+    crypt_free(cd);
+    return 0;
+}
diff --git a/src/includes/common-includes.h b/src/includes/common-includes.h
index 910cd619c913769648c973216a08fe6ca0fad744..b54967d00ee393e07612081f88f765adb3291033 100644
--- a/src/includes/common-includes.h
+++ b/src/includes/common-includes.h
@@ -1,5 +1,11 @@
 #include <string.h>
+#include <stdbool.h>
 #include <sys/stat.h>
+#include <sys/sysinfo.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/statvfs.h>
+#include <linux/fs.h>
 #include <fcntl.h>
 
 #define U_DISABLE_CURL
diff --git a/src/includes/settings.h b/src/includes/settings.h
index 10122d0d82a84dda308221ff02a8db4c2ef4e71f..33fdc3c1e3e980760ff6a49e1f69455cbbaadfe1 100644
--- a/src/includes/settings.h
+++ b/src/includes/settings.h
@@ -2,3 +2,9 @@
 #define PORT 8000
 #define CONTAINER_DEVICE "/dev/xvda1"
 #define MAPPED_DEVICE_NAME "xvda1_crypt"
+#define MAPPED_DEVICE_PATH "/dev/mapper/" MAPPED_DEVICE_NAME
+#define FILESYSTEM_TYPE "xfs"
+#define MEMORY_USAGE 0.8
+#define UNENCRYPTED_MOUNTPOINT "/tmp/mnt-plain"
+#define ENCRYPTED_MOUNTPOINT "/tmp/mnt-encrypted"
+#define TMP_LOCATION "/tmp/" MAPPED_DEVICE_NAME