diff --git a/src/api/encryption_init.c b/src/api/encryption_init.c
index f708cd0d5e1cfc7d1282ebe01f8085eea74ee606..5f2880be01f23dd315022b82244b1fa6ca00578f 100644
--- a/src/api/encryption_init.c
+++ b/src/api/encryption_init.c
@@ -53,7 +53,7 @@ int callback_encryption_init(const struct _u_request * request,
     }
 
     // Mount the filesystem on the unencrypted device.
-    r = temporary_mount(ROOT_DEVICE, UNENCRYPTED_MOUNTPOINT,
+    r = temporary_mount(ROOT_DEVICE, UNENCRYPTED_TMP_MOUNTPOINT,
         FILESYSTEM_TYPE);
     if (r != 0)
     {
@@ -63,7 +63,7 @@ int callback_encryption_init(const struct _u_request * request,
     }
 
     // Determine the filesystem usage of the device to be encrypted.
-    unsigned long size = filesystem_usage(UNENCRYPTED_MOUNTPOINT);
+    unsigned long size = filesystem_usage(UNENCRYPTED_TMP_MOUNTPOINT);
     if (size < 0)
     {
         // Something went wrong in determining the filesystem usage.
@@ -88,7 +88,8 @@ int callback_encryption_init(const struct _u_request * request,
     // Copy device contents to temporary filesystem.
     printf("copying existing root device contents to memory\n");
     char * command = NULL;
-    asprintf(&command, "rsync -a %s/ %s", UNENCRYPTED_MOUNTPOINT, TMP_LOCATION);
+    asprintf(&command, "rsync -a %s/ %s", UNENCRYPTED_TMP_MOUNTPOINT,
+        TMP_LOCATION);
     r = system(command);
     if(r != 0)
     {
@@ -99,8 +100,8 @@ int callback_encryption_init(const struct _u_request * request,
     }
 
     // Unmount unencrypted device.
-    printf("unmounting unencrypted device at %s\n", UNENCRYPTED_MOUNTPOINT);
-    r = umount(UNENCRYPTED_MOUNTPOINT);
+    printf("unmounting unencrypted device at %s\n", UNENCRYPTED_TMP_MOUNTPOINT);
+    r = umount(UNENCRYPTED_TMP_MOUNTPOINT);
     if (r != 0)
     {
         printf("unmounting encrypted device failed: return code %d\n", r);
@@ -166,7 +167,7 @@ int callback_encryption_init(const struct _u_request * request,
 
     // Mount the info partition.
     printf("mounting info partition\n");
-    r = temporary_mount(INFO_PARTITION_DEVICE, INFO_MOUNTPOINT,
+    r = temporary_mount(INFO_PARTITION_DEVICE, INFO_TMP_MOUNTPOINT,
         FILESYSTEM_TYPE);
     if (r != 0)
     {
@@ -178,8 +179,8 @@ int callback_encryption_init(const struct _u_request * request,
     // Create some directories in the info partition.
     printf("creating directories in info partition\n");
     command = NULL;
-    asprintf(&command, "mkdir -p %s%s %s%s", INFO_MOUNTPOINT,
-        AUTHORIZED_KEYS_DIR, INFO_MOUNTPOINT, SSH_HOST_KEY_DIR);
+    asprintf(&command, "mkdir -p %s%s %s%s", INFO_TMP_MOUNTPOINT,
+        AUTHORIZED_KEYS_DIR, INFO_TMP_MOUNTPOINT, SSH_HOST_KEY_DIR);
     r = system(command);
     if (r != 0)
     {
@@ -192,7 +193,7 @@ int callback_encryption_init(const struct _u_request * request,
     printf("copying authorized_keys to info partition\n");
     command = NULL;
     asprintf(&command, "cp %s %s%s",
-        AUTHORIZED_KEYS_PATH, INFO_MOUNTPOINT, AUTHORIZED_KEYS_PATH);
+        AUTHORIZED_KEYS_PATH, INFO_TMP_MOUNTPOINT, AUTHORIZED_KEYS_PATH);
     r = system(command);
     if (r != 0)
     {
@@ -204,7 +205,7 @@ int callback_encryption_init(const struct _u_request * request,
     // Copy dropbear ssh host keys from the initrd to the info partition.
     printf("copying dropbear ssh host keys\n");
     command = NULL;
-    asprintf(&command, "cp /etc/dropbear/* %s%s/", INFO_MOUNTPOINT,
+    asprintf(&command, "cp /etc/dropbear/* %s%s/", INFO_TMP_MOUNTPOINT,
         SSH_HOST_KEY_DIR);
     r = system(command);
     if (r != 0)
@@ -215,8 +216,8 @@ int callback_encryption_init(const struct _u_request * request,
     }
 
     // Unmount info partition.
-    printf("unmounting info partition at %s\n", INFO_MOUNTPOINT);
-    r = umount(INFO_MOUNTPOINT);
+    printf("unmounting info partition at %s\n", INFO_TMP_MOUNTPOINT);
+    r = umount(INFO_TMP_MOUNTPOINT);
     if (r != 0)
     {
         printf("unmounting failed: return code %d\n", r);
@@ -259,7 +260,7 @@ int callback_encryption_init(const struct _u_request * request,
 
     // Mount the unlocked container.
     printf("mounting new filesystem\n");
-    r = temporary_mount(MAPPED_DEVICE_PATH, DATA_MOUNTPOINT,
+    r = temporary_mount(MAPPED_DEVICE_PATH, DATA_TMP_MOUNTPOINT,
         FILESYSTEM_TYPE);
     if (r != 0)
     {
@@ -271,7 +272,7 @@ int callback_encryption_init(const struct _u_request * request,
     // Copy device contents from temporary filesystem to encrypted container.
     printf("copying root device contents from memory\n");
     command = NULL;
-    asprintf(&command, "rsync -a %s/ %s", TMP_LOCATION, DATA_MOUNTPOINT);
+    asprintf(&command, "rsync -a %s/ %s", TMP_LOCATION, DATA_TMP_MOUNTPOINT);
     r = system(command);
     if (r != 0)
     {
@@ -282,8 +283,8 @@ int callback_encryption_init(const struct _u_request * request,
     }
 
     // Unmount filesystem on encrypted data partition.
-    printf("unmounting encrypted device at %s\n", DATA_MOUNTPOINT);
-    r = umount(DATA_MOUNTPOINT);
+    printf("unmounting encrypted device at %s\n", DATA_TMP_MOUNTPOINT);
+    r = umount(DATA_TMP_MOUNTPOINT);
     if (r != 0)
     {
         printf("unmounting encrypted device failed: return code %d\n", r);
diff --git a/src/api/encryption_remove.c b/src/api/encryption_remove.c
new file mode 100644
index 0000000000000000000000000000000000000000..f49529aa444f7f0fe0c72518d075ac01329deee4
--- /dev/null
+++ b/src/api/encryption_remove.c
@@ -0,0 +1,208 @@
+/**
+ * Callback function for permanently decrypting an encrypted device.
+ * It proceeds as follows:
+ * 1.  read the encryption password from the request body;
+ * 2.  check if the device isn't already encrypted;
+ * 3.  unlock the encrypted container;
+ * 4.  mount the filesystem on the encrypted device;
+ * 5.  check if there is enough available memory to contain all files currently
+ *     stored on the device;
+ * 6.  copy device contents to temporary filesystem;
+ * 7.  unmount encrypted device;
+ * 8.  lock the container;
+ * 9.  unmount info partition;
+ * 10. remove all partitions from the device;
+ * 11. create a new filesystem on the unencrypted device;
+ * 12. mount the new filesystem;
+ * 13. copy device contents from memory to encrypted container;
+ * 14. unmount the new filesystem;
+ * 15. reboot.
+ * @param[in]   request   incoming HTTP request
+ * @param[out]  response  HTTP response to the request
+ * @param[in]   user_data extra data to pass between handler and main thread
+ * @return                internal status code
+ */
+int callback_encryption_remove(const struct _u_request * request,
+    struct _u_response * response, void * user_data)
+{
+    bool * reboot = (bool *)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 is encrypted.
+    if (! is_encrypted_device(DATA_PARTITION_DEVICE))
+    {
+        // The device is not encrypted, so this command does not make sense.
+        return send_simple_response(response, 400, "error",
+           "not encrypted");
+    }
+
+    // Unlock the container.
+    printf("unlocking encrypted device\n");
+    r = encryption_unlock(DATA_PARTITION_DEVICE, MAPPED_DEVICE_NAME,
+        password);
+    if (r == -1)
+    {
+        // The return code -1 signals that the password is wrong.
+        return send_simple_response(response, 403, "error",
+           "incorrect password");
+    }
+    if (r != 0)
+    {
+        printf("unlocking encrypted container failed: return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "unlocking encrypted container failed");
+    }
+
+    // Mount the filesystem on the encrypted data partition.
+    r = temporary_mount(MAPPED_DEVICE_PATH, DATA_TMP_MOUNTPOINT,
+        FILESYSTEM_TYPE);
+    if (r != 0)
+    {
+        printf("mounting root device failed: return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "mounting root device failed");
+    }
+
+    // Determine the filesystem usage of the encrypted data partition.
+    unsigned long size = filesystem_usage(DATA_TMP_MOUNTPOINT);
+    if (size < 0)
+    {
+        // Something went wrong in determining the filesystem usage.
+        printf("determining filesystem usage failed: return code %lu\n", size);
+        return send_simple_response(response, 500, "error",
+           "determining filesystem usage failed");
+    }
+    printf("root device 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 device contents to memory\n");
+    char * command = NULL;
+    asprintf(&command, "rsync -a %s/ %s", DATA_TMP_MOUNTPOINT, TMP_LOCATION);
+    r = system(command);
+    if(r != 0)
+    {
+        printf("copying root device contents into memory failed"
+            ": return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+            "copying root device contents into memory failed");
+    }
+
+    // Unmount encrypted data partition.
+    printf("unmounting encrypted device at %s\n", DATA_TMP_MOUNTPOINT);
+    r = umount(DATA_TMP_MOUNTPOINT);
+    if (r != 0)
+    {
+        printf("unmounting encrypted device failed: return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "unmounting encrypted device failed");
+    }
+
+    // Lock the container.
+    printf("locking encrypted device\n");
+    r = encryption_lock(MAPPED_DEVICE_NAME);
+    if (r != 0)
+    {
+        printf("locking encrypted container failed: return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "locking encrypted container failed");
+    }
+
+    // Unmount info partition.
+    // We didn't mount this in cryptops-api, but it was mounted by the initrd
+    // scripts for use by dropbear.
+    printf("unmounting info partition at %s\n", INFO_MOUNTPOINT);
+    r = umount(INFO_MOUNTPOINT);
+    if (r != 0)
+    {
+        printf("unmounting info partition failed: return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "unmounting info partition failed");
+    }
+
+    // Remove all partitions from the device.
+    printf("removing partitions from device %s\n", ROOT_DEVICE);
+    command = NULL;
+    asprintf(&command, "sgdisk -Z %s", ROOT_DEVICE);
+    r = system(command);
+    if (r != 0)
+    {
+        printf("removing partitions failed: return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "removing partitions failed");
+    }
+
+    // Create filesystem on the unencrypted device.
+    printf("creating filesystem on unencrypted device\n");
+    command = NULL;
+    asprintf(&command, "mkfs -t %s %s", FILESYSTEM_TYPE, ROOT_DEVICE);
+    r = system(command);
+    if (r != 0)
+    {
+        printf("creating filesystem failed: return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "creating filesystem on unencrypted device failed");
+    }
+
+    // Mount the new filesystem.
+    printf("mounting new filesystem\n");
+    r = temporary_mount(ROOT_DEVICE, UNENCRYPTED_TMP_MOUNTPOINT,
+        FILESYSTEM_TYPE);
+    if (r != 0)
+    {
+        printf("mounting unencrypted device failed: return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "mounting unencrypted root device failed");
+    }
+
+    // Copy device contents from memory to the unencrypted device.
+    printf("copying root device contents from memory\n");
+    command = NULL;
+    asprintf(&command, "rsync -a %s/ %s",
+        TMP_LOCATION, UNENCRYPTED_TMP_MOUNTPOINT);
+    r = system(command);
+    if (r != 0)
+    {
+        printf("copying from memory to unencrypted device failed:"
+            " return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "copying root device contents from memory failed");
+    }
+
+    // Unmount filesystem on unencrypted device.
+    printf("unmounting unencrypted device at %s\n", UNENCRYPTED_TMP_MOUNTPOINT);
+    r = umount(UNENCRYPTED_TMP_MOUNTPOINT);
+    if (r != 0)
+    {
+        printf("unmounting unencrypted device failed: return code %d\n", r);
+        return send_simple_response(response, 500, "error",
+           "unmounting unencrypted device failed");
+    }
+
+    // Record that we want to reboot the machine.
+    *reboot = true;
+
+    r = send_simple_response(response, 200, "status", "ok");
+    stop_server();
+    return r;
+}
diff --git a/src/cryptops-api.c b/src/cryptops-api.c
index 5a49efdfdcf0deed550936ac842f6f18b0a5c061..c066ad00b075b9aa3d40a967d2e3c5931a877167 100644
--- a/src/cryptops-api.c
+++ b/src/cryptops-api.c
@@ -8,6 +8,7 @@
 #include <api/default.c>
 #include <api/encryption.c>
 #include <api/encryption_init.c>
+#include <api/encryption_remove.c>
 #include <api/encryption_unlock.c>
 #include <api/encryption_keys_put.c>
 #include <api/ssh_keys_get.c>
@@ -44,6 +45,9 @@ int main(int argc, char ** argv)
     ulfius_add_endpoint_by_val(&instance, "POST", PREFIX,
         "/encryption/init",
         0, &callback_encryption_init, &reboot);
+    ulfius_add_endpoint_by_val(&instance, "POST", PREFIX,
+        "/encryption/remove",
+        0, &callback_encryption_remove, &reboot);
     ulfius_add_endpoint_by_val(&instance, "POST", PREFIX,
         "/encryption/unlock",
         0, &callback_encryption_unlock, NULL);
diff --git a/src/includes/settings.h b/src/includes/settings.h
index 8352c51513477907acf8d2148e30fb6807203cbf..5d29b2bc9d50f3c6a3e51b839ff0852603a7be82 100644
--- a/src/includes/settings.h
+++ b/src/includes/settings.h
@@ -1,17 +1,24 @@
 #define PREFIX "/cryptops/v0"
 #define PORT 8000
 #define BIND_ADDRESS "127.0.0.1"
+
 #define ROOT_DEVICE "/dev/xvda"
 #define INFO_PARTITION_DEVICE ROOT_DEVICE "1"
 #define DATA_PARTITION_DEVICE ROOT_DEVICE "2"
 #define MAPPED_DEVICE_NAME "xvda1_crypt"
 #define MAPPED_DEVICE_PATH "/dev/mapper/" MAPPED_DEVICE_NAME
+
 #define FILESYSTEM_TYPE "xfs"
+
 #define MEMORY_USAGE 0.9
-#define UNENCRYPTED_MOUNTPOINT "/tmp/mnt-plain"
-#define INFO_MOUNTPOINT "/tmp/mnt-info"
-#define DATA_MOUNTPOINT "/tmp/mnt-data"
+
+#define UNENCRYPTED_TMP_MOUNTPOINT "/tmp/mnt-plain"
+#define INFO_TMP_MOUNTPOINT "/tmp/mnt-info"
+#define DATA_TMP_MOUNTPOINT "/tmp/mnt-data"
 #define TMP_LOCATION "/tmp/" MAPPED_DEVICE_NAME
+
+#define INFO_MOUNTPOINT "/conf/persistent"
+
 #define AUTHORIZED_KEYS_DIR "/root/.ssh"
 #define AUTHORIZED_KEYS_PATH AUTHORIZED_KEYS_DIR "/authorized_keys"
-#define SSH_HOST_KEY_DIR "/dropbear"
\ No newline at end of file
+#define SSH_HOST_KEY_DIR "/dropbear"