add SIDs and password storage support to Keyguard base

Change-Id: I2b1bb41a5e40e45e810f2bd299edb6b8765df9e6
diff --git a/Android.mk b/Android.mk
index 1c4916c..8a9bd86 100644
--- a/Android.mk
+++ b/Android.mk
@@ -25,7 +25,7 @@
 	keyguard.cpp
 LOCAL_C_INCLUDES := \
 	$(LOCAL_PATH)/include
-LOCAL_CFLAGS = -Wall -Werror
+LOCAL_CFLAGS = -Wall -Werror -g
 LOCAL_MODULE_TAGS := optional
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
diff --git a/include/keyguard/keyguard.h b/include/keyguard/keyguard.h
index 7e06c3e..8141ce3 100644
--- a/include/keyguard/keyguard.h
+++ b/include/keyguard/keyguard.h
@@ -25,24 +25,28 @@
 
 namespace keyguard {
 
+typedef uint64_t secure_id_t;
+typedef uint64_t salt_t;
+
 /**
  * Data format for an authentication record used to prove
  * successful password verification. Consumed by KeyStore
  * and keymaster to determine CryptoObject availability.
+ *
+ * All fields are written in network order.
  */
+const uint8_t AUTH_TOKEN_VERSION = 0;
 struct __attribute__ ((__packed__)) AuthToken {
-    const uint8_t auth_token_tag = 0x01;
-    uint32_t auth_token_size;
-    const uint8_t user_id_tag = 0x02;
-    uint32_t user_id;
-    const uint8_t authenticator_id_tag = 0x03;
-    const uint32_t authenticator_id = 0;
-    const uint8_t timestamp_tag = 0x04;
-    uint64_t timestamp;
-    const uint8_t hmac_tag = 0x06;
-    uint8_t hmac[16];
+    uint8_t auth_token_version = AUTH_TOKEN_VERSION;
+    secure_id_t root_secure_user_id;
+    secure_id_t auxiliary_secure_user_id;
+    uint32_t authenticator_id = 0;
+    uint32_t timestamp;
+    uint8_t hmac[32];
 };
 
+struct password_handle_t;
+
 /**
  * Base class for keyguard implementations. Provides all functionality except
  * the ability to create/access keys and compute signatures. These are left up
@@ -51,7 +55,7 @@
 class Keyguard {
 public:
     Keyguard() {}
-    virtual ~Keyguard();
+    virtual ~Keyguard() {}
 
     void Enroll(const EnrollRequest &request, EnrollResponse *response);
     void Verify(const VerifyRequest &request, VerifyResponse *response);
@@ -72,6 +76,16 @@
      */
     virtual void GetAuthTokenKey(UniquePtr<uint8_t> *auth_token_key, size_t *length)
         const = 0;
+    /**
+     * The key used to sign and verify password data.
+     *
+     * MUST be different from the AuthTokenKey.
+     *
+     * GetPasswordKey is not const because unlike AuthTokenKey,
+     * this value can and should be cached in local memory. The
+     *
+     */
+    virtual void GetPasswordKey(UniquePtr<uint8_t> *password_key, size_t *length) = 0;
 
     /**
      * Uses platform-specific routines to compute a signature on the provided password.
@@ -80,41 +94,38 @@
      * available in case handling for password signatures is different from general
      * purpose signatures.
      *
-     * Assigns the signature to the signature UniquePtr, relinquishing ownership
-     * to the caller.
-     * Writes the length in bytes of the returned key to signature_length if it is not null.
-     *
+     * Writes the signature_length size signature to the 'signature' pointer.
      */
-    virtual void ComputePasswordSignature(const uint8_t *key, size_t key_length,
-            const uint8_t *password, size_t password_length, const uint8_t *salt,
-            size_t salt_length, UniquePtr<uint8_t> *signature, size_t *signature_length) const = 0;
+    virtual void ComputePasswordSignature(uint8_t *signature, size_t signature_length,
+            const uint8_t *key, size_t key_length, const uint8_t *password,
+            size_t password_length, salt_t salt) const = 0;
 
     /**
-     * Retrieves a unique, cryptographically randomly generated salt for use in password
-     * hashing.
+     * Retrieves a unique, cryptographically randomly generated buffer for use in password
+     * hashing, etc.
      *
-     * Assings the salt to the salt UniquePtr, relinquishing ownership to the caller
-     * Writes the length in bytes of the salt to salt_length if it is not null.
+     * Assings the random to the random UniquePtr, relinquishing ownership to the caller
      */
-    virtual void GetSalt(UniquePtr<uint8_t> *salt, size_t *salt_length) const = 0;
+    virtual void GetRandom(void *random, size_t requested_size) const = 0;
 
     /**
      * Uses platform-specific routines to compute a signature on the provided message.
      *
-     * Assigns the signature to the signature UniquePtr, relinquishing ownership
-     * to the caller.
-     * Writes the length in bytes of the returned key to signature_length if it is not null.
+     * Writes the signature_length size signature to the 'signature' pointer.
      */
-    virtual void ComputeSignature(const uint8_t *key, size_t key_length,
-            const uint8_t *message, const size_t length, UniquePtr<uint8_t> *signature,
-            size_t *signature_length) const = 0;
+    virtual void ComputeSignature(uint8_t *signature, size_t signature_length,
+            const uint8_t *key, size_t key_length, const uint8_t *message,
+            const size_t length) const = 0;
 
     /**
-     * The key used to sign and verify password data. This is different from the AuthTokenKey.
-     * It can be cached in this member variable as Keyguard is its only consumer. It should at
-     * no point leave Keyguard for any reason.
+     * Write the password file to persistent storage.
      */
-    SizedBuffer password_key_;
+    virtual void ReadPasswordFile(uint32_t uid, SizedBuffer *password_file) const = 0;
+
+    /**
+     * Read the password file from persistent storage.
+     */
+    virtual void WritePasswordFile(uint32_t uid, const SizedBuffer &password_file) const = 0;
 
 private:
     /**
@@ -123,19 +134,28 @@
      * The format is consistent with that of AuthToken above.
      * Also returns the length in length if it is not null.
      */
-    void MintAuthToken(uint32_t user_id, UniquePtr<uint8_t> *auth_token, size_t *length);
+    void MintAuthToken(UniquePtr<uint8_t> *auth_token, size_t *length, uint32_t timestamp,
+            secure_id_t user_id, secure_id_t authenticator_id);
 
-    // Takes a salt/signature and their lengths and generates a pasword handle written
-    // into result.
-    void SerializeHandle(const uint8_t *salt, size_t salt_length, const uint8_t *signature,
-        size_t signataure_length, SizedBuffer &result);
+    /**
+     * Verifies that handle matches password HMAC'ed with the password_key
+     */
+    bool DoVerify(const password_handle_t *expected_handle, const SizedBuffer &password);
 
-    // Takes a handle and generates pointers into the salt and password inside the handle and
-    // copies out the sizes of those buffers. Makes no allocations.
-    keyguard_error_t DeserializeHandle(const SizedBuffer *handle, uint8_t **salt,
-        size_t *salt_length, uint8_t **password, size_t *password_length);
+    /**
+     * Verifies that the provided handle matches byte-by-byte what was previously
+     * stored as a result of a call to 'Enroll'
+     */
+    bool ValidatePasswordFile(uint32_t uid, const SizedBuffer &provided_handle);
 
+    /**
+     * Populates password_handle with the data provided and computes HMAC.
+     */
+    bool CreatePasswordHandle(SizedBuffer *password_handle, salt_t salt,
+        secure_id_t secure_id, secure_id_t authenticator_id, const uint8_t *password,
+        size_t password_length);
 };
+
 }
 
 #endif // KEYGUARD_H_
diff --git a/include/keyguard/keyguard_messages.h b/include/keyguard/keyguard_messages.h
index eb8a43c..87cb38a 100644
--- a/include/keyguard/keyguard_messages.h
+++ b/include/keyguard/keyguard_messages.h
@@ -37,6 +37,19 @@
     }
 
     /*
+     * Constructs a SizedBuffer of a provided
+     * length.
+     */
+    SizedBuffer(size_t length) {
+        if (length != 0) {
+            buffer.reset(new uint8_t[length]);
+        } else {
+            buffer.reset();
+        }
+        this->length = length;
+    }
+
+    /*
      * Constructs a SizedBuffer out of a pointer and a length
      * Takes ownership of the buf pointer, and deallocates it
      * when destructed.
@@ -123,21 +136,22 @@
 };
 
 struct VerifyResponse : public KeyguardMessage {
-    VerifyResponse(uint32_t user_id, SizedBuffer *verification_token);
+    VerifyResponse(uint32_t user_id, SizedBuffer *auth_token);
     VerifyResponse();
     ~VerifyResponse();
 
-    void SetVerificationToken(SizedBuffer *verification_token);
+    void SetVerificationToken(SizedBuffer *auth_token);
 
     virtual size_t nonErrorSerializedSize() const;
     virtual void nonErrorSerialize(uint8_t *buffer) const;
     virtual keyguard_error_t nonErrorDeserialize(const uint8_t *payload, const uint8_t *end);
 
-    SizedBuffer verification_token;
+    SizedBuffer auth_token;
 };
 
 struct EnrollRequest : public KeyguardMessage {
-    EnrollRequest(uint32_t user_id, SizedBuffer *provided_password);
+    EnrollRequest(uint32_t user_id, SizedBuffer *password_handle,
+            SizedBuffer *provided_password, SizedBuffer *enrolled_password);
     EnrollRequest();
     ~EnrollRequest();
 
@@ -145,6 +159,18 @@
     virtual void nonErrorSerialize(uint8_t *buffer) const;
     virtual keyguard_error_t nonErrorDeserialize(const uint8_t *payload, const uint8_t *end);
 
+    /**
+     * The password handle returned from the previous call to enroll or NULL
+     * if none
+     */
+    SizedBuffer password_handle;
+    /**
+     * The currently enrolled password as entered by the user
+     */
+    SizedBuffer enrolled_password;
+    /**
+     * The password desired by the user
+     */
     SizedBuffer provided_password;
 };
 
diff --git a/include/keyguard/soft_keyguard.h b/include/keyguard/soft_keyguard.h
index 52712af..56ba775 100644
--- a/include/keyguard/soft_keyguard.h
+++ b/include/keyguard/soft_keyguard.h
@@ -25,9 +25,20 @@
 
 #include <UniquePtr.h>
 #include <keyguard/keyguard.h>
+#include <iostream>
 
 namespace keyguard {
 
+/**
+ * Convenience class for easily switching out a testing implementation
+ */
+class KeyguardFileIo {
+public:
+    virtual ~KeyguardFileIo() {}
+    virtual void Write(const char *filename, const uint8_t *bytes, size_t length) = 0;
+    virtual size_t Read(const char *filename, UniquePtr<uint8_t> *bytes) const = 0;
+};
+
 class SoftKeyguard : public Keyguard {
 public:
     static const size_t SALT_LENGTH = 8;
@@ -38,46 +49,67 @@
     static const uint32_t r = 8;
     static const uint32_t p = 1;
 
-    SoftKeyguard() {
-        password_key_.buffer.reset();
-        password_key_.length = 0;
+    static const int MAX_UINT_32_CHARS = 11;
+
+    SoftKeyguard(KeyguardFileIo *file_io) {
+        file_io_ = file_io;
     }
 
-    virtual void GetAuthTokenKey(UniquePtr<uint8_t> *,
+    virtual ~SoftKeyguard() {
+        delete file_io_;
+    }
+
+    virtual void GetAuthTokenKey(UniquePtr<uint8_t> *auth_token_key,
             size_t *length) const {
-        // No auth token key for SW impl
-        if (length != NULL) *length = 0;
+        auth_token_key->reset(new uint8_t[SIGNATURE_LENGTH]);
+        memset(auth_token_key->get(), 0, SIGNATURE_LENGTH);
+        if (length != NULL) *length = SIGNATURE_LENGTH;
     }
 
-    virtual void ComputePasswordSignature(const uint8_t *, size_t,
-            const uint8_t *password, size_t password_length, const uint8_t *salt, size_t salt_length,
-            UniquePtr<uint8_t> *signature, size_t *signature_length) const {
+    virtual void GetPasswordKey(UniquePtr<uint8_t> *password_key, size_t *length) {
+        password_key->reset(new uint8_t[SIGNATURE_LENGTH]);
+        memset(password_key->get(), 0, SIGNATURE_LENGTH);
+        if (length != NULL) *length = SIGNATURE_LENGTH;
+    }
+
+    virtual void ComputePasswordSignature(uint8_t *signature, size_t signature_length,
+            const uint8_t *, size_t, const uint8_t *password,
+            size_t password_length, salt_t salt) const {
         if (signature == NULL) return;
-        uint8_t *signature_bytes = new uint8_t[SIGNATURE_LENGTH];
-        crypto_scrypt(password, password_length, salt, salt_length, N, r, p,
-                signature_bytes, SIGNATURE_LENGTH);
-        if (signature_length != NULL) *signature_length = SIGNATURE_LENGTH;
-        signature->reset(signature_bytes);
+        crypto_scrypt(password, password_length, reinterpret_cast<uint8_t *>(&salt),
+                sizeof(salt), N, r, p, signature, signature_length);
     }
 
-    virtual void GetSalt(UniquePtr<uint8_t> *salt, size_t *salt_length) const {
-        if (salt == NULL) return;
-        uint8_t *salt_bytes = new uint8_t[SALT_LENGTH];
-        RAND_pseudo_bytes(salt_bytes, SALT_LENGTH);
-        if (salt_length != NULL) *salt_length = SALT_LENGTH;
-        salt->reset(salt_bytes);
+    virtual void GetRandom(void *random, size_t requested_length) const {
+        if (random == NULL) return;
+        RAND_pseudo_bytes((uint8_t *) random, requested_length);
     }
 
-    virtual void ComputeSignature(const uint8_t *, size_t,
-                const uint8_t *, const size_t, UniquePtr<uint8_t> *signature,
-                size_t *signature_length) const {
+    virtual void ComputeSignature(uint8_t *signature, size_t signature_length,
+            const uint8_t *, size_t, const uint8_t *, const size_t) const {
         if (signature == NULL) return;
-        if (signature_length != NULL) *signature_length = SIGNATURE_LENGTH;
-        uint8_t *result = new uint8_t[16];
-        memset(result, 0, 16);
-        signature->reset(result);
+        memset(signature, 0, signature_length);
     }
 
+    virtual void ReadPasswordFile(uint32_t uid, SizedBuffer *password_file) const {
+        char buf[MAX_UINT_32_CHARS];
+        sprintf(buf, "%u", uid);
+        UniquePtr<uint8_t> password_buffer;
+        size_t length = file_io_->Read(buf, &password_buffer);
+        password_file->buffer.reset(password_buffer.release());
+        password_file->length = length;
+    }
+
+    virtual void WritePasswordFile(uint32_t uid, const SizedBuffer &password_file) const {
+        char buf[MAX_UINT_32_CHARS];
+        sprintf(buf, "%u", uid);
+        file_io_->Write(buf, password_file.buffer.get(), password_file.length);
+    }
+
+private:
+    KeyguardFileIo *file_io_;
 };
 }
+
 #endif // SOFT_KEYGUARD_H_
+
diff --git a/keyguard.cpp b/keyguard.cpp
index e435a3f..3e1f338 100644
--- a/keyguard.cpp
+++ b/keyguard.cpp
@@ -22,34 +22,74 @@
 
 namespace keyguard {
 
-Keyguard::~Keyguard() {
-    if (password_key_.buffer.get()) {
-        memset_s(password_key_.buffer.get(), 0, password_key_.length);
-    }
-}
+/**
+ * Internal only structure for easy serialization
+ * and deserialization of password handles.
+ */
+static const uint8_t HANDLE_VERSION = 0;
+struct __attribute__ ((__packed__)) password_handle_t {
+    // fields included in signature
+    uint8_t version = HANDLE_VERSION;
+    secure_id_t user_id;
+    secure_id_t authenticator_id;
+
+    // fields not included in signature
+    salt_t salt;
+    uint8_t signature[32];
+};
 
 void Keyguard::Enroll(const EnrollRequest &request, EnrollResponse *response) {
     if (response == NULL) return;
 
-    SizedBuffer enrolled_password;
     if (!request.provided_password.buffer.get()) {
         response->error = KG_ERROR_INVALID;
         return;
     }
 
-    size_t salt_length;
-    UniquePtr<uint8_t> salt;
-    GetSalt(&salt, &salt_length);
+    secure_id_t user_id = 0;
+    uint8_t *current_password = NULL;
+    size_t current_password_size = 0;
 
-    size_t signature_length;
-    UniquePtr<uint8_t> signature;
-    ComputePasswordSignature(password_key_.buffer.get(),
-                password_key_.length, request.provided_password.buffer.get(),
-                request.provided_password.length, salt.get(), salt_length, &signature,
-                &signature_length);
+    if (request.password_handle.buffer.get() == NULL) {
+        // Password handle does not match what is stored, generate new SecureID
+        GetRandom(&user_id, sizeof(secure_id_t));
+    } else {
+        if (!ValidatePasswordFile(request.user_id, request.password_handle)) {
+           response->error = KG_ERROR_INVALID;
+           return;
+        } else {
+            // Password handle matches password file
+            password_handle_t *pw_handle =
+                reinterpret_cast<password_handle_t *>(request.password_handle.buffer.get());
+            if (!DoVerify(pw_handle, request.enrolled_password)) {
+                // incorrect old password
+                response->error = KG_ERROR_INVALID;
+                return;
+            }
 
-    SerializeHandle(salt.get(), salt_length, signature.get(), signature_length, enrolled_password);
-    response->SetEnrolledPasswordHandle(&enrolled_password);
+            user_id = pw_handle->user_id;
+        }
+    }
+
+    salt_t salt;
+    GetRandom(&salt, sizeof(salt));
+
+    secure_id_t authenticator_id;
+    GetRandom(&authenticator_id, sizeof(authenticator_id));
+
+
+    SizedBuffer password_handle;
+    if(!CreatePasswordHandle(&password_handle,
+            salt, user_id, authenticator_id, request.provided_password.buffer.get(),
+            request.provided_password.length)) {
+        response->error = KG_ERROR_INVALID;
+        return;
+    }
+
+
+    WritePasswordFile(request.user_id, password_handle);
+
+    response->SetEnrolledPasswordHandle(&password_handle);
 }
 
 void Keyguard::Verify(const VerifyRequest &request, VerifyResponse *response) {
@@ -60,104 +100,120 @@
         return;
     }
 
-    size_t salt_length, signature_length;
-    uint8_t *salt, *signature;
-    keyguard_error_t error = DeserializeHandle(
-            &request.password_handle, &salt, &salt_length, &signature, &signature_length);
+    secure_id_t user_id, authenticator_id;
+    password_handle_t *password_handle = reinterpret_cast<password_handle_t *>(
+            request.password_handle.buffer.get());
 
-    if (error != KG_ERROR_OK) {
-        response->error = error;
+    // Sanity check
+    if (password_handle->version != HANDLE_VERSION) {
+        response->error = KG_ERROR_INVALID;
         return;
     }
 
-    size_t provided_password_signature_length;
-    UniquePtr<uint8_t> provided_password_signature;
-    ComputePasswordSignature(password_key_.buffer.get(),
-            password_key_.length, request.provided_password.buffer.get(), request.provided_password.length,
-            salt, salt_length, &provided_password_signature, &provided_password_signature_length);
+    if (!ValidatePasswordFile(request.user_id, request.password_handle)) {
+        // we don't allow access to keys if we can't validate the file.
+        // we must allow this case to support authentication before we decrypt
+        // /data, however.
+        user_id = 0;
+        authenticator_id = 0;
+    } else {
+        user_id = password_handle->user_id;
+        authenticator_id = password_handle->authenticator_id;
+    }
 
-    if (provided_password_signature_length == signature_length &&
-            memcmp_s(signature, provided_password_signature.get(), signature_length) == 0) {
+    struct timespec time;
+    uint64_t timestamp;
+    clock_gettime(CLOCK_MONOTONIC_RAW, &time);
+    timestamp = static_cast<uint32_t>(time.tv_sec);
+
+    if (DoVerify(password_handle, request.provided_password)) {
         // Signature matches
         SizedBuffer auth_token;
-        MintAuthToken(request.user_id, &auth_token.buffer, &auth_token.length);
+        MintAuthToken(&auth_token.buffer, &auth_token.length, timestamp,
+                user_id, authenticator_id);
         response->SetVerificationToken(&auth_token);
     } else {
         response->error = KG_ERROR_INVALID;
     }
 }
 
-void Keyguard::MintAuthToken(uint32_t user_id, UniquePtr<uint8_t> *auth_token, size_t *length) {
+bool Keyguard::CreatePasswordHandle(SizedBuffer *password_handle_buffer, salt_t salt,
+        secure_id_t user_id, secure_id_t authenticator_id, const uint8_t *password,
+        size_t password_length) {
+    password_handle_buffer->buffer.reset(new uint8_t[sizeof(password_handle_t)]);
+    password_handle_buffer->length = sizeof(password_handle_t);
+
+    password_handle_t *password_handle = reinterpret_cast<password_handle_t *>(
+            password_handle_buffer->buffer.get());
+    password_handle->version = HANDLE_VERSION;
+    password_handle->salt = salt;
+    password_handle->user_id = user_id;
+    password_handle->authenticator_id = authenticator_id;
+
+    size_t metadata_length = sizeof(user_id) /* user id */
+        + sizeof(authenticator_id) /* auth id */ + sizeof(uint8_t) /* version */;
+    uint8_t to_sign[password_length + metadata_length];
+    memcpy(to_sign, &password_handle->version, metadata_length);
+    memcpy(to_sign + metadata_length, password, password_length);
+
+    UniquePtr<uint8_t> password_key;
+    size_t password_key_length = 0;
+    GetPasswordKey(&password_key, &password_key_length);
+
+    if (!password_key.get() || password_key_length == 0) {
+        return false;
+    }
+
+    ComputePasswordSignature(password_handle->signature, sizeof(password_handle->signature),
+            password_key.get(), password_key_length, to_sign, sizeof(to_sign), salt);
+    return true;
+}
+
+bool Keyguard::DoVerify(const password_handle_t *expected_handle, const SizedBuffer &password) {
+    if (!password.buffer.get()) return false;
+
+    SizedBuffer provided_handle;
+    if (!CreatePasswordHandle(&provided_handle, expected_handle->salt, expected_handle->user_id,
+            expected_handle->authenticator_id, password.buffer.get(), password.length)) {
+        return false;
+    }
+
+    return memcmp_s(provided_handle.buffer.get(), expected_handle, sizeof(*expected_handle)) == 0;
+}
+
+bool Keyguard::ValidatePasswordFile(uint32_t uid, const SizedBuffer &provided_handle) {
+    SizedBuffer stored_handle;
+    ReadPasswordFile(uid, &stored_handle);
+
+    if (!stored_handle.buffer.get() || stored_handle.length == 0) return false;
+
+    // do we also verify the signature here?
+    return stored_handle.length == provided_handle.length &&
+        memcmp_s(stored_handle.buffer.get(), provided_handle.buffer.get(), stored_handle.length)
+            == 0;
+}
+
+void Keyguard::MintAuthToken(UniquePtr<uint8_t> *auth_token, size_t *length,
+        uint32_t timestamp, secure_id_t user_id, secure_id_t authenticator_id) {
     if (auth_token == NULL) return;
 
     AuthToken *token = new AuthToken;
     SizedBuffer serialized_auth_token;
 
-    struct timespec time;
-    clock_gettime(CLOCK_MONOTONIC_RAW, &time);
-
-    token->auth_token_size = sizeof(AuthToken) -
-        sizeof(token->auth_token_tag) - sizeof(token->auth_token_size);
-    token->user_id = user_id;
-    token->timestamp = static_cast<uint64_t>(time.tv_sec);
+    token->root_secure_user_id = user_id;
+    token->auxiliary_secure_user_id = authenticator_id;
+    token->timestamp = timestamp;
 
     UniquePtr<uint8_t> auth_token_key;
     size_t key_len;
     GetAuthTokenKey(&auth_token_key, &key_len);
 
-    size_t hash_len = (size_t)((uint8_t *)&token->hmac_tag - (uint8_t *)token);
-    size_t signature_len;
-    UniquePtr<uint8_t> signature;
-    ComputeSignature(auth_token_key.get(), key_len,
-            reinterpret_cast<uint8_t *>(token), hash_len, &signature, &signature_len);
+    size_t hash_len = (size_t)((uint8_t *)&token->hmac - (uint8_t *)token);
+    ComputeSignature(token->hmac, sizeof(token->hmac), auth_token_key.get(), key_len,
+            reinterpret_cast<uint8_t *>(token), hash_len);
 
-    memset(&token->hmac, 0, sizeof(token->hmac));
-
-    memcpy(&token->hmac, signature.get(), signature_len > sizeof(token->hmac)
-            ? sizeof(token->hmac) : signature_len);
     if (length != NULL) *length = sizeof(AuthToken);
     auth_token->reset(reinterpret_cast<uint8_t *>(token));
 }
 
-void Keyguard::SerializeHandle(const uint8_t *salt, size_t salt_length, const uint8_t *signature,
-        size_t signature_length, SizedBuffer &result) {
-    const size_t buffer_len = 2 * sizeof(size_t) + salt_length + signature_length;
-    result.buffer.reset(new uint8_t[buffer_len]);
-    result.length = buffer_len;
-    uint8_t *buffer = result.buffer.get();
-    memcpy(buffer, &salt_length, sizeof(salt_length));
-    buffer += sizeof(salt_length);
-    memcpy(buffer, salt, salt_length);
-    buffer += salt_length;
-    memcpy(buffer, &signature_length, sizeof(signature_length));
-    buffer += sizeof(signature_length);
-    memcpy(buffer, signature, signature_length);
-}
-
-keyguard_error_t Keyguard::DeserializeHandle(const SizedBuffer *handle, uint8_t **salt,
-        size_t *salt_length, uint8_t **password, size_t *password_length) {
-    if (handle && handle->length > (2 * sizeof(size_t))) {
-        int read = 0;
-        uint8_t *buffer = handle->buffer.get();
-        memcpy(salt_length, buffer, sizeof(*salt_length));
-        read += sizeof(*salt_length);
-        if (read + *salt_length < handle->length) {
-            *salt = buffer + read;
-            read += *salt_length;
-            if (read + sizeof(*password_length) < handle->length) {
-                buffer += read;
-                memcpy(password_length, buffer, sizeof(*password_length));
-                *password = buffer + sizeof(*password_length);
-            } else {
-                return KG_ERROR_INVALID;
-            }
-        } else {
-            return KG_ERROR_INVALID;
-        }
-
-        return KG_ERROR_OK;
-    }
-    return KG_ERROR_INVALID;
-}
-
 }
diff --git a/keyguard_messages.cpp b/keyguard_messages.cpp
index d7b90a7..34c3c91 100644
--- a/keyguard_messages.cpp
+++ b/keyguard_messages.cpp
@@ -33,22 +33,26 @@
 static inline void append_to_buffer(uint8_t **buffer, const SizedBuffer *to_append) {
     memcpy(*buffer, &to_append->length, sizeof(to_append->length));
     *buffer += sizeof(to_append->length);
-    memcpy(*buffer, to_append->buffer.get(), to_append->length);
-    *buffer += to_append->length;
+    if (to_append->length != 0) {
+        memcpy(*buffer, to_append->buffer.get(), to_append->length);
+        *buffer += to_append->length;
+    }
 }
 
 static inline keyguard_error_t read_from_buffer(const uint8_t **buffer, const uint8_t *end,
         SizedBuffer *target) {
-    if (*buffer + sizeof(target->length) >= end) return KG_ERROR_INVALID;
+    if (*buffer + sizeof(target->length) > end) return KG_ERROR_INVALID;
 
     memcpy(&target->length, *buffer, sizeof(target->length));
     *buffer += sizeof(target->length);
-    const uint8_t *buffer_end = *buffer + target->length;
-    if (buffer_end > end || buffer_end <= *buffer) return KG_ERROR_INVALID;
+    if (target->length != 0) {
+        const uint8_t *buffer_end = *buffer + target->length;
+        if (buffer_end > end || buffer_end <= *buffer) return KG_ERROR_INVALID;
 
-    target->buffer.reset(new uint8_t[target->length]);
-    memcpy(target->buffer.get(), *buffer, target->length);
-    *buffer += target->length;
+        target->buffer.reset(new uint8_t[target->length]);
+        memcpy(target->buffer.get(), *buffer, target->length);
+        *buffer += target->length;
+    }
     return KG_ERROR_OK;
 }
 
@@ -145,51 +149,70 @@
 
 }
 
-VerifyResponse::VerifyResponse(uint32_t user_id, SizedBuffer *verification_token) {
+VerifyResponse::VerifyResponse(uint32_t user_id, SizedBuffer *auth_token) {
     this->user_id = user_id;
-    this->verification_token.buffer.reset(verification_token->buffer.release());
-    this->verification_token.length = verification_token->length;
+    this->auth_token.buffer.reset(auth_token->buffer.release());
+    this->auth_token.length = auth_token->length;
 }
 
 VerifyResponse::VerifyResponse() {
-    memset_s(&verification_token, 0, sizeof(verification_token));
+    memset_s(&auth_token, 0, sizeof(auth_token));
 };
 
 VerifyResponse::~VerifyResponse() {
-    if (verification_token.length > 0) {
-        verification_token.buffer.reset();
+    if (auth_token.length > 0) {
+        auth_token.buffer.reset();
     }
 }
 
-void VerifyResponse::SetVerificationToken(SizedBuffer *verification_token) {
-    this->verification_token.buffer.reset(verification_token->buffer.release());
-    this->verification_token.length = verification_token->length;
+void VerifyResponse::SetVerificationToken(SizedBuffer *auth_token) {
+    this->auth_token.buffer.reset(auth_token->buffer.release());
+    this->auth_token.length = auth_token->length;
 }
 
 size_t VerifyResponse::nonErrorSerializedSize() const {
-    return serialized_buffer_size(verification_token);
+    return serialized_buffer_size(auth_token);
 }
 
 void VerifyResponse::nonErrorSerialize(uint8_t *buffer) const {
-    append_to_buffer(&buffer, &verification_token);
+    append_to_buffer(&buffer, &auth_token);
 }
 
 keyguard_error_t VerifyResponse::nonErrorDeserialize(const uint8_t *payload, const uint8_t *end) {
-    if (verification_token.buffer.get()) {
-        verification_token.buffer.reset();
+    if (auth_token.buffer.get()) {
+        auth_token.buffer.reset();
     }
 
-    return read_from_buffer(&payload, end, &verification_token);
+    return read_from_buffer(&payload, end, &auth_token);
 }
 
-EnrollRequest::EnrollRequest(uint32_t user_id, SizedBuffer *provided_password) {
+EnrollRequest::EnrollRequest(uint32_t user_id, SizedBuffer *password_handle,
+        SizedBuffer *provided_password,  SizedBuffer *enrolled_password) {
     this->user_id = user_id;
     this->provided_password.buffer.reset(provided_password->buffer.release());
     this->provided_password.length = provided_password->length;
+
+    if (enrolled_password == NULL) {
+        this->enrolled_password.buffer.reset();
+        this->enrolled_password.length = 0;
+    } else {
+        this->enrolled_password.buffer.reset(enrolled_password->buffer.release());
+        this->enrolled_password.length = enrolled_password->length;
+    }
+
+    if (password_handle == NULL) {
+        this->password_handle.buffer.reset();
+        this->password_handle.length = 0;
+    } else {
+        this->password_handle.buffer.reset(password_handle->buffer.release());
+        this->password_handle.length = password_handle->length;
+    }
 }
 
 EnrollRequest::EnrollRequest() {
     memset_s(&provided_password, 0, sizeof(provided_password));
+    memset_s(&enrolled_password, 0, sizeof(enrolled_password));
+    memset_s(&password_handle, 0, sizeof(password_handle));
 }
 
 EnrollRequest::~EnrollRequest() {
@@ -197,23 +220,57 @@
         memset_s(provided_password.buffer.get(), 0, provided_password.length);
         provided_password.buffer.reset();
     }
+
+    if (enrolled_password.buffer.get()) {
+        memset_s(enrolled_password.buffer.get(), 0, enrolled_password.length);
+        enrolled_password.buffer.reset();
+    }
+
+    if (password_handle.buffer.get()) {
+        memset_s(password_handle.buffer.get(), 0, password_handle.length);
+        password_handle.buffer.reset();
+    }
 }
 
 size_t EnrollRequest::nonErrorSerializedSize() const {
-   return serialized_buffer_size(provided_password);
+   return serialized_buffer_size(provided_password) + serialized_buffer_size(enrolled_password)
+       + serialized_buffer_size(password_handle);
 }
 
 void EnrollRequest::nonErrorSerialize(uint8_t *buffer) const {
     append_to_buffer(&buffer, &provided_password);
+    append_to_buffer(&buffer, &enrolled_password);
+    append_to_buffer(&buffer, &password_handle);
 }
 
 keyguard_error_t EnrollRequest::nonErrorDeserialize(const uint8_t *payload, const uint8_t *end) {
+    keyguard_error_t ret;
     if (provided_password.buffer.get()) {
         memset_s(provided_password.buffer.get(), 0, provided_password.length);
         provided_password.buffer.reset();
     }
 
-    return read_from_buffer(&payload, end, &provided_password);
+    if (enrolled_password.buffer.get()) {
+        memset_s(enrolled_password.buffer.get(), 0, enrolled_password.length);
+        enrolled_password.buffer.reset();
+    }
+
+    if (password_handle.buffer.get()) {
+        memset_s(password_handle.buffer.get(), 0, password_handle.length);
+        password_handle.buffer.reset();
+    }
+
+     ret = read_from_buffer(&payload, end, &provided_password);
+     if (ret != KG_ERROR_OK) {
+         return ret;
+     }
+
+     ret = read_from_buffer(&payload, end, &enrolled_password);
+     if (ret != KG_ERROR_OK) {
+         return ret;
+     }
+
+     return read_from_buffer(&payload, end, &password_handle);
 }
 
 EnrollResponse::EnrollResponse(uint32_t user_id, SizedBuffer *enrolled_password_handle) {
diff --git a/softkeyguard/module.cpp b/softkeyguard/module.cpp
index b41ee9d..07f1ec0 100644
--- a/softkeyguard/module.cpp
+++ b/softkeyguard/module.cpp
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include<keyguard/soft_keyguard_device.h>
+#include "soft_keyguard_device.h"
 
 extern struct keyguard_module soft_keyguard_device_module;
 
diff --git a/softkeyguard/native_keyguard_file_io.h b/softkeyguard/native_keyguard_file_io.h
new file mode 100644
index 0000000..61a75de
--- /dev/null
+++ b/softkeyguard/native_keyguard_file_io.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef KEYGUARD_FILE_IO_
+#define KEYGUARD_FILE_IO_
+
+#include <keyguard/soft_keyguard.h>
+
+namespace keyguard {
+
+class NativeKeyguardFileIo : public ::keyguard::KeyguardFileIo {
+public:
+    virtual void Write(const char *filename, const uint8_t *bytes, size_t length) {
+        // TODO
+    }
+
+    virtual size_t Read(const char *filename, UniquePtr<uint8_t> *bytes) const {
+        // TODO
+        return 0;
+    }
+private:
+};
+}
+
+#endif // KEYGUARD_FILE_IO_
diff --git a/softkeyguard/soft_keyguard_device.cpp b/softkeyguard/soft_keyguard_device.cpp
index 6422531..8781b74 100644
--- a/softkeyguard/soft_keyguard_device.cpp
+++ b/softkeyguard/soft_keyguard_device.cpp
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-#include <keyguard/soft_keyguard_device.h>
+#include "soft_keyguard_device.h"
+#include "native_keyguard_file_io.h"
 
 __attribute__((visibility("default")))
 int softkeyguard_device_open(const hw_module_t *module, const char *name, hw_device_t **device) {
@@ -53,7 +54,7 @@
 namespace keyguard {
 
 SoftKeyguardDevice::SoftKeyguardDevice(const hw_module_t *module)
-    : impl_(new SoftKeyguard()) {
+    : impl_(new SoftKeyguard(new NativeKeyguardFileIo())) {
 #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
     static_assert(std::is_standard_layout<SoftKeyguardDevice>::value,
                   "SoftKeyguardDevice must be standard layout");
@@ -72,8 +73,8 @@
     device_.common.module = const_cast<hw_module_t *>(module);
     device_.common.close = close_device;
 
-    device_.verify = verify;
-    device_.enroll = enroll;
+    device_.verify = Verify;
+    device_.enroll = Enroll;
 }
 
 hw_device_t *SoftKeyguardDevice::hw_device() {
@@ -90,19 +91,42 @@
     return 0;
 }
 
-int SoftKeyguardDevice::enroll(const struct keyguard_device *dev, uint32_t uid,
-        const uint8_t *password_payload, size_t password_payload_length,
-        uint8_t **enrolled_password_handle, size_t *enrolled_password_handle_length) {
+int SoftKeyguardDevice::Enroll(const struct keyguard_device *dev, uint32_t uid,
+            const uint8_t *current_password_handle, size_t current_password_handle_length,
+            const uint8_t *current_password, size_t current_password_length,
+            const uint8_t *desired_password, size_t desired_password_length,
+            uint8_t **enrolled_password_handle, size_t *enrolled_password_handle_length) {
 
     if (dev == NULL ||
-            enrolled_password_handle == NULL || enrolled_password_handle_length == NULL)
+            enrolled_password_handle == NULL || enrolled_password_handle_length == NULL ||
+            desired_password == NULL || desired_password_length == 0)
         return -EINVAL;
 
-    uint8_t *local_password_payload = new uint8_t[password_payload_length];
-    memcpy(local_password_payload, password_payload, password_payload_length);
+    // Current password and current password handle go together
+    if (current_password_handle == NULL || current_password_handle_length == 0 ||
+            current_password == NULL || current_password_length == 0) {
+        current_password_handle = NULL;
+        current_password_handle_length = 0;
+        current_password = NULL;
+        current_password_length = 0;
+    }
 
-    SizedBuffer provided_password(local_password_payload, password_payload_length);
-    EnrollRequest request(uid, &provided_password);
+    SizedBuffer desired_password_buffer(desired_password_length);
+    memcpy(desired_password_buffer.buffer.get(), desired_password, desired_password_length);
+
+    SizedBuffer current_password_handle_buffer(current_password_handle_length);
+    if (current_password_handle) {
+        memcpy(current_password_handle_buffer.buffer.get(), current_password_handle,
+                current_password_handle_length);
+    }
+
+    SizedBuffer current_password_buffer(current_password_length);
+    if (current_password) {
+        memcpy(current_password_buffer.buffer.get(), current_password, current_password_length);
+    }
+
+    EnrollRequest request(uid, &current_password_handle_buffer, &desired_password_buffer,
+            &current_password_buffer);
     EnrollResponse response;
 
     convert_device(dev)->impl_->Enroll(request, &response);
@@ -115,25 +139,22 @@
     return 0;
 }
 
-int SoftKeyguardDevice::verify(const struct keyguard_device *dev, uint32_t uid,
+int SoftKeyguardDevice::Verify(const struct keyguard_device *dev, uint32_t uid,
         const uint8_t *enrolled_password_handle, size_t enrolled_password_handle_length,
         const uint8_t *provided_password, size_t provided_password_length,
-        uint8_t **verification_token, size_t *verification_token_length) {
+        uint8_t **auth_token, size_t *auth_token_length) {
 
     if (dev == NULL || enrolled_password_handle == NULL ||
             provided_password == NULL) {
         return -EINVAL;
     }
 
-    uint8_t *local_provided_password = new uint8_t[provided_password_length];
-    uint8_t *local_enrolled_password = new uint8_t[enrolled_password_handle_length];
-    memcpy(local_provided_password, provided_password, provided_password_length);
-    memcpy(local_enrolled_password, enrolled_password_handle, enrolled_password_handle_length);
+    SizedBuffer password_handle_buffer(enrolled_password_handle_length);
+    memcpy(password_handle_buffer.buffer.get(), enrolled_password_handle, enrolled_password_handle_length);
+    SizedBuffer provided_password_buffer(provided_password_length);
+    memcpy(provided_password_buffer.buffer.get(), provided_password, provided_password_length);
 
-    SizedBuffer password_handle(local_enrolled_password,
-            enrolled_password_handle_length);
-    SizedBuffer provided(local_provided_password, provided_password_length);
-    VerifyRequest request(uid, &password_handle, &provided);
+    VerifyRequest request(uid, &password_handle_buffer, &provided_password_buffer);
     VerifyResponse response;
 
     convert_device(dev)->impl_->Verify(request, &response);
@@ -141,9 +162,9 @@
     if (response.error != KG_ERROR_OK)
        return -EINVAL;
 
-    if (verification_token != NULL && verification_token_length != NULL) {
-       *verification_token = response.verification_token.buffer.release();
-       *verification_token_length = response.verification_token.length;
+    if (auth_token != NULL && auth_token_length != NULL) {
+       *auth_token = response.auth_token.buffer.release();
+       *auth_token_length = response.auth_token.length;
     }
 
     return 0;
diff --git a/include/keyguard/soft_keyguard_device.h b/softkeyguard/soft_keyguard_device.h
similarity index 85%
rename from include/keyguard/soft_keyguard_device.h
rename to softkeyguard/soft_keyguard_device.h
index 6da20de..23bc944 100644
--- a/include/keyguard/soft_keyguard_device.h
+++ b/softkeyguard/soft_keyguard_device.h
@@ -50,27 +50,28 @@
      * Returns: 0 on success or an error code less than 0 on error.
      * On error, enrolled_password_handle will not be allocated.
      */
-    static int enroll(const struct keyguard_device *dev, uint32_t uid,
-            const uint8_t *password_payload, size_t password_payload_length,
+    static int Enroll(const struct keyguard_device *dev, uint32_t uid,
+            const uint8_t *current_password_handle, size_t current_password_handle_length,
+            const uint8_t *current_password, size_t current_password_length,
+            const uint8_t *desired_password, size_t desired_password_length,
             uint8_t **enrolled_password_handle, size_t *enrolled_password_handle_length);
-
     /**
      * Verifies provided_password matches enrolled_password_handle.
      *
      * Implementations of this module may retain the result of this call
      * to attest to the recency of authentication.
      *
-     * On success, writes the address of a verification token to verification_token,
+     * On success, writes the address of a verification token to auth_token,
      * usable to attest password verification to other trusted services. Clients
      * may pass NULL for this value.
      *
      * Returns: 0 on success or an error code less than 0 on error
      * On error, verification token will not be allocated
      */
-    static int verify(const struct keyguard_device *dev, uint32_t uid,
+    static int Verify(const struct keyguard_device *dev, uint32_t uid,
             const uint8_t *enrolled_password_handle, size_t enrolled_password_handle_length,
             const uint8_t *provided_password, size_t provided_password_length,
-            uint8_t **verification_token, size_t *verification_token_length);
+            uint8_t **auth_token, size_t *auth_token_length);
 
     keyguard_device device_;
     UniquePtr<Keyguard> impl_;
diff --git a/tests/keyguard_device_test.cpp b/tests/keyguard_device_test.cpp
index 0bc7db9..b3f3b21 100644
--- a/tests/keyguard_device_test.cpp
+++ b/tests/keyguard_device_test.cpp
@@ -55,7 +55,7 @@
     size_t auth_token_len;
     int ret;
 
-    ret = device->enroll(device, 0, password_payload, password_len,
+    ret = device->enroll(device, 0, NULL, 0, NULL, 0,  password_payload, password_len,
             &password_handle, &password_handle_length);
 
     ASSERT_EQ(0, ret);
@@ -75,8 +75,8 @@
     size_t auth_token_len;
     int ret;
 
-    ret = device->enroll(device, 0, password_payload, password_len,
-            &password_handle, &password_handle_length);
+    ret = device->enroll(device, 0, NULL, 0, NULL, 0,  password_payload, password_len,
+             &password_handle, &password_handle_length);
 
     ASSERT_EQ(0, ret);
 
diff --git a/tests/keyguard_messages_test.cpp b/tests/keyguard_messages_test.cpp
index 10f81bd..fd70c07 100644
--- a/tests/keyguard_messages_test.cpp
+++ b/tests/keyguard_messages_test.cpp
@@ -46,12 +46,12 @@
     return result;
 }
 
-TEST(RoundTripTest, EnrollRequest) {
+TEST(RoundTripTest, EnrollRequestNullEnrolledNullHandle) {
     const size_t password_size = 512;
     SizedBuffer *provided_password = make_buffer(password_size);
     const SizedBuffer *deserialized_password;
     // create request, serialize, deserialize, and validate
-    EnrollRequest req(USER_ID, provided_password);
+    EnrollRequest req(USER_ID, NULL, provided_password, NULL);
     uint8_t *serialized_req = req.Serialize();
     EnrollRequest deserialized_req;
     deserialized_req.Deserialize(serialized_req, serialized_req + req.GetSerializedSize());
@@ -64,9 +64,74 @@
     ASSERT_EQ(USER_ID, deserialized_req.user_id);
     ASSERT_EQ((uint32_t) password_size, deserialized_password->length);
     ASSERT_EQ(0, memcmp(req.provided_password.buffer.get(), deserialized_password->buffer.get(), password_size));
+    ASSERT_EQ((size_t) 0, deserialized_req.enrolled_password.length);
+    ASSERT_EQ(NULL, deserialized_req.enrolled_password.buffer.get());
+    ASSERT_EQ((size_t) 0, deserialized_req.password_handle.length);
+    ASSERT_EQ(NULL, deserialized_req.password_handle.buffer.get());
     delete provided_password;
 }
 
+TEST(RoundTripTest, EnrollRequestEmptyEnrolledEmptyHandle) {
+    const size_t password_size = 512;
+    SizedBuffer *provided_password = make_buffer(password_size);
+    SizedBuffer enrolled;
+    SizedBuffer handle;
+    const SizedBuffer *deserialized_password;
+    // create request, serialize, deserialize, and validate
+    EnrollRequest req(USER_ID, &handle, provided_password, &enrolled);
+    uint8_t *serialized_req = req.Serialize();
+    EnrollRequest deserialized_req;
+    deserialized_req.Deserialize(serialized_req, serialized_req + req.GetSerializedSize());
+    delete[] serialized_req;
+
+    ASSERT_EQ(keyguard::keyguard_error_t::KG_ERROR_OK,
+            deserialized_req.error);
+
+    deserialized_password = &deserialized_req.provided_password;
+    ASSERT_EQ(USER_ID, deserialized_req.user_id);
+    ASSERT_EQ((uint32_t) password_size, deserialized_password->length);
+    ASSERT_EQ(0, memcmp(req.provided_password.buffer.get(), deserialized_password->buffer.get(), password_size));
+    ASSERT_EQ((size_t) 0, deserialized_req.enrolled_password.length);
+    ASSERT_EQ(NULL, deserialized_req.enrolled_password.buffer.get());
+    ASSERT_EQ((size_t) 0, deserialized_req.password_handle.length);
+    ASSERT_EQ(NULL, deserialized_req.password_handle.buffer.get());
+    delete provided_password;
+}
+
+TEST(RoundTripTest, EnrollRequestNonNullEnrolledOrHandle) {
+    const size_t password_size = 512;
+    SizedBuffer *provided_password = make_buffer(password_size);
+    SizedBuffer *enrolled_password = make_buffer(password_size);
+    SizedBuffer *password_handle = make_buffer(password_size);
+    const SizedBuffer *deserialized_password;
+    const SizedBuffer *deserialized_enrolled;
+    const SizedBuffer *deserialized_handle;
+    // create request, serialize, deserialize, and validate
+    EnrollRequest req(USER_ID, password_handle, provided_password, enrolled_password);
+    uint8_t *serialized_req = req.Serialize();
+    EnrollRequest deserialized_req;
+    deserialized_req.Deserialize(serialized_req, serialized_req + req.GetSerializedSize());
+    delete[] serialized_req;
+
+    ASSERT_EQ(keyguard::keyguard_error_t::KG_ERROR_OK,
+            deserialized_req.error);
+
+    deserialized_password = &deserialized_req.provided_password;
+    deserialized_enrolled = &deserialized_req.enrolled_password;
+    deserialized_handle = &deserialized_req.password_handle;
+    ASSERT_EQ(USER_ID, deserialized_req.user_id);
+    ASSERT_EQ((uint32_t) password_size, deserialized_password->length);
+    ASSERT_EQ(0, memcmp(req.provided_password.buffer.get(), deserialized_password->buffer.get(), password_size));
+    ASSERT_EQ((uint32_t) password_size, deserialized_enrolled->length);
+    ASSERT_EQ(0, memcmp(req.enrolled_password.buffer.get(), deserialized_enrolled->buffer.get(), password_size));
+    ASSERT_EQ((uint32_t) password_size, deserialized_handle->length);
+    ASSERT_EQ(0, memcmp(req.password_handle.buffer.get(), deserialized_handle->buffer.get(), password_size));
+    delete provided_password;
+    delete enrolled_password;
+    delete password_handle;
+}
+
+
 TEST(RoundTripTest, EnrollResponse) {
     const size_t password_size = 512;
     SizedBuffer *enrolled_password = make_buffer(password_size);
@@ -116,10 +181,10 @@
 
 TEST(RoundTripTest, VerifyResponse) {
     const size_t password_size = 512;
-    SizedBuffer *verification_token = make_buffer(password_size);
+    SizedBuffer *auth_token = make_buffer(password_size);
     const SizedBuffer *deserialized_password;
     // create request, serialize, deserialize, and validate
-    VerifyResponse req(USER_ID, verification_token);
+    VerifyResponse req(USER_ID, auth_token);
     uint8_t *serialized_req = req.Serialize();
     VerifyResponse deserialized_req;
     deserialized_req.Deserialize(serialized_req, serialized_req + req.GetSerializedSize());
@@ -129,9 +194,9 @@
             deserialized_req.error);
 
     ASSERT_EQ(USER_ID, deserialized_req.user_id);
-    deserialized_password = &deserialized_req.verification_token;
+    deserialized_password = &deserialized_req.auth_token;
     ASSERT_EQ((uint32_t) password_size, deserialized_password->length);
-    ASSERT_EQ(0, memcmp(req.verification_token.buffer.get(), deserialized_password->buffer.get(),
+    ASSERT_EQ(0, memcmp(req.auth_token.buffer.get(), deserialized_password->buffer.get(),
                 password_size));
 }
 
diff --git a/tests/keyguard_test.cpp b/tests/keyguard_test.cpp
index 4ee09ba..02a6c34 100644
--- a/tests/keyguard_test.cpp
+++ b/tests/keyguard_test.cpp
@@ -16,6 +16,7 @@
 
 #include <gtest/gtest.h>
 #include <UniquePtr.h>
+#include <iostream>
 
 #include <keyguard/soft_keyguard.h>
 
@@ -27,6 +28,33 @@
 using ::keyguard::VerifyResponse;
 using ::keyguard::SoftKeyguard;
 using ::keyguard::AuthToken;
+using ::keyguard::secure_id_t;
+
+class TestKeyguardFileIo : public ::keyguard::KeyguardFileIo {
+public:
+    TestKeyguardFileIo() {
+        bytes_.length = 0;
+    }
+
+    virtual void Write(const char *filename, const uint8_t *bytes, size_t length) {
+        bytes_.buffer.reset(new uint8_t[length]);
+        memcpy(bytes_.buffer.get(), bytes, length);
+        bytes_.length = length;
+    }
+
+    virtual size_t Read(const char *filename, UniquePtr<uint8_t> *bytes) const {
+        if (!bytes_.buffer.get() || bytes_.length == 0) {
+            bytes->reset();
+        } else {
+            bytes->reset(new uint8_t[bytes_.length]);
+            memcpy(bytes->get(), bytes_.buffer.get(), bytes_.length);
+        }
+
+        return bytes_.length;
+    }
+
+    SizedBuffer bytes_;
+};
 
 static void do_enroll(SoftKeyguard &keyguard, EnrollResponse *response) {
     SizedBuffer password;
@@ -34,24 +62,24 @@
     password.buffer.reset(new uint8_t[16]);
     password.length = 16;
     memset(password.buffer.get(), 0, 16);
-    EnrollRequest request(0, &password);
+    EnrollRequest request(0, NULL, &password, NULL);
 
     keyguard.Enroll(request, response);
 }
 
 TEST(KeyguardTest, EnrollSuccess) {
-    SoftKeyguard keyguard;
+    SoftKeyguard keyguard(new TestKeyguardFileIo());
     EnrollResponse response;
     do_enroll(keyguard, &response);
     ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, response.error);
 }
 
 TEST(KeyguardTest, EnrollBogusData) {
-    SoftKeyguard keyguard;
+    SoftKeyguard keyguard(new TestKeyguardFileIo());
     SizedBuffer password;
     EnrollResponse response;
 
-    EnrollRequest request(0, &password);
+    EnrollRequest request(0, NULL, &password, NULL);
 
     keyguard.Enroll(request, &response);
 
@@ -59,7 +87,7 @@
 }
 
 TEST(KeyguardTest, VerifySuccess) {
-    SoftKeyguard keyguard;
+    SoftKeyguard keyguard(new TestKeyguardFileIo());
     SizedBuffer provided_password;
     EnrollResponse enroll_response;
 
@@ -78,19 +106,144 @@
     ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, response.error);
 
     AuthToken *auth_token =
-        reinterpret_cast<AuthToken *>(response.verification_token.buffer.get());
+        reinterpret_cast<AuthToken *>(response.auth_token.buffer.get());
 
-    ASSERT_EQ((uint8_t) 1, auth_token->auth_token_tag);
-    ASSERT_EQ((uint8_t) 2, auth_token->user_id_tag);
-    ASSERT_EQ((uint8_t) 3, auth_token->authenticator_id_tag);
-    ASSERT_EQ((uint8_t) 4, auth_token->timestamp_tag);
-
-    ASSERT_EQ((uint32_t)0, auth_token->user_id);
-    ASSERT_EQ((uint32_t)0, auth_token->authenticator_id);
+    ASSERT_EQ((uint32_t) 0, auth_token->authenticator_id);
+    ASSERT_NE(~((uint32_t) 0), auth_token->timestamp);
+    ASSERT_NE((uint64_t) 0, auth_token->root_secure_user_id);
+    ASSERT_NE((uint64_t) 0, auth_token->auxiliary_secure_user_id);
 }
 
+TEST(KeyguardTest, VerifyBadPwFile) {
+    TestKeyguardFileIo *fw = new TestKeyguardFileIo();
+    SoftKeyguard keyguard(fw);
+    SizedBuffer provided_password;
+    EnrollResponse enroll_response;
+
+    provided_password.buffer.reset(new uint8_t[16]);
+    provided_password.length = 16;
+    memset(provided_password.buffer.get(), 0, 16);
+    do_enroll(keyguard, &enroll_response);
+    ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, enroll_response.error);
+
+    VerifyRequest request(0, &enroll_response.enrolled_password_handle,
+            &provided_password);
+    VerifyResponse response;
+    fw->bytes_.buffer.reset();
+    keyguard.Verify(request, &response);
+    ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, response.error);
+
+    AuthToken *auth_token =
+        reinterpret_cast<AuthToken *>(response.auth_token.buffer.get());
+
+    ASSERT_EQ((uint32_t) 0, auth_token->authenticator_id);
+    ASSERT_NE(~((uint32_t) 0), auth_token->timestamp);
+    ASSERT_EQ((uint64_t) 0, auth_token->root_secure_user_id);
+    ASSERT_EQ((uint64_t) 0, auth_token->auxiliary_secure_user_id);
+}
+
+TEST(KeyguardTest, TrustedReEnroll) {
+    SoftKeyguard keyguard(new TestKeyguardFileIo());
+    SizedBuffer provided_password;
+    EnrollResponse enroll_response;
+    SizedBuffer password_handle;
+
+    // do_enroll enrolls an all 0 password
+    provided_password.buffer.reset(new uint8_t[16]);
+    provided_password.length = 16;
+    memset(provided_password.buffer.get(), 0, 16);
+    do_enroll(keyguard, &enroll_response);
+    ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, enroll_response.error);
+
+    // keep a copy of the handle
+    password_handle.buffer.reset(new uint8_t[enroll_response.enrolled_password_handle.length]);
+    password_handle.length = enroll_response.enrolled_password_handle.length;
+    memcpy(password_handle.buffer.get(), enroll_response.enrolled_password_handle.buffer.get(),
+            password_handle.length);
+
+    // verify first password
+    VerifyRequest request(0, &enroll_response.enrolled_password_handle,
+            &provided_password);
+    VerifyResponse response;
+    keyguard.Verify(request, &response);
+    ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, response.error);
+    AuthToken *auth_token =
+        reinterpret_cast<AuthToken *>(response.auth_token.buffer.get());
+
+    secure_id_t secure_id = auth_token->root_secure_user_id;
+
+    // enroll new password
+    provided_password.buffer.reset(new uint8_t[16]);
+    provided_password.length = 16;
+    memset(provided_password.buffer.get(), 0, 16);
+    SizedBuffer password;
+    password.buffer.reset(new uint8_t[16]);
+    memset(password.buffer.get(), 1, 16);
+    password.length = 16;
+    EnrollRequest enroll_request(0, &password_handle, &password, &provided_password);
+    keyguard.Enroll(enroll_request, &enroll_response);
+    ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, enroll_response.error);
+
+    // verify new password
+    password.buffer.reset(new uint8_t[16]);
+    memset(password.buffer.get(), 1, 16);
+    password.length = 16;
+    VerifyRequest new_request(0, &enroll_response.enrolled_password_handle,
+            &password);
+    keyguard.Verify(new_request, &response);
+    ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, response.error);
+    ASSERT_EQ(secure_id,
+        reinterpret_cast<AuthToken *>(response.auth_token.buffer.get())->root_secure_user_id);
+}
+
+
+TEST(KeyguardTest, UntrustedReEnroll) {
+    SoftKeyguard keyguard(new TestKeyguardFileIo());
+    SizedBuffer provided_password;
+    EnrollResponse enroll_response;
+
+    // do_enroll enrolls an all 0 password
+    provided_password.buffer.reset(new uint8_t[16]);
+    provided_password.length = 16;
+    memset(provided_password.buffer.get(), 0, 16);
+    do_enroll(keyguard, &enroll_response);
+    ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, enroll_response.error);
+
+    // verify first password
+    VerifyRequest request(0, &enroll_response.enrolled_password_handle,
+            &provided_password);
+    VerifyResponse response;
+    keyguard.Verify(request, &response);
+    ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, response.error);
+    AuthToken *auth_token =
+        reinterpret_cast<AuthToken *>(response.auth_token.buffer.get());
+
+    secure_id_t secure_id = auth_token->root_secure_user_id;
+
+    // enroll new password
+    SizedBuffer password;
+    password.buffer.reset(new uint8_t[16]);
+    memset(password.buffer.get(), 1, 16);
+    password.length = 16;
+    EnrollRequest enroll_request(0, NULL, &password, NULL);
+    keyguard.Enroll(enroll_request, &enroll_response);
+    ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, enroll_response.error);
+
+    // verify new password
+    password.buffer.reset(new uint8_t[16]);
+    memset(password.buffer.get(), 1, 16);
+    password.length = 16;
+    VerifyRequest new_request(0, &enroll_response.enrolled_password_handle,
+            &password);
+    keyguard.Verify(new_request, &response);
+    ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, response.error);
+    ASSERT_NE(secure_id,
+        reinterpret_cast<AuthToken *>(response.auth_token.buffer.get())->root_secure_user_id);
+}
+
+
 TEST(KeyguardTest, VerifyBogusData) {
-    SoftKeyguard keyguard;
+    SoftKeyguard keyguard(new TestKeyguardFileIo());
     SizedBuffer provided_password;
     SizedBuffer password_handle;
     VerifyResponse response;