Implement SoftKeyguard

scrypt/openssl based implementation of Keyguard

Change-Id: Ib04fee3bb34d81bfdb659ab1a9f16efd0cbd630f
diff --git a/keyguard.cpp b/keyguard.cpp
index 95cfc73..e435a3f 100644
--- a/keyguard.cpp
+++ b/keyguard.cpp
@@ -13,80 +13,151 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <sys/time.h>
+#include <time.h>
+#include <iostream>
+#include <iomanip>
+#include <UniquePtr.h>
 
-#include <keyguard/google_keyguard.h>
+#include <keyguard/keyguard.h>
 
 namespace keyguard {
 
-GoogleKeyguard::~GoogleKeyguard() {
-    if (password_key_) {
-        memset_s(password_key_.get(), 0, sizeof(password_key_.get()) / sizeof(password_key_[0]));
+Keyguard::~Keyguard() {
+    if (password_key_.buffer.get()) {
+        memset_s(password_key_.buffer.get(), 0, password_key_.length);
     }
 }
 
-void GoogleKeyguard::Enroll(const EnrollRequest &request, EnrollResponse *response) {
+void Keyguard::Enroll(const EnrollRequest &request, EnrollResponse *response) {
     if (response == NULL) return;
 
     SizedBuffer enrolled_password;
-    const SizedBuffer *provided_password = request.GetProvidedPassword();
-    if (provided_password == NULL || !provided_password->buffer) {
-        response->SetError(KG_ERROR_INVALID);
+    if (!request.provided_password.buffer.get()) {
+        response->error = KG_ERROR_INVALID;
         return;
     }
-    enrolled_password.buffer = ComputeSignature(password_key_.get(),
-            provided_password->buffer.get(), provided_password->length, &enrolled_password.length);
+
+    size_t salt_length;
+    UniquePtr<uint8_t> salt;
+    GetSalt(&salt, &salt_length);
+
+    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);
+
+    SerializeHandle(salt.get(), salt_length, signature.get(), signature_length, enrolled_password);
     response->SetEnrolledPasswordHandle(&enrolled_password);
 }
 
-void GoogleKeyguard::Verify(const VerifyRequest &request, VerifyResponse *response) {
+void Keyguard::Verify(const VerifyRequest &request, VerifyResponse *response) {
     if (response == NULL) return;
 
-    const SizedBuffer *enrolled_password = request.GetPasswordHandle();
-    const SizedBuffer *provided_password = request.GetProvidedPassword();
-
-
-    if (provided_password == NULL || !provided_password->buffer
-            || enrolled_password == NULL || !enrolled_password->buffer) {
-        response->SetError(KG_ERROR_INVALID);
+    if (!request.provided_password.buffer.get() || !request.password_handle.buffer.get()) {
+        response->error = KG_ERROR_INVALID;
         return;
     }
 
-    SizedBuffer signed_provided_password;
-    signed_provided_password.buffer = ComputeSignature(password_key_.get(),
-            provided_password->buffer.get(), provided_password->length,
-            &signed_provided_password.length);
-    if (memcmp_s(enrolled_password->buffer.get(), signed_provided_password.buffer.get(),
-                enrolled_password->length) == 0) {
+    size_t salt_length, signature_length;
+    uint8_t *salt, *signature;
+    keyguard_error_t error = DeserializeHandle(
+            &request.password_handle, &salt, &salt_length, &signature, &signature_length);
+
+    if (error != KG_ERROR_OK) {
+        response->error = error;
+        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 (provided_password_signature_length == signature_length &&
+            memcmp_s(signature, provided_password_signature.get(), signature_length) == 0) {
         // Signature matches
         SizedBuffer auth_token;
-        auth_token.buffer = MintAuthToken(request.GetUserId(), &auth_token.length);
+        MintAuthToken(request.user_id, &auth_token.buffer, &auth_token.length);
         response->SetVerificationToken(&auth_token);
     } else {
-        response->SetError(KG_ERROR_INVALID);
+        response->error = KG_ERROR_INVALID;
     }
 }
 
-std::unique_ptr<uint8_t> GoogleKeyguard::MintAuthToken(uint32_t user_id, size_t *length) {
-    AuthToken *auth_token = new AuthToken;
+void Keyguard::MintAuthToken(uint32_t user_id, UniquePtr<uint8_t> *auth_token, size_t *length) {
+    if (auth_token == NULL) return;
+
+    AuthToken *token = new AuthToken;
     SizedBuffer serialized_auth_token;
 
-    struct timeval time;
-    gettimeofday(&time, NULL);
+    struct timespec time;
+    clock_gettime(CLOCK_MONOTONIC_RAW, &time);
 
-    auth_token->auth_token_size = sizeof(AuthToken) -
-        sizeof(auth_token->auth_token_tag) - sizeof(auth_token->auth_token_size);
-    auth_token->user_id = user_id;
-    auth_token->timestamp = static_cast<uint64_t>(time.tv_sec);
+    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);
 
-    size_t hash_len = (size_t)((uint8_t *)&auth_token->hmac_tag - (uint8_t *)auth_token);
+    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;
-    std::unique_ptr<uint8_t> signature = ComputeSignature(GetAuthTokenKey().get(),
-            reinterpret_cast<uint8_t *>(auth_token), hash_len, &signature_len);
+    UniquePtr<uint8_t> signature;
+    ComputeSignature(auth_token_key.get(), key_len,
+            reinterpret_cast<uint8_t *>(token), hash_len, &signature, &signature_len);
 
-    memcpy(&auth_token->hmac, signature.get(), sizeof(auth_token->hmac));
+    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);
-    std::unique_ptr<uint8_t> result(reinterpret_cast<uint8_t *>(auth_token));
-    return result;
+    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;
+}
+
 }