diff --git a/Vagrantfile b/Vagrantfile
index 678efd39c44c2238c9f729c4af26846c34bd562d..42171daf6e3883ed829fb12633f344f3d24ae480 100644
--- a/Vagrantfile
+++ b/Vagrantfile
@@ -3,9 +3,16 @@
 
 Vagrant.configure("2") do |config|
   config.vm.box = "debian/jessie64"
-  config.vm.synced_folder ".", "/test", type: 'virtualbox'
+  config.vm.synced_folder ".", "/cryptops-api", type: 'virtualbox'
+  # If cryptops-client directory exists, mount it as well so you can test easier
+  if File.directory?(File.expand_path('../cryptops-client'))
+      config.vm.synced_folder "../cryptops-client", "/cryptops-client", type: 'virtualbox'
+  end
   config.vm.provision "shell", inline: <<-SHELL
     apt-get update
     apt-get install -y libmicrohttpd-dev libjansson-dev libcurl4-gnutls-dev libgnutls28-dev libgcrypt20-dev libcryptsetup-dev
+    if ! grep -q 'export LD_LIBRARY_PATH="/cryptops-api/libraries"' /home/vagrant/.bashrc ; then
+        echo export LD_LIBRARY_PATH="/cryptops-api/libraries">> /home/vagrant/.bashrc
+    fi
   SHELL
 end
diff --git a/src/api/ssh_keys_delete.c b/src/api/ssh_keys_delete.c
new file mode 100644
index 0000000000000000000000000000000000000000..9c763b8cf1ff52a941a5194eb1bfbf05892c0235
--- /dev/null
+++ b/src/api/ssh_keys_delete.c
@@ -0,0 +1,45 @@
+/**
+ * Callback function that deletes an SSH key from the list of keys authorised
+ * for access to the initrd. The line will be left empty, because that keeps
+ * the ids of SSH keys intact for ssh_keys_get
+ *
+ * @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_ssh_keys_delete(const struct _u_request * request,
+    struct _u_response * response, void * user_data)
+{
+    // Read ssh key id from request URI.
+    const char * id_string = u_map_get(request->map_url, "id");
+    if (id_string == NULL)
+    {
+        return send_simple_response(response, 400, "error",
+            "missing url parameter `id`");
+    }
+
+    int id;
+    int r = parse_int(id_string, &id);
+    if (r != 0)
+    {
+        printf("invalid url parameter `id`: %s\n", id_string);
+        return send_simple_response(response, 400, "error",
+            "invalid url parameter `id`");
+    }
+
+    // Replace the key at ID with ""
+    r = replace_ssh_key(id, "");
+    if (r < 0)
+    {
+        if (r == -1)
+            return send_simple_response(response, 500, "error",
+                "error opening authorized_keys");
+        if (r == -2)
+            return send_simple_response(response, 500, "error",
+                "error opening authorized_keys tmp file");
+        return send_simple_response(response, 500, "error",
+            "Unknown error while processing ssh keys");
+    }
+    return send_simple_response(response, 200, "status", "ok");
+}
diff --git a/src/api/ssh_keys_get.c b/src/api/ssh_keys_get.c
index 255442174be3a3f72fa99ed6eb59b766a4865c42..3818706297ada1c2e81f56eb61d211c16390ef40 100644
--- a/src/api/ssh_keys_get.c
+++ b/src/api/ssh_keys_get.c
@@ -23,11 +23,15 @@ json_t * readAuthorizedKeysToJson()
     ssize_t read;
     while ((read = getline(&line, &line_length, authorized_keys)) != -1)
     {
-        asprintf(&field, "%d", index);
-        // Remove trailing newline.
-        line[strcspn(line, "\n")] = 0;
-        json_object_set(keys, field, json_string(line));
-        ++index;
+        // Ignore empty lines, they do have IDs though.
+        if (strlen(line) > 1)
+        {
+            asprintf(&field, "%d", index);
+            // Remove trailing newline.
+            line[strcspn(line, "\n")] = 0;
+            json_object_set(keys, field, json_string(line));
+        }
+        index++;
     }
 
     // Close file and clean up.
diff --git a/src/api/ssh_keys_post.c b/src/api/ssh_keys_post.c
index 08fd28f2628463ca8530e238beb4f3f434974e24..30633c144cb5c25504cb9d9e9201429e9493e90d 100644
--- a/src/api/ssh_keys_post.c
+++ b/src/api/ssh_keys_post.c
@@ -41,13 +41,12 @@ int callback_ssh_keys_post(const struct _u_request * request,
         return send_simple_response(response, 400, "error", "missing ssh-key");
     }
 
+    // add cryptops-client command to ssh-key
     char * ssh_key_with_command;
-
     add_ssh_command(&ssh_key_with_command, ssh_key);
 
-    asprintf(&ssh_key_with_command, "%s\n", ssh_key_with_command);
-
     // Write SSH key to file
+    asprintf(&ssh_key_with_command, "%s\n", ssh_key_with_command);
     fprintf(authorized_keys, ssh_key_with_command);
     fclose(authorized_keys);
 
diff --git a/src/api/ssh_keys_put.c b/src/api/ssh_keys_put.c
new file mode 100644
index 0000000000000000000000000000000000000000..9bf53bde27041c323d0aa26f1fb1182968bd092c
--- /dev/null
+++ b/src/api/ssh_keys_put.c
@@ -0,0 +1,60 @@
+/**
+ * Callback function that updates an SSH key in the list of keys authorised
+ * for access to the initrd. Needs an ID provided in the URL and a new SSH key
+ * provided in the request body.
+ *
+ * @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_ssh_keys_put(const struct _u_request * request,
+    struct _u_response * response, void * user_data)
+{
+    // Read ssh key id from request URI.
+    const char * id_string = u_map_get(request->map_url, "id");
+    if (id_string == NULL)
+    {
+        return send_simple_response(response, 400, "error",
+            "missing url parameter `id`");
+    }
+
+    int id;
+    int r = parse_int(id_string, &id);
+    if (r != 0)
+    {
+        printf("invalid url parameter `id`: %s\n", id_string);
+        return send_simple_response(response, 400, "error",
+            "invalid url parameter `id`");
+    }
+
+    // Read in json request body.
+    json_t * json_input = ulfius_get_json_body_request(request, NULL);
+
+    // Read SSH key from request.
+    const char * ssh_key;
+    ssh_key = json_string_value(json_object_get(json_input, "ssh-key"));
+    if (ssh_key == NULL)
+    {
+        return send_simple_response(response, 400, "error", "missing ssh-key");
+    }
+
+    // add cryptops-client command to ssh-key
+    char * ssh_key_with_command;
+    add_ssh_command(&ssh_key_with_command, ssh_key);
+
+    r = replace_ssh_key(id, ssh_key_with_command);
+
+    if (r < 0)
+    {
+        if (r == -1)
+            return send_simple_response(response, 500, "error",
+                "error opening authorized_keys");
+        if (r == -2)
+            return send_simple_response(response, 500, "error",
+                "error opening authorized_keys tmp file");
+        return send_simple_response(response, 500, "error",
+            "Unknown error while processing ssh keys");
+    }
+    return send_simple_response(response, 200, "status", "ok");
+}
diff --git a/src/auxiliary.c b/src/auxiliary.c
index db1f7af3102e10c382acff61258b17dc3a222ad8..85cc449bed997b11fcebffaaa7c091d847d99562 100644
--- a/src/auxiliary.c
+++ b/src/auxiliary.c
@@ -220,6 +220,92 @@ int parse_int(const char * input, int * result)
     return 0;
 }
 
+/**
+ * Write an ssh_key to a specific rule in the authorized_keys file.
+ *
+ * @param[in]   id      line number/ssh_key id
+ * @param[in]   ssh_key ssh key contents. If this string is empty, this is seen
+ *                      as deleting the key. Newline characters are ignored
+ */
+int replace_ssh_key(int id, const char * ssh_key)
+{
+    // Open file.
+    FILE * authorized_keys_in = fopen(AUTHORIZED_KEYS_PATH, "r");
+    // Check if that succeeded.
+    if (authorized_keys_in == NULL)
+    {
+        printf("Could not open authorized_keys file for reading\n");
+        return -1;
+    }
+
+    // Make tmp outfile for authorized keys
+    char * authorized_keys_out_name;
+    asprintf(&authorized_keys_out_name, "%s%s", AUTHORIZED_KEYS_PATH, ".tmp");
+
+    // Open file.
+    FILE * authorized_keys_out = fopen(authorized_keys_out_name, "w");
+    // Check if that succeeded.
+    if (authorized_keys_out == NULL)
+    {
+        printf("Could not open authorized_keys tmp file for writing\n");
+        return -2;
+    }
+
+    char ch;
+    int line_number = 1;
+
+    // Loop through all the lines in the input file
+    do
+    {
+        if (line_number != id)
+        {
+            // Copy 1 line
+            ch = getc(authorized_keys_in);
+            while (ch != EOF && ch != '\n')
+            {
+                // Copy all lines that don't have id as line number
+                putc(ch, authorized_keys_out);
+                ch = getc(authorized_keys_in);
+            }
+        }
+        else
+        {
+            // Insert an ssh key instead of a line
+            ch = *ssh_key++;
+            while (ch != '\0')
+            {
+                // New line in ssh key is not allowed, because that will screw
+                // up the indices
+                if (ch != '\n')
+                    putc(ch, authorized_keys_out);
+                ch = *ssh_key++;
+            }
+
+            // ignore replaced line
+            do
+            {
+                ch = getc(authorized_keys_in);
+            } while (ch != EOF && ch != '\n');
+        }
+
+        if (ch != EOF)
+        {
+            // Insert newline
+            putc('\n', authorized_keys_out);
+            // Increment line number
+            line_number++;
+        }
+    } while (ch != EOF);
+
+    fclose(authorized_keys_in);
+    fclose(authorized_keys_out);
+
+    // Remove old authorized_keys file and replace it with the new one
+    remove(AUTHORIZED_KEYS_PATH);
+    rename(authorized_keys_out_name, AUTHORIZED_KEYS_PATH);
+    return 0;
+}
+
 /**
  * Add the SSH_COMMAND string in front of ssh_key unless it's already there
  * because people have seen it being used in ssh_keys_list.
diff --git a/src/cryptops-api.c b/src/cryptops-api.c
index ffbc915b82a7fb604da6d7c1c47c87a2187ce497..87dc0d6953fa5636df908c5564c78e0978f70e83 100644
--- a/src/cryptops-api.c
+++ b/src/cryptops-api.c
@@ -12,7 +12,9 @@
 #include <api/encryption_unlock_post.c>
 #include <api/encryption_keys_put.c>
 #include <api/ssh_keys_get.c>
+#include <api/ssh_keys_put.c>
 #include <api/ssh_keys_post.c>
+#include <api/ssh_keys_delete.c>
 
 int main(int argc, char ** argv)
 {
@@ -58,9 +60,15 @@ int main(int argc, char ** argv)
     ulfius_add_endpoint_by_val(&instance, "GET" , PREFIX,
         "/ssh/keys",
         0, &callback_ssh_keys_get, NULL);
+    ulfius_add_endpoint_by_val(&instance, "PUT" , PREFIX,
+        "/ssh/keys/:id",
+        0, &callback_ssh_keys_put, NULL);
     ulfius_add_endpoint_by_val(&instance, "POST" , PREFIX,
         "/ssh/keys",
         0, &callback_ssh_keys_post, NULL);
+    ulfius_add_endpoint_by_val(&instance, "DELETE" , PREFIX,
+        "/ssh/keys/:id",
+        0, &callback_ssh_keys_delete, NULL);
 
     // Add default endpoint.
     ulfius_set_default_endpoint(&instance, &callback_default, NULL);