implement Keyguard base class

Base class for all hardware KG implementations.
Platform-specific subclasses need only provide keys
and a signature routine.

Change-Id: I354b136a7ee1c5352ac611d8b9093fd5f2ff47ac
diff --git a/keyguard.cpp b/keyguard.cpp
new file mode 100644
index 0000000..95cfc73
--- /dev/null
+++ b/keyguard.cpp
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+#include <sys/time.h>
+
+#include <keyguard/google_keyguard.h>
+
+namespace keyguard {
+
+GoogleKeyguard::~GoogleKeyguard() {
+    if (password_key_) {
+        memset_s(password_key_.get(), 0, sizeof(password_key_.get()) / sizeof(password_key_[0]));
+    }
+}
+
+void GoogleKeyguard::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);
+        return;
+    }
+    enrolled_password.buffer = ComputeSignature(password_key_.get(),
+            provided_password->buffer.get(), provided_password->length, &enrolled_password.length);
+    response->SetEnrolledPasswordHandle(&enrolled_password);
+}
+
+void GoogleKeyguard::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);
+        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) {
+        // Signature matches
+        SizedBuffer auth_token;
+        auth_token.buffer = MintAuthToken(request.GetUserId(), &auth_token.length);
+        response->SetVerificationToken(&auth_token);
+    } else {
+        response->SetError(KG_ERROR_INVALID);
+    }
+}
+
+std::unique_ptr<uint8_t> GoogleKeyguard::MintAuthToken(uint32_t user_id, size_t *length) {
+    AuthToken *auth_token = new AuthToken;
+    SizedBuffer serialized_auth_token;
+
+    struct timeval time;
+    gettimeofday(&time, NULL);
+
+    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);
+
+    size_t hash_len = (size_t)((uint8_t *)&auth_token->hmac_tag - (uint8_t *)auth_token);
+    size_t signature_len;
+    std::unique_ptr<uint8_t> signature = ComputeSignature(GetAuthTokenKey().get(),
+            reinterpret_cast<uint8_t *>(auth_token), hash_len, &signature_len);
+
+    memcpy(&auth_token->hmac, signature.get(), sizeof(auth_token->hmac));
+    if (length != NULL) *length = sizeof(AuthToken);
+    std::unique_ptr<uint8_t> result(reinterpret_cast<uint8_t *>(auth_token));
+    return result;
+}
+}