Add encryption convenience methods to KeystoreClient.

This Cl adds authenticated encryption and decryption methods which
require minimal inputs. These methods are suitable for encrypting local
state on brillo.

BUG: 23528174
TEST=manual using the keystore_cli_v2 tool

Change-Id: I41abcd77452e86b1eb7373f9db95b645100e2f0f
diff --git a/keystore/Android.mk b/keystore/Android.mk
index 6c25b89..2daf131 100644
--- a/keystore/Android.mk
+++ b/keystore/Android.mk
@@ -16,6 +16,12 @@
 
 LOCAL_PATH := $(call my-dir)
 
+# This has to be lazy-resolved because it depends on the LOCAL_MODULE_CLASS
+# which varies depending on what is being built.
+define keystore_proto_include
+$(call local-generated-sources-dir)/proto/$(LOCAL_PATH)
+endef
+
 include $(CLEAR_VARS)
 ifeq ($(USE_32_BIT_KEYSTORE), true)
 LOCAL_MULTILIB := 32
@@ -65,6 +71,7 @@
 	libkeystore_binder
 LOCAL_MODULE := keystore_cli_v2
 LOCAL_MODULE_TAGS := debug
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include external/gtest/include
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_EXECUTABLE)
 
@@ -77,17 +84,20 @@
 LOCAL_SRC_FILES := \
 	IKeystoreService.cpp \
 	keyblob_utils.cpp \
+	keystore_client.proto \
 	keystore_client_impl.cpp \
 	keystore_get.cpp
 LOCAL_SHARED_LIBRARIES := \
 	libbinder \
 	libkeymaster_messages \
 	liblog \
+	libprotobuf-cpp-lite \
 	libsoftkeymasterdevice \
 	libutils
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
 LOCAL_MODULE := libkeystore_binder
 LOCAL_MODULE_TAGS := optional
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(call keystore_proto_include)
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_SHARED_LIBRARY)
diff --git a/keystore/include/keystore/keystore_client.h b/keystore/include/keystore/keystore_client.h
index f87e9af..cec29f7 100644
--- a/keystore/include/keystore/keystore_client.h
+++ b/keystore/include/keystore/keystore_client.h
@@ -53,6 +53,33 @@
     KeystoreClient() = default;
     virtual ~KeystoreClient() = default;
 
+    // Encrypts and authenticates |data| with minimal configuration for local
+    // decryption. If a key identified by |key_name| does not already exist it
+    // will be generated. On success returns true and populates |encrypted_data|.
+    // Note: implementations may generate more than one key but they will always
+    // have |key_name| as a prefix.
+    virtual bool encryptWithAuthentication(const std::string& key_name, const std::string& data,
+                                           std::string* encrypted_data) = 0;
+
+    // Decrypts and authenticates |encrypted_data| as output by
+    // EncryptWithAuthentication using the key(s) identified by |key_name|. On
+    // success returns true and populates |data|.
+    virtual bool decryptWithAuthentication(const std::string& key_name,
+                                           const std::string& encrypted_data,
+                                           std::string* data) = 0;
+
+    // Performs a Begin/Update/Finish sequence for an operation. The |purpose|,
+    // |key_name|, |input_parameters|, and |output_parameters| are as in
+    // BeginOperation. The |input_data| is as in UpdateOperation. The
+    // |signature_to_verify| and |output_data| are as in FinishOperation. On
+    // success returns true.
+    virtual bool oneShotOperation(keymaster_purpose_t purpose, const std::string& key_name,
+                                  const keymaster::AuthorizationSet& input_parameters,
+                                  const std::string& input_data,
+                                  const std::string& signature_to_verify,
+                                  keymaster::AuthorizationSet* output_parameters,
+                                  std::string* output_data) = 0;
+
     // Adds |entropy| to the random number generator. Returns KM_ERROR_OK on
     // success and a Keystore ResponseCode or keymaster_error_t on failure.
     virtual int32_t addRandomNumberGeneratorEntropy(const std::string& entropy) = 0;
@@ -112,9 +139,9 @@
 
     // Continues the operation associated with |handle| using the given
     // |input_parameters| and |input_data|. On success, the
-    // |num_input_bytes_consumed|, any |output_parameters|, and any |output_data|
-    // is populated. Returns KM_ERROR_OK on success and a Keystore ResponseCode or
-    // keymaster_error_t on failure.
+    // |num_input_bytes_consumed| and any |output_parameters| are populated. Any
+    // |output_data| will be appended. Returns KM_ERROR_OK on success and a
+    // Keystore ResponseCode or keymaster_error_t on failure.
     virtual int32_t updateOperation(keymaster_operation_handle_t handle,
                                     const keymaster::AuthorizationSet& input_parameters,
                                     const std::string& input_data, size_t* num_input_bytes_consumed,
@@ -123,9 +150,9 @@
 
     // Finishes the operation associated with |handle| using the given
     // |input_parameters| and, if necessary, a |signature_to_verify|. On success,
-    // any |output_parameters| and final |output_data| are populated. Returns
-    // KM_ERROR_OK on success and a Keystore ResponseCode or keymaster_error_t on
-    // failure.
+    // any |output_parameters| are populated and |output_data| is appended.
+    // Returns KM_ERROR_OK on success and a Keystore ResponseCode or
+    // keymaster_error_t on failure.
     virtual int32_t finishOperation(keymaster_operation_handle_t handle,
                                     const keymaster::AuthorizationSet& input_parameters,
                                     const std::string& signature_to_verify,
diff --git a/keystore/include/keystore/keystore_client_impl.h b/keystore/include/keystore/keystore_client_impl.h
index 7ed8443..21f68f9 100644
--- a/keystore/include/keystore/keystore_client_impl.h
+++ b/keystore/include/keystore/keystore_client_impl.h
@@ -34,6 +34,15 @@
     ~KeystoreClientImpl() override = default;
 
     // KeystoreClient methods.
+    bool encryptWithAuthentication(const std::string& key_name, const std::string& data,
+                                   std::string* encrypted_data) override;
+    bool decryptWithAuthentication(const std::string& key_name, const std::string& encrypted_data,
+                                   std::string* data) override;
+    bool oneShotOperation(keymaster_purpose_t purpose, const std::string& key_name,
+                          const keymaster::AuthorizationSet& input_parameters,
+                          const std::string& input_data, const std::string& signature_to_verify,
+                          keymaster::AuthorizationSet* output_parameters,
+                          std::string* output_data) override;
     int32_t addRandomNumberGeneratorEntropy(const std::string& entropy) override;
     int32_t generateKey(const std::string& key_name,
                         const keymaster::AuthorizationSet& key_parameters,
@@ -71,12 +80,6 @@
     bool listKeys(const std::string& prefix, std::vector<std::string>* key_name_list) override;
 
   private:
-    android::sp<android::IServiceManager> service_manager_;
-    android::sp<android::IBinder> keystore_binder_;
-    android::sp<android::IKeystoreService> keystore_;
-    keymaster_operation_handle_t next_virtual_handle_ = 1;
-    std::map<keymaster_operation_handle_t, android::sp<android::IBinder>> active_operations_;
-
     // Returns an available virtual operation handle.
     keymaster_operation_handle_t getNextVirtualHandle();
 
@@ -84,6 +87,30 @@
     // KM_ERROR_OK (not keystore's NO_ERROR).
     int32_t mapKeystoreError(int32_t keystore_error);
 
+    // Creates an encryption key suitable for EncryptWithAuthentication or
+    // verifies attributes if the key already exists. Returns true on success.
+    bool createOrVerifyEncryptionKey(const std::string& key_name);
+
+    // Creates an authentication key suitable for EncryptWithAuthentication or
+    // verifies attributes if the key already exists. Returns true on success.
+    bool createOrVerifyAuthenticationKey(const std::string& key_name);
+
+    // Verifies attributes of an encryption key suitable for
+    // EncryptWithAuthentication. Returns true on success and populates |verified|
+    // with the result of the verification.
+    bool verifyEncryptionKeyAttributes(const std::string& key_name, bool* verified);
+
+    // Verifies attributes of an authentication key suitable for
+    // EncryptWithAuthentication. Returns true on success and populates |verified|
+    // with the result of the verification.
+    bool verifyAuthenticationKeyAttributes(const std::string& key_name, bool* verified);
+
+    android::sp<android::IServiceManager> service_manager_;
+    android::sp<android::IBinder> keystore_binder_;
+    android::sp<android::IKeystoreService> keystore_;
+    keymaster_operation_handle_t next_virtual_handle_ = 1;
+    std::map<keymaster_operation_handle_t, android::sp<android::IBinder>> active_operations_;
+
     DISALLOW_COPY_AND_ASSIGN(KeystoreClientImpl);
 };
 
diff --git a/keystore/include/keystore/keystore_client_mock.h b/keystore/include/keystore/keystore_client_mock.h
index 2bda844..2d1f499 100644
--- a/keystore/include/keystore/keystore_client_mock.h
+++ b/keystore/include/keystore/keystore_client_mock.h
@@ -29,6 +29,17 @@
     KeystoreClientMock() = default;
     ~KeystoreClientMock() = default;
 
+    MOCK_METHOD3(encryptWithAuthentication,
+                 bool(const std::string& key_name, const std::string& data,
+                      std::string* encrypted_data));
+    MOCK_METHOD3(decryptWithAuthentication,
+                 bool(const std::string& key_name, const std::string& encrypted_data,
+                      std::string* data));
+    MOCK_METHOD7(oneShotOperation,
+                 bool(keymaster_purpose_t purpose, const std::string& key_name,
+                      const keymaster::AuthorizationSet& input_parameters,
+                      const std::string& input_data, const std::string& signature_to_verify,
+                      keymaster::AuthorizationSet* output_parameters, std::string* output_data));
     MOCK_METHOD1(addRandomNumberGeneratorEntropy, int32_t(const std::string& entropy));
     MOCK_METHOD4(generateKey,
                  int32_t(const std::string& key_name,
diff --git a/keystore/keystore_cli_v2.cpp b/keystore/keystore_cli_v2.cpp
index 288d600..4f4040d 100644
--- a/keystore/keystore_cli_v2.cpp
+++ b/keystore/keystore_cli_v2.cpp
@@ -18,6 +18,7 @@
 #include <vector>
 
 #include "base/command_line.h"
+#include "base/files/file_util.h"
 #include "keymaster/authorization_set.h"
 #include "keystore/keystore_client_impl.h"
 
@@ -38,7 +39,8 @@
            "          delete-all\n"
            "          exists --name=<key_name>\n"
            "          list [--prefix=<key_name_prefix>]\n"
-           "          sign-verify --name=<key_name>\n");
+           "          sign-verify --name=<key_name>\n"
+           "          [en|de]crypt --name=<key_name> --in=<file> --out=<file>\n");
     exit(1);
 }
 
@@ -46,6 +48,25 @@
     return std::unique_ptr<KeystoreClient>(new keystore::KeystoreClientImpl);
 }
 
+std::string ReadFile(const std::string& filename) {
+    std::string content;
+    base::FilePath path(filename);
+    if (!base::ReadFileToString(path, &content)) {
+        printf("Failed to read file: %s\n", filename.c_str());
+        exit(1);
+    }
+    return content;
+}
+
+void WriteFile(const std::string& filename, const std::string& content) {
+    base::FilePath path(filename);
+    int size = content.size();
+    if (base::WriteFile(path, content.data(), size) != size) {
+        printf("Failed to write file: %s\n", filename.c_str());
+        exit(1);
+    }
+}
+
 int AddEntropy(const std::string& input) {
     std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance();
     int32_t result = keystore->addRandomNumberGeneratorEntropy(input);
@@ -157,6 +178,7 @@
     printf("Sign: %zu bytes.\n", output_data.size());
     // We have a signature, now verify it.
     std::string signature_to_verify = output_data;
+    output_data.clear();
     result = keystore->beginOperation(KM_PURPOSE_VERIFY, name, sign_params.build(), &output_params,
                                       &handle);
     if (result != KM_ERROR_OK) {
@@ -183,6 +205,32 @@
     return 0;
 }
 
+int Encrypt(const std::string& key_name, const std::string& input_filename,
+            const std::string& output_filename) {
+    std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance();
+    std::string input = ReadFile(input_filename);
+    std::string output;
+    if (!keystore->encryptWithAuthentication(key_name, input, &output)) {
+        printf("EncryptWithAuthentication failed.\n");
+        return 1;
+    }
+    WriteFile(output_filename, output);
+    return 0;
+}
+
+int Decrypt(const std::string& key_name, const std::string& input_filename,
+            const std::string& output_filename) {
+    std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance();
+    std::string input = ReadFile(input_filename);
+    std::string output;
+    if (!keystore->decryptWithAuthentication(key_name, input, &output)) {
+        printf("DecryptWithAuthentication failed.\n");
+        return 1;
+    }
+    WriteFile(output_filename, output);
+    return 0;
+}
+
 }  // namespace
 
 int main(int argc, char** argv) {
@@ -210,6 +258,14 @@
         return List(command_line->GetSwitchValueASCII("prefix"));
     } else if (args[0] == "sign-verify") {
         return SignAndVerify(command_line->GetSwitchValueASCII("name"));
+    } else if (args[0] == "encrypt") {
+        return Encrypt(command_line->GetSwitchValueASCII("name"),
+                       command_line->GetSwitchValueASCII("in"),
+                       command_line->GetSwitchValueASCII("out"));
+    } else if (args[0] == "decrypt") {
+        return Decrypt(command_line->GetSwitchValueASCII("name"),
+                       command_line->GetSwitchValueASCII("in"),
+                       command_line->GetSwitchValueASCII("out"));
     } else {
         PrintUsageAndExit();
     }
diff --git a/keystore/keystore_client.proto b/keystore/keystore_client.proto
new file mode 100644
index 0000000..cd520dc
--- /dev/null
+++ b/keystore/keystore_client.proto
@@ -0,0 +1,26 @@
+// 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.
+
+package keystore;
+
+option optimize_for = LITE_RUNTIME;
+
+// Holds encrypted, authenticated data.
+message EncryptedData {
+  // The initialization vector used during encryption.
+  optional bytes init_vector = 1;
+  // MAC of (init_vector + encrypted_data).
+  optional bytes authentication_data = 2;
+  optional bytes encrypted_data = 3;
+}
diff --git a/keystore/keystore_client_impl.cpp b/keystore/keystore_client_impl.cpp
index deaa615..d4e784f 100644
--- a/keystore/keystore_client_impl.cpp
+++ b/keystore/keystore_client_impl.cpp
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#define LOG_TAG "keystore_client"
+
 #include "keystore/keystore_client_impl.h"
 
 #include <string>
@@ -22,20 +24,29 @@
 #include "binder/IServiceManager.h"
 #include "keystore/IKeystoreService.h"
 #include "keystore/keystore.h"
+#include "log/log.h"
 #include "utils/String16.h"
 #include "utils/String8.h"
 
+#include "keystore_client.pb.h"
+
 using android::ExportResult;
 using android::KeyCharacteristics;
 using android::KeymasterArguments;
 using android::OperationResult;
 using android::String16;
 using keymaster::AuthorizationSet;
+using keymaster::AuthorizationSetBuilder;
 
 namespace {
 
 // Use the UID of the current process.
 const int kDefaultUID = -1;
+const char kEncryptSuffix[] = "_ENC";
+const char kAuthenticateSuffix[] = "_AUTH";
+const uint32_t kAESKeySize = 256;      // bits
+const uint32_t kHMACKeySize = 256;     // bits
+const uint32_t kHMACOutputSize = 256;  // bits
 
 const uint8_t* StringAsByteArray(const std::string& s) {
     return reinterpret_cast<const uint8_t*>(s.data());
@@ -55,6 +66,126 @@
     keystore_ = android::interface_cast<android::IKeystoreService>(keystore_binder_);
 }
 
+bool KeystoreClientImpl::encryptWithAuthentication(const std::string& key_name,
+                                                   const std::string& data,
+                                                   std::string* encrypted_data) {
+    // The encryption algorithm is AES-256-CBC with PKCS #7 padding and a random
+    // IV. The authentication algorithm is HMAC-SHA256 and is computed over the
+    // cipher-text (i.e. Encrypt-then-MAC approach). This was chosen over AES-GCM
+    // because hardware support for GCM is not mandatory for all Brillo devices.
+    std::string encryption_key_name = key_name + kEncryptSuffix;
+    if (!createOrVerifyEncryptionKey(encryption_key_name)) {
+        return false;
+    }
+    std::string authentication_key_name = key_name + kAuthenticateSuffix;
+    if (!createOrVerifyAuthenticationKey(authentication_key_name)) {
+        return false;
+    }
+    AuthorizationSetBuilder encrypt_params;
+    encrypt_params.Padding(KM_PAD_PKCS7);
+    encrypt_params.Authorization(keymaster::TAG_BLOCK_MODE, KM_MODE_CBC);
+    AuthorizationSet output_params;
+    std::string raw_encrypted_data;
+    if (!oneShotOperation(KM_PURPOSE_ENCRYPT, encryption_key_name, encrypt_params.build(), data,
+                          std::string(), /* signature_to_verify */
+                          &output_params, &raw_encrypted_data)) {
+        ALOGE("Encrypt: AES operation failed.");
+        return false;
+    }
+    keymaster_blob_t init_vector_blob;
+    if (!output_params.GetTagValue(keymaster::TAG_NONCE, &init_vector_blob)) {
+        ALOGE("Encrypt: Missing initialization vector.");
+        return false;
+    }
+    std::string init_vector =
+        ByteArrayAsString(init_vector_blob.data, init_vector_blob.data_length);
+
+    AuthorizationSetBuilder authenticate_params;
+    authenticate_params.Digest(KM_DIGEST_SHA_2_256);
+    authenticate_params.Authorization(keymaster::TAG_MAC_LENGTH, kHMACOutputSize);
+    std::string raw_authentication_data;
+    if (!oneShotOperation(KM_PURPOSE_SIGN, authentication_key_name, authenticate_params.build(),
+                          init_vector + raw_encrypted_data, std::string(), /* signature_to_verify */
+                          &output_params, &raw_authentication_data)) {
+        ALOGE("Encrypt: HMAC operation failed.");
+        return false;
+    }
+    EncryptedData protobuf;
+    protobuf.set_init_vector(init_vector);
+    protobuf.set_authentication_data(raw_authentication_data);
+    protobuf.set_encrypted_data(raw_encrypted_data);
+    if (!protobuf.SerializeToString(encrypted_data)) {
+        ALOGE("Encrypt: Failed to serialize EncryptedData protobuf.");
+        return false;
+    }
+    return true;
+}
+
+bool KeystoreClientImpl::decryptWithAuthentication(const std::string& key_name,
+                                                   const std::string& encrypted_data,
+                                                   std::string* data) {
+    EncryptedData protobuf;
+    if (!protobuf.ParseFromString(encrypted_data)) {
+        ALOGE("Decrypt: Failed to parse EncryptedData protobuf.");
+    }
+    // Verify authentication before attempting decryption.
+    std::string authentication_key_name = key_name + kAuthenticateSuffix;
+    AuthorizationSetBuilder authenticate_params;
+    authenticate_params.Digest(KM_DIGEST_SHA_2_256);
+    AuthorizationSet output_params;
+    std::string output_data;
+    if (!oneShotOperation(KM_PURPOSE_VERIFY, authentication_key_name, authenticate_params.build(),
+                          protobuf.init_vector() + protobuf.encrypted_data(),
+                          protobuf.authentication_data(), &output_params, &output_data)) {
+        ALOGE("Decrypt: HMAC operation failed.");
+        return false;
+    }
+    std::string encryption_key_name = key_name + kEncryptSuffix;
+    AuthorizationSetBuilder encrypt_params;
+    encrypt_params.Padding(KM_PAD_PKCS7);
+    encrypt_params.Authorization(keymaster::TAG_BLOCK_MODE, KM_MODE_CBC);
+    encrypt_params.Authorization(keymaster::TAG_NONCE, protobuf.init_vector().data(),
+                                 protobuf.init_vector().size());
+    if (!oneShotOperation(KM_PURPOSE_DECRYPT, encryption_key_name, encrypt_params.build(),
+                          protobuf.encrypted_data(), std::string(), /* signature_to_verify */
+                          &output_params, data)) {
+        ALOGE("Decrypt: AES operation failed.");
+        return false;
+    }
+    return true;
+}
+
+bool KeystoreClientImpl::oneShotOperation(keymaster_purpose_t purpose, const std::string& key_name,
+                                          const keymaster::AuthorizationSet& input_parameters,
+                                          const std::string& input_data,
+                                          const std::string& signature_to_verify,
+                                          keymaster::AuthorizationSet* output_parameters,
+                                          std::string* output_data) {
+    keymaster_operation_handle_t handle;
+    int32_t result =
+        beginOperation(purpose, key_name, input_parameters, output_parameters, &handle);
+    if (result != KM_ERROR_OK) {
+        ALOGE("BeginOperation failed: %d", result);
+        return false;
+    }
+    AuthorizationSet empty_params;
+    size_t num_input_bytes_consumed;
+    AuthorizationSet ignored_params;
+    result = updateOperation(handle, empty_params, input_data, &num_input_bytes_consumed,
+                             &ignored_params, output_data);
+    if (result != KM_ERROR_OK) {
+        ALOGE("UpdateOperation failed: %d", result);
+        return false;
+    }
+    result =
+        finishOperation(handle, empty_params, signature_to_verify, &ignored_params, output_data);
+    if (result != KM_ERROR_OK) {
+        ALOGE("FinishOperation failed: %d", result);
+        return false;
+    }
+    return true;
+}
+
 int32_t KeystoreClientImpl::addRandomNumberGeneratorEntropy(const std::string& entropy) {
     return mapKeystoreError(keystore_->addRngEntropy(StringAsByteArray(entropy), entropy.size()));
 }
@@ -173,7 +304,7 @@
             output_parameters->Reinitialize(&*result.outParams.params.begin(),
                                             result.outParams.params.size());
         }
-        *output_data = ByteArrayAsString(result.data.get(), result.dataLength);
+        output_data->append(ByteArrayAsString(result.data.get(), result.dataLength));
     }
     return error_code;
 }
@@ -198,7 +329,7 @@
             output_parameters->Reinitialize(&*result.outParams.params.begin(),
                                             result.outParams.params.size());
         }
-        *output_data = ByteArrayAsString(result.data.get(), result.dataLength);
+        output_data->append(ByteArrayAsString(result.data.get(), result.dataLength));
         active_operations_.erase(handle);
     }
     return error_code;
@@ -248,4 +379,171 @@
     return keystore_error;
 }
 
+bool KeystoreClientImpl::createOrVerifyEncryptionKey(const std::string& key_name) {
+    bool key_exists = doesKeyExist(key_name);
+    if (key_exists) {
+        bool verified = false;
+        if (!verifyEncryptionKeyAttributes(key_name, &verified)) {
+            return false;
+        }
+        if (!verified) {
+            int32_t result = deleteKey(key_name);
+            if (result != KM_ERROR_OK) {
+                ALOGE("Failed to delete invalid encryption key: %d", result);
+                return false;
+            }
+            key_exists = false;
+        }
+    }
+    if (!key_exists) {
+        AuthorizationSetBuilder key_parameters;
+        key_parameters.AesEncryptionKey(kAESKeySize)
+            .Padding(KM_PAD_PKCS7)
+            .Authorization(keymaster::TAG_BLOCK_MODE, KM_MODE_CBC)
+            .Authorization(keymaster::TAG_NO_AUTH_REQUIRED);
+        AuthorizationSet hardware_enforced_characteristics;
+        AuthorizationSet software_enforced_characteristics;
+        int32_t result =
+            generateKey(key_name, key_parameters.build(), &hardware_enforced_characteristics,
+                        &software_enforced_characteristics);
+        if (result != KM_ERROR_OK) {
+            ALOGE("Failed to generate encryption key: %d", result);
+            return false;
+        }
+        if (hardware_enforced_characteristics.size() == 0) {
+            ALOGW("WARNING: Encryption key is not hardware-backed.");
+        }
+    }
+    return true;
+}
+
+bool KeystoreClientImpl::createOrVerifyAuthenticationKey(const std::string& key_name) {
+    bool key_exists = doesKeyExist(key_name);
+    if (key_exists) {
+        bool verified = false;
+        if (!verifyAuthenticationKeyAttributes(key_name, &verified)) {
+            return false;
+        }
+        if (!verified) {
+            int32_t result = deleteKey(key_name);
+            if (result != KM_ERROR_OK) {
+                ALOGE("Failed to delete invalid authentication key: %d", result);
+                return false;
+            }
+            key_exists = false;
+        }
+    }
+    if (!key_exists) {
+        AuthorizationSetBuilder key_parameters;
+        key_parameters.HmacKey(kHMACKeySize)
+            .Digest(KM_DIGEST_SHA_2_256)
+            .Authorization(keymaster::TAG_MIN_MAC_LENGTH, kHMACOutputSize)
+            .Authorization(keymaster::TAG_NO_AUTH_REQUIRED);
+        AuthorizationSet hardware_enforced_characteristics;
+        AuthorizationSet software_enforced_characteristics;
+        int32_t result =
+            generateKey(key_name, key_parameters.build(), &hardware_enforced_characteristics,
+                        &software_enforced_characteristics);
+        if (result != KM_ERROR_OK) {
+            ALOGE("Failed to generate authentication key: %d", result);
+            return false;
+        }
+        if (hardware_enforced_characteristics.size() == 0) {
+            ALOGW("WARNING: Authentication key is not hardware-backed.");
+        }
+    }
+    return true;
+}
+
+bool KeystoreClientImpl::verifyEncryptionKeyAttributes(const std::string& key_name,
+                                                       bool* verified) {
+    AuthorizationSet hardware_enforced_characteristics;
+    AuthorizationSet software_enforced_characteristics;
+    int32_t result = getKeyCharacteristics(key_name, &hardware_enforced_characteristics,
+                                           &software_enforced_characteristics);
+    if (result != KM_ERROR_OK) {
+        ALOGE("Failed to query encryption key: %d", result);
+        return false;
+    }
+    *verified = true;
+    keymaster_algorithm_t algorithm = KM_ALGORITHM_RSA;
+    if ((!hardware_enforced_characteristics.GetTagValue(keymaster::TAG_ALGORITHM, &algorithm) &&
+         !software_enforced_characteristics.GetTagValue(keymaster::TAG_ALGORITHM, &algorithm)) ||
+        algorithm != KM_ALGORITHM_AES) {
+        ALOGW("Found encryption key with invalid algorithm.");
+        *verified = false;
+    }
+    uint32_t key_size = 0;
+    if ((!hardware_enforced_characteristics.GetTagValue(keymaster::TAG_KEY_SIZE, &key_size) &&
+         !software_enforced_characteristics.GetTagValue(keymaster::TAG_KEY_SIZE, &key_size)) ||
+        key_size != kAESKeySize) {
+        ALOGW("Found encryption key with invalid size.");
+        *verified = false;
+    }
+    keymaster_block_mode_t block_mode = KM_MODE_ECB;
+    if ((!hardware_enforced_characteristics.GetTagValue(keymaster::TAG_BLOCK_MODE, &block_mode) &&
+         !software_enforced_characteristics.GetTagValue(keymaster::TAG_BLOCK_MODE, &block_mode)) ||
+        block_mode != KM_MODE_CBC) {
+        ALOGW("Found encryption key with invalid block mode.");
+        *verified = false;
+    }
+    keymaster_padding_t padding_mode = KM_PAD_NONE;
+    if ((!hardware_enforced_characteristics.GetTagValue(keymaster::TAG_PADDING, &padding_mode) &&
+         !software_enforced_characteristics.GetTagValue(keymaster::TAG_PADDING, &padding_mode)) ||
+        padding_mode != KM_PAD_PKCS7) {
+        ALOGW("Found encryption key with invalid padding mode.");
+        *verified = false;
+    }
+    if (hardware_enforced_characteristics.size() == 0) {
+        ALOGW("WARNING: Encryption key is not hardware-backed.");
+    }
+    return true;
+}
+
+bool KeystoreClientImpl::verifyAuthenticationKeyAttributes(const std::string& key_name,
+                                                           bool* verified) {
+    AuthorizationSet hardware_enforced_characteristics;
+    AuthorizationSet software_enforced_characteristics;
+    int32_t result = getKeyCharacteristics(key_name, &hardware_enforced_characteristics,
+                                           &software_enforced_characteristics);
+    if (result != KM_ERROR_OK) {
+        ALOGE("Failed to query authentication key: %d", result);
+        return false;
+    }
+    *verified = true;
+    keymaster_algorithm_t algorithm = KM_ALGORITHM_RSA;
+    if ((!hardware_enforced_characteristics.GetTagValue(keymaster::TAG_ALGORITHM, &algorithm) &&
+         !software_enforced_characteristics.GetTagValue(keymaster::TAG_ALGORITHM, &algorithm)) ||
+        algorithm != KM_ALGORITHM_HMAC) {
+        ALOGW("Found authentication key with invalid algorithm.");
+        *verified = false;
+    }
+    uint32_t key_size = 0;
+    if ((!hardware_enforced_characteristics.GetTagValue(keymaster::TAG_KEY_SIZE, &key_size) &&
+         !software_enforced_characteristics.GetTagValue(keymaster::TAG_KEY_SIZE, &key_size)) ||
+        key_size != kHMACKeySize) {
+        ALOGW("Found authentication key with invalid size.");
+        *verified = false;
+    }
+    uint32_t mac_size = 0;
+    if ((!hardware_enforced_characteristics.GetTagValue(keymaster::TAG_MIN_MAC_LENGTH, &mac_size) &&
+         !software_enforced_characteristics.GetTagValue(keymaster::TAG_MIN_MAC_LENGTH,
+                                                        &mac_size)) ||
+        mac_size != kHMACOutputSize) {
+        ALOGW("Found authentication key with invalid minimum mac size.");
+        *verified = false;
+    }
+    keymaster_digest_t digest = KM_DIGEST_NONE;
+    if ((!hardware_enforced_characteristics.GetTagValue(keymaster::TAG_DIGEST, &digest) &&
+         !software_enforced_characteristics.GetTagValue(keymaster::TAG_DIGEST, &digest)) ||
+        digest != KM_DIGEST_SHA_2_256) {
+        ALOGW("Found authentication key with invalid digest list.");
+        *verified = false;
+    }
+    if (hardware_enforced_characteristics.size() == 0) {
+        ALOGW("WARNING: Authentication key is not hardware-backed.");
+    }
+    return true;
+}
+
 }  // namespace keystore