summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGaurav Shah <gauravsh@google.com>2015-11-02 19:28:18 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2015-11-02 19:28:18 +0000
commite01125c8a96e35e22783fcb73fdcaa7f129463c0 (patch)
tree2a6e7b1e61c7ebd24dc805697d70b4ed2062908e
parent4122b99ba0cdaeb8bf4a348275de94055fc5df10 (diff)
parent251cb28132e456f81374c8f8a983a5a9ad9aaee8 (diff)
downloadsecurity-e01125c8a96e35e22783fcb73fdcaa7f129463c0.tar.gz
Merge "Add encryption convenience methods to KeystoreClient."
-rw-r--r--keystore/Android.mk12
-rw-r--r--keystore/include/keystore/keystore_client.h39
-rw-r--r--keystore/include/keystore/keystore_client_impl.h39
-rw-r--r--keystore/include/keystore/keystore_client_mock.h11
-rw-r--r--keystore/keystore_cli_v2.cpp58
-rw-r--r--keystore/keystore_client.proto26
-rw-r--r--keystore/keystore_client_impl.cpp302
7 files changed, 471 insertions, 16 deletions
diff --git a/keystore/Android.mk b/keystore/Android.mk
index 6c25b892..2daf131b 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 @@ LOCAL_SHARED_LIBRARIES := \
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_CFLAGS := -Wall -Wextra -Werror
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 f87e9af0..cec29f71 100644
--- a/keystore/include/keystore/keystore_client.h
+++ b/keystore/include/keystore/keystore_client.h
@@ -53,6 +53,33 @@ class KeystoreClient {
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 @@ class KeystoreClient {
// 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 @@ class KeystoreClient {
// 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 7ed8443b..21f68f94 100644
--- a/keystore/include/keystore/keystore_client_impl.h
+++ b/keystore/include/keystore/keystore_client_impl.h
@@ -34,6 +34,15 @@ class KeystoreClientImpl : public KeystoreClient {
~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 @@ class KeystoreClientImpl : public KeystoreClient {
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 @@ class KeystoreClientImpl : public KeystoreClient {
// 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 2bda8444..2d1f4996 100644
--- a/keystore/include/keystore/keystore_client_mock.h
+++ b/keystore/include/keystore/keystore_client_mock.h
@@ -29,6 +29,17 @@ class KeystoreClientMock : public KeystoreClient {
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 288d600e..4f4040d3 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 @@ void PrintUsageAndExit() {
" 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 @@ std::unique_ptr<KeystoreClient> CreateKeystoreInstance() {
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 @@ int SignAndVerify(const std::string& name) {
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 @@ int SignAndVerify(const std::string& name) {
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 @@ int main(int argc, char** argv) {
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 00000000..cd520dc0
--- /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 deaa6153..d4e784f2 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 @@ KeystoreClientImpl::KeystoreClientImpl() {
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 @@ int32_t KeystoreClientImpl::updateOperation(keymaster_operation_handle_t handle,
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 @@ int32_t KeystoreClientImpl::finishOperation(keymaster_operation_handle_t handle,
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 @@ int32_t KeystoreClientImpl::mapKeystoreError(int32_t keystore_error) {
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