Add SoftKeymasterDevice

SoftKeymasterDevice implements the keymaster HAL API by calling directly
to a GoogleKeymaster instance.

Change-Id: If530b98fecbef05815b685efff9295539614fd52
diff --git a/Android.mk b/Android.mk
index 171caaa..7e92c0b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -17,10 +17,6 @@
 ###
 # libkeymaster_messages contains just the code necessary to communicate with a
 # GoogleKeymaster implementation, e.g. one running in TrustZone.
-#
-# Note that this library is too large; it should not include ocb.c and not use
-# openssl.  At present it must, because the code needs refactoring to separate
-# concerns a bit better.
 ##
 include $(CLEAR_VARS)
 # Disable clang until we find a way to suppress clang optmization in google_keymaster_utils.h.
@@ -38,32 +34,60 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-include $(BUILD_STATIC_LIBRARY)
+include $(BUILD_SHARED_LIBRARY)
 
 ###
 # libkeymaster contains almost everything needed for a keymaster implementation,
 # lacking only a subclass of the (abstract) GoogleKeymaster class to provide
-# environment-specific services.
+# environment-specific services and a wrapper to translate from the
+# function-based keymaster HAL API to the message-based GoogleKeymaster API.
 ###
 include $(CLEAR_VARS)
 # Disable clang until we find a way to suppress clang optmization in google_keymaster_utils.h.
 LOCAL_CLANG := false
 LOCAL_MODULE:= libkeymaster
 LOCAL_SRC_FILES:= \
+		aes_key.cpp \
+		aes_operation.cpp \
+		asymmetric_key.cpp \
 		authorization_set.cpp \
-		google_keymaster_messages.cpp \
+		ecdsa_key.cpp \
+		ecdsa_operation.cpp \
 		google_keymaster.cpp \
+		google_keymaster_messages.cpp \
 		google_keymaster_utils.cpp \
-		ocb.c \
+		key.cpp \
 		key_blob.cpp \
+		ocb.c \
+		rsa_key.cpp \
+		rsa_operation.cpp \
 		serializable.cpp \
 		unencrypted_key_blob.cpp
 LOCAL_C_INCLUDES := \
-	$(LOCAL_PATH)/include \
-	external/openssl/include
+	$(LOCAL_PATH)/include
 LOCAL_SHARED_LIBRARIES := libcrypto
 LOCAL_CFLAGS = -Wall -Werror
 LOCAL_MODULE_TAGS := optional
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-include $(BUILD_STATIC_LIBRARY)
+include $(BUILD_SHARED_LIBRARY)
+
+
+###
+# soft_keymaster_device provides a software-based keymaster HAL implementation.
+# This is used by keystore as a fallback when there is no HW keymaster
+# implementation available, or it doesn't provide needed features.
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := soft_keymaster_device
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+	soft_keymaster_device.cpp \
+	soft_keymaster_logger.cpp
+LOCAL_C_INCLUDES := \
+	system/security/keystore
+LOCAL_CFLAGS = -Wall -Werror
+LOCAL_SHARED_LIBRARIES := libkeymaster liblog
+LOCAL_MODULE_TAGS := optional
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_SHARED_LIBRARY)
diff --git a/Makefile b/Makefile
index d214c5b..3378f70 100644
--- a/Makefile
+++ b/Makefile
@@ -44,6 +44,7 @@
 	rsa_key.cpp \
 	rsa_operation.cpp \
 	serializable.cpp \
+	soft_keymaster_device.cpp \
 	unencrypted_key_blob.cpp
 CCSRCS=$(GTEST)/src/gtest-all.cc
 CSRCS=ocb.c
@@ -141,6 +142,7 @@
 	rsa_key.o \
 	rsa_operation.o \
 	serializable.o \
+	soft_keymaster_device.o \
 	unencrypted_key_blob.o \
 	$(GTEST)/src/gtest-all.o
 
diff --git a/google_keymaster_test.cpp b/google_keymaster_test.cpp
index 199b523..6c672be 100644
--- a/google_keymaster_test.cpp
+++ b/google_keymaster_test.cpp
@@ -25,7 +25,7 @@
 #include <keymaster/keymaster_tags.h>
 
 #include "google_keymaster_test_utils.h"
-#include "google_softkeymaster.h"
+#include "soft_keymaster_device.h"
 
 using std::string;
 using std::ifstream;
@@ -72,126 +72,189 @@
 
 class KeymasterTest : public testing::Test {
   protected:
-    KeymasterTest() : device(5, new StdoutLogger) { RAND_seed("foobar", 6); }
-    ~KeymasterTest() {}
-
-    template <typename T> void ExpectEmptyResponse(const SupportedResponse<T>& response) {
-        EXPECT_EQ(KM_ERROR_OK, response.error);
-        EXPECT_EQ(0U, response.results_length);
+    KeymasterTest() : device_(new StdoutLogger), characteristics_(NULL) {
+        blob_.key_material = NULL;
+        RAND_seed("foobar", 6);
+    }
+    ~KeymasterTest() {
+        FreeCharacteristics();
+        FreeKeyBlob();
     }
 
-    template <typename T> void ExpectResponseContains(T val, const SupportedResponse<T>& response) {
-        EXPECT_EQ(KM_ERROR_OK, response.error);
-        EXPECT_EQ(1U, response.results_length);
-        EXPECT_EQ(val, response.results[0]);
+    keymaster_device* device() { return reinterpret_cast<keymaster_device*>(device_.hw_device()); }
+
+    template <typename T> void ExpectContains(T val, T* vals, size_t len) {
+        EXPECT_EQ(1U, len);
+        EXPECT_EQ(val, vals[0]);
     }
 
-    GoogleSoftKeymaster device;
+    void FreeCharacteristics() {
+        keymaster_free_characteristics(characteristics_);
+        free(characteristics_);
+        characteristics_ = NULL;
+    }
+
+    void FreeKeyBlob() {
+        free(const_cast<uint8_t*>(blob_.key_material));
+        blob_.key_material = NULL;
+    }
+
+    SoftKeymasterDevice device_;
+
+    AuthorizationSet params_;
+    keymaster_key_blob_t blob_;
+    keymaster_key_characteristics_t* characteristics_;
 };
 
 typedef KeymasterTest CheckSupported;
 TEST_F(CheckSupported, SupportedAlgorithms) {
-    // Shouldn't blow up on NULL.
-    device.SupportedAlgorithms(NULL);
+    EXPECT_EQ(KM_ERROR_OUTPUT_PARAMETER_NULL,
+              device()->get_supported_algorithms(device(), NULL, NULL));
 
-    SupportedResponse<keymaster_algorithm_t> response;
-    device.SupportedAlgorithms(&response);
-    EXPECT_EQ(KM_ERROR_OK, response.error);
-    EXPECT_EQ(4U, response.results_length);
-    EXPECT_EQ(KM_ALGORITHM_RSA, response.results[0]);
-    EXPECT_EQ(KM_ALGORITHM_DSA, response.results[1]);
-    EXPECT_EQ(KM_ALGORITHM_ECDSA, response.results[2]);
-    EXPECT_EQ(KM_ALGORITHM_AES, response.results[3]);
+    size_t len;
+    keymaster_algorithm_t* algorithms;
+    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_algorithms(device(), &algorithms, &len));
+    ASSERT_EQ(4U, len);
+    EXPECT_EQ(KM_ALGORITHM_RSA, algorithms[0]);
+    EXPECT_EQ(KM_ALGORITHM_DSA, algorithms[1]);
+    EXPECT_EQ(KM_ALGORITHM_ECDSA, algorithms[2]);
+    EXPECT_EQ(KM_ALGORITHM_AES, algorithms[3]);
+
+    free(algorithms);
 }
 
 TEST_F(CheckSupported, SupportedBlockModes) {
-    // Shouldn't blow up on NULL.
-    device.SupportedBlockModes(KM_ALGORITHM_RSA, KM_PURPOSE_ENCRYPT, NULL);
+    EXPECT_EQ(KM_ERROR_OUTPUT_PARAMETER_NULL,
+              device()->get_supported_block_modes(device(), KM_ALGORITHM_RSA, KM_PURPOSE_ENCRYPT,
+                                                  NULL, NULL));
 
-    SupportedResponse<keymaster_block_mode_t> response;
-    device.SupportedBlockModes(KM_ALGORITHM_RSA, KM_PURPOSE_ENCRYPT, &response);
-    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE, response.error);
+    size_t len;
+    keymaster_block_mode_t* modes;
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE,
+              device()->get_supported_block_modes(device(), KM_ALGORITHM_RSA, KM_PURPOSE_ENCRYPT,
+                                                  &modes, &len));
 
-    device.SupportedBlockModes(KM_ALGORITHM_DSA, KM_PURPOSE_ENCRYPT, &response);
-    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE, response.error);
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE,
+              device()->get_supported_block_modes(device(), KM_ALGORITHM_DSA, KM_PURPOSE_ENCRYPT,
+                                                  &modes, &len));
 
-    device.SupportedBlockModes(KM_ALGORITHM_ECDSA, KM_PURPOSE_ENCRYPT, &response);
-    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE, response.error);
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE,
+              device()->get_supported_block_modes(device(), KM_ALGORITHM_ECDSA, KM_PURPOSE_ENCRYPT,
+                                                  &modes, &len));
 
-    device.SupportedBlockModes(KM_ALGORITHM_AES, KM_PURPOSE_ENCRYPT, &response);
-    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE, response.error);
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE,
+              device()->get_supported_block_modes(device(), KM_ALGORITHM_AES, KM_PURPOSE_ENCRYPT,
+                                                  &modes, &len));
 }
 
 TEST_F(CheckSupported, SupportedPaddingModes) {
-    // Shouldn't blow up on NULL.
-    device.SupportedPaddingModes(KM_ALGORITHM_RSA, KM_PURPOSE_ENCRYPT, NULL);
+    EXPECT_EQ(KM_ERROR_OUTPUT_PARAMETER_NULL,
+              device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA, KM_PURPOSE_ENCRYPT,
+                                                    NULL, NULL));
 
-    SupportedResponse<keymaster_padding_t> response;
-    device.SupportedPaddingModes(KM_ALGORITHM_RSA, KM_PURPOSE_SIGN, &response);
-    ExpectResponseContains(KM_PAD_NONE, response);
+    size_t len;
+    keymaster_padding_t* modes;
+    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA,
+                                                                 KM_PURPOSE_SIGN, &modes, &len));
+    ExpectContains(KM_PAD_NONE, modes, len);
+    free(modes);
 
-    device.SupportedPaddingModes(KM_ALGORITHM_DSA, KM_PURPOSE_SIGN, &response);
-    ExpectResponseContains(KM_PAD_NONE, response);
+    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_DSA,
+                                                                 KM_PURPOSE_SIGN, &modes, &len));
+    ExpectContains(KM_PAD_NONE, modes, len);
+    free(modes);
 
-    device.SupportedPaddingModes(KM_ALGORITHM_ECDSA, KM_PURPOSE_SIGN, &response);
-    ExpectResponseContains(KM_PAD_NONE, response);
+    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_ECDSA,
+                                                                 KM_PURPOSE_SIGN, &modes, &len));
+    ExpectContains(KM_PAD_NONE, modes, len);
+    free(modes);
 
-    device.SupportedPaddingModes(KM_ALGORITHM_AES, KM_PURPOSE_SIGN, &response);
-    ExpectEmptyResponse(response);
+    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_AES,
+                                                                 KM_PURPOSE_SIGN, &modes, &len));
+    EXPECT_EQ(0, len);
+    free(modes);
 }
 
 TEST_F(CheckSupported, SupportedDigests) {
-    // Shouldn't blow up on NULL.
-    device.SupportedDigests(KM_ALGORITHM_RSA, KM_PURPOSE_SIGN, NULL);
+    EXPECT_EQ(
+        KM_ERROR_OUTPUT_PARAMETER_NULL,
+        device()->get_supported_digests(device(), KM_ALGORITHM_RSA, KM_PURPOSE_SIGN, NULL, NULL));
 
-    SupportedResponse<keymaster_digest_t> response;
-    device.SupportedDigests(KM_ALGORITHM_RSA, KM_PURPOSE_SIGN, &response);
-    ExpectResponseContains(KM_DIGEST_NONE, response);
+    size_t len;
+    keymaster_digest_t* digests;
+    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_RSA,
+                                                           KM_PURPOSE_SIGN, &digests, &len));
+    ExpectContains(KM_DIGEST_NONE, digests, len);
+    free(digests);
 
-    device.SupportedDigests(KM_ALGORITHM_DSA, KM_PURPOSE_SIGN, &response);
-    ExpectResponseContains(KM_DIGEST_NONE, response);
+    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_DSA,
+                                                           KM_PURPOSE_SIGN, &digests, &len));
+    ExpectContains(KM_DIGEST_NONE, digests, len);
+    free(digests);
 
-    device.SupportedDigests(KM_ALGORITHM_ECDSA, KM_PURPOSE_SIGN, &response);
-    ExpectResponseContains(KM_DIGEST_NONE, response);
+    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_ECDSA,
+                                                           KM_PURPOSE_SIGN, &digests, &len));
+    ExpectContains(KM_DIGEST_NONE, digests, len);
+    free(digests);
 
-    device.SupportedDigests(KM_ALGORITHM_AES, KM_PURPOSE_SIGN, &response);
-    ExpectEmptyResponse(response);
+    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_AES,
+                                                           KM_PURPOSE_SIGN, &digests, &len));
+    EXPECT_EQ(0, len);
+    free(digests);
 }
 
 TEST_F(CheckSupported, SupportedImportFormats) {
-    // Shouldn't blow up on NULL.
-    device.SupportedImportFormats(KM_ALGORITHM_RSA, NULL);
+    EXPECT_EQ(KM_ERROR_OUTPUT_PARAMETER_NULL,
+              device()->get_supported_import_formats(device(), KM_ALGORITHM_RSA, NULL, NULL));
 
-    SupportedResponse<keymaster_key_format_t> response;
-    device.SupportedImportFormats(KM_ALGORITHM_RSA, &response);
-    ExpectResponseContains(KM_KEY_FORMAT_PKCS8, response);
+    size_t len;
+    keymaster_key_format_t* formats;
+    EXPECT_EQ(KM_ERROR_OK,
+              device()->get_supported_import_formats(device(), KM_ALGORITHM_RSA, &formats, &len));
+    ExpectContains(KM_KEY_FORMAT_PKCS8, formats, len);
+    free(formats);
 
-    device.SupportedImportFormats(KM_ALGORITHM_DSA, &response);
-    ExpectResponseContains(KM_KEY_FORMAT_PKCS8, response);
+    EXPECT_EQ(KM_ERROR_OK,
+              device()->get_supported_import_formats(device(), KM_ALGORITHM_DSA, &formats, &len));
+    ExpectContains(KM_KEY_FORMAT_PKCS8, formats, len);
+    free(formats);
 
-    device.SupportedImportFormats(KM_ALGORITHM_ECDSA, &response);
-    ExpectResponseContains(KM_KEY_FORMAT_PKCS8, response);
+    EXPECT_EQ(KM_ERROR_OK,
+              device()->get_supported_import_formats(device(), KM_ALGORITHM_ECDSA, &formats, &len));
+    ExpectContains(KM_KEY_FORMAT_PKCS8, formats, len);
+    free(formats);
 
-    device.SupportedImportFormats(KM_ALGORITHM_AES, &response);
-    ExpectEmptyResponse(response);
+    EXPECT_EQ(KM_ERROR_OK,
+              device()->get_supported_import_formats(device(), KM_ALGORITHM_AES, &formats, &len));
+    EXPECT_EQ(0, len);
+    free(formats);
 }
 
 TEST_F(CheckSupported, SupportedExportFormats) {
-    // Shouldn't blow up on NULL.
-    device.SupportedExportFormats(KM_ALGORITHM_RSA, NULL);
+    EXPECT_EQ(KM_ERROR_OUTPUT_PARAMETER_NULL,
+              device()->get_supported_export_formats(device(), KM_ALGORITHM_RSA, NULL, NULL));
 
-    SupportedResponse<keymaster_key_format_t> response;
-    device.SupportedExportFormats(KM_ALGORITHM_RSA, &response);
-    ExpectResponseContains(KM_KEY_FORMAT_X509, response);
+    size_t len;
+    keymaster_key_format_t* formats;
+    EXPECT_EQ(KM_ERROR_OK,
+              device()->get_supported_export_formats(device(), KM_ALGORITHM_RSA, &formats, &len));
+    ExpectContains(KM_KEY_FORMAT_X509, formats, len);
+    free(formats);
 
-    device.SupportedExportFormats(KM_ALGORITHM_DSA, &response);
-    ExpectResponseContains(KM_KEY_FORMAT_X509, response);
+    EXPECT_EQ(KM_ERROR_OK,
+              device()->get_supported_export_formats(device(), KM_ALGORITHM_DSA, &formats, &len));
+    ExpectContains(KM_KEY_FORMAT_X509, formats, len);
+    free(formats);
 
-    device.SupportedExportFormats(KM_ALGORITHM_ECDSA, &response);
-    ExpectResponseContains(KM_KEY_FORMAT_X509, response);
+    EXPECT_EQ(KM_ERROR_OK,
+              device()->get_supported_export_formats(device(), KM_ALGORITHM_ECDSA, &formats, &len));
+    ExpectContains(KM_KEY_FORMAT_X509, formats, len);
+    free(formats);
 
-    device.SupportedExportFormats(KM_ALGORITHM_AES, &response);
-    ExpectEmptyResponse(response);
+    EXPECT_EQ(KM_ERROR_OK,
+              device()->get_supported_export_formats(device(), KM_ALGORITHM_AES, &formats, &len));
+    EXPECT_EQ(0, len);
+    free(formats);
 }
 
 keymaster_key_param_t key_generation_base_params[] = {
@@ -201,114 +264,157 @@
     Authorization(TAG_APPLICATION_DATA, "app_data", 8), Authorization(TAG_AUTH_TIMEOUT, 300),
 };
 
+TEST_F(KeymasterTest, TestFlags) {
+    EXPECT_TRUE(device()->flags & KEYMASTER_SOFTWARE_ONLY);
+    EXPECT_TRUE(device()->flags & KEYMASTER_BLOBS_ARE_STANDALONE);
+    EXPECT_FALSE(device()->flags & KEYMASTER_SUPPORTS_DSA);
+    EXPECT_TRUE(device()->flags & KEYMASTER_SUPPORTS_EC);
+}
+
+typedef KeymasterTest OldKeyGeneration;
+
+TEST_F(OldKeyGeneration, Rsa) {
+    keymaster_rsa_keygen_params_t params = {.modulus_size = 256, .public_exponent = 3};
+    uint8_t* key_blob;
+    size_t key_blob_length;
+    EXPECT_EQ(0,
+              device()->generate_keypair(device(), TYPE_RSA, &params, &key_blob, &key_blob_length));
+    EXPECT_GT(key_blob_length, 0);
+
+    free(key_blob);
+}
+
+TEST_F(OldKeyGeneration, Ecdsa) {
+
+    keymaster_ec_keygen_params_t params = {.field_size = 256};
+    uint8_t* key_blob;
+    size_t key_blob_length;
+    EXPECT_EQ(0,
+              device()->generate_keypair(device(), TYPE_EC, &params, &key_blob, &key_blob_length));
+    EXPECT_GT(key_blob_length, 0);
+
+    free(key_blob);
+}
+
 class NewKeyGeneration : public KeymasterTest {
   protected:
     NewKeyGeneration() {
-        req_.key_description.Reinitialize(key_generation_base_params,
-                                          array_length(key_generation_base_params));
+        params_.Reinitialize(key_generation_base_params, array_length(key_generation_base_params));
     }
 
-    void CheckBaseParams(const GenerateKeyResponse& rsp) {
-        ASSERT_EQ(KM_ERROR_OK, rsp.error);
-        EXPECT_EQ(0U, rsp.enforced.size());
-        EXPECT_EQ(12U, rsp.enforced.SerializedSize());
-        EXPECT_GT(rsp.unenforced.SerializedSize(), 12U);
-
-        EXPECT_TRUE(contains(rsp.unenforced, TAG_PURPOSE, KM_PURPOSE_SIGN));
-        EXPECT_TRUE(contains(rsp.unenforced, TAG_PURPOSE, KM_PURPOSE_VERIFY));
-        EXPECT_TRUE(contains(rsp.unenforced, TAG_USER_ID, 7));
-        EXPECT_TRUE(contains(rsp.unenforced, TAG_USER_AUTH_ID, 8));
-        EXPECT_TRUE(contains(rsp.unenforced, TAG_AUTH_TIMEOUT, 300));
+    void CheckBaseParams(const AuthorizationSet& auths) {
+        EXPECT_TRUE(contains(auths, TAG_PURPOSE, KM_PURPOSE_SIGN));
+        EXPECT_TRUE(contains(auths, TAG_PURPOSE, KM_PURPOSE_VERIFY));
+        EXPECT_TRUE(contains(auths, TAG_USER_ID, 7));
+        EXPECT_TRUE(contains(auths, TAG_USER_AUTH_ID, 8));
+        EXPECT_TRUE(contains(auths, TAG_AUTH_TIMEOUT, 300));
 
         // Verify that App ID, App data and ROT are NOT included.
-        EXPECT_FALSE(contains(rsp.unenforced, TAG_ROOT_OF_TRUST));
-        EXPECT_FALSE(contains(rsp.unenforced, TAG_APPLICATION_ID));
-        EXPECT_FALSE(contains(rsp.unenforced, TAG_APPLICATION_DATA));
+        EXPECT_FALSE(contains(auths, TAG_ROOT_OF_TRUST));
+        EXPECT_FALSE(contains(auths, TAG_APPLICATION_ID));
+        EXPECT_FALSE(contains(auths, TAG_APPLICATION_DATA));
 
         // Just for giggles, check that some unexpected tags/values are NOT present.
-        EXPECT_FALSE(contains(rsp.unenforced, TAG_PURPOSE, KM_PURPOSE_ENCRYPT));
-        EXPECT_FALSE(contains(rsp.unenforced, TAG_PURPOSE, KM_PURPOSE_DECRYPT));
-        EXPECT_FALSE(contains(rsp.unenforced, TAG_AUTH_TIMEOUT, 301));
+        EXPECT_FALSE(contains(auths, TAG_PURPOSE, KM_PURPOSE_ENCRYPT));
+        EXPECT_FALSE(contains(auths, TAG_PURPOSE, KM_PURPOSE_DECRYPT));
+        EXPECT_FALSE(contains(auths, TAG_AUTH_TIMEOUT, 301));
 
         // Now check that unspecified, defaulted tags are correct.
-        EXPECT_TRUE(contains(rsp.unenforced, TAG_ORIGIN, KM_ORIGIN_SOFTWARE));
-        EXPECT_TRUE(contains(rsp.unenforced, KM_TAG_CREATION_DATETIME));
+        EXPECT_TRUE(contains(auths, TAG_ORIGIN, KM_ORIGIN_SOFTWARE));
+        EXPECT_TRUE(contains(auths, KM_TAG_CREATION_DATETIME));
     }
-
-    GenerateKeyRequest req_;
-    GenerateKeyResponse rsp_;
 };
 
+struct ParamListDelete {
+    void operator()(keymaster_key_param_set_t* p) { keymaster_free_param_set(p); }
+};
+
+typedef UniquePtr<keymaster_key_param_set_t, ParamListDelete> UniqueParamSetPtr;
+
 TEST_F(NewKeyGeneration, Rsa) {
-    req_.key_description.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA));
-    req_.key_description.push_back(Authorization(TAG_KEY_SIZE, 256));
-    req_.key_description.push_back(Authorization(TAG_RSA_PUBLIC_EXPONENT, 3));
-    device.GenerateKey(req_, &rsp_);
+    params_.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA));
+    params_.push_back(Authorization(TAG_KEY_SIZE, 256));
+    params_.push_back(Authorization(TAG_RSA_PUBLIC_EXPONENT, 3));
+    ASSERT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(), &blob_,
+                                                  &characteristics_));
+    EXPECT_EQ(0U, characteristics_->hw_enforced.length);
+    AuthorizationSet auths(characteristics_->sw_enforced);
+    CheckBaseParams(auths);
 
-    CheckBaseParams(rsp_);
-
-    // Check specified tags are all present in unenforced characteristics
-    EXPECT_TRUE(contains(rsp_.unenforced, TAG_ALGORITHM, KM_ALGORITHM_RSA));
-    EXPECT_TRUE(contains(rsp_.unenforced, TAG_KEY_SIZE, 256));
-    EXPECT_TRUE(contains(rsp_.unenforced, TAG_RSA_PUBLIC_EXPONENT, 3));
+    // Check specified tags are all present in auths
+    EXPECT_TRUE(contains(auths, TAG_ALGORITHM, KM_ALGORITHM_RSA));
+    EXPECT_TRUE(contains(auths, TAG_KEY_SIZE, 256));
+    EXPECT_TRUE(contains(auths, TAG_RSA_PUBLIC_EXPONENT, 3));
 }
 
 TEST_F(NewKeyGeneration, RsaDefaultSize) {
-    req_.key_description.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA));
-    device.GenerateKey(req_, &rsp_);
+    params_.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA));
+    ASSERT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(), &blob_,
+                                                  &characteristics_));
 
-    CheckBaseParams(rsp_);
+    EXPECT_EQ(0U, characteristics_->hw_enforced.length);
+    AuthorizationSet auths(characteristics_->sw_enforced);
+    CheckBaseParams(auths);
 
-    // Check specified tags are all present in unenforced characteristics
-    EXPECT_TRUE(contains(rsp_.unenforced, TAG_ALGORITHM, KM_ALGORITHM_RSA));
+    // Check specified tags are all present in auths
+    EXPECT_TRUE(contains(auths, TAG_ALGORITHM, KM_ALGORITHM_RSA));
 
     // Now check that unspecified, defaulted tags are correct.
-    EXPECT_TRUE(contains(rsp_.unenforced, TAG_RSA_PUBLIC_EXPONENT, 65537));
-    EXPECT_TRUE(contains(rsp_.unenforced, TAG_KEY_SIZE, 2048));
+    EXPECT_TRUE(contains(auths, TAG_RSA_PUBLIC_EXPONENT, 65537));
+    EXPECT_TRUE(contains(auths, TAG_KEY_SIZE, 2048));
 }
 
 TEST_F(NewKeyGeneration, Ecdsa) {
-    req_.key_description.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
-    req_.key_description.push_back(Authorization(TAG_KEY_SIZE, 224));
-    device.GenerateKey(req_, &rsp_);
+    params_.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
+    params_.push_back(Authorization(TAG_KEY_SIZE, 224));
+    EXPECT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(), &blob_,
+                                                  &characteristics_));
 
-    CheckBaseParams(rsp_);
+    EXPECT_EQ(0U, characteristics_->hw_enforced.length);
+    AuthorizationSet auths(characteristics_->sw_enforced);
+    CheckBaseParams(auths);
 
-    // Check specified tags are all present in unenforced characteristics
-    EXPECT_TRUE(contains(rsp_.unenforced, TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
-    EXPECT_TRUE(contains(rsp_.unenforced, TAG_KEY_SIZE, 224));
+    // Check specified tags are all present in auths characteristics
+    EXPECT_TRUE(contains(auths, TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
+    EXPECT_TRUE(contains(auths, TAG_KEY_SIZE, 224));
 }
 
 TEST_F(NewKeyGeneration, EcdsaDefaultSize) {
-    req_.key_description.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
-    device.GenerateKey(req_, &rsp_);
+    params_.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
+    EXPECT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(), &blob_,
+                                                  &characteristics_));
 
-    CheckBaseParams(rsp_);
+    EXPECT_EQ(0U, characteristics_->hw_enforced.length);
+    AuthorizationSet auths(characteristics_->sw_enforced);
+    CheckBaseParams(auths);
 
-    // Check specified tags are all present in unenforced characteristics
-    EXPECT_TRUE(contains(rsp_.unenforced, TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
+    // Check specified tags are all present in auths
+    EXPECT_TRUE(contains(auths, TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
 
     // Now check that unspecified, defaulted tags are correct.
-    EXPECT_TRUE(contains(rsp_.unenforced, TAG_KEY_SIZE, 224));
+    EXPECT_TRUE(contains(auths, TAG_KEY_SIZE, 224));
 }
 
 TEST_F(NewKeyGeneration, EcdsaInvalidSize) {
-    req_.key_description.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
-    req_.key_description.push_back(Authorization(TAG_KEY_SIZE, 190));
-    device.GenerateKey(req_, &rsp_);
-    ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE, rsp_.error);
+    params_.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
+    params_.push_back(Authorization(TAG_KEY_SIZE, 190));
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE,
+              device()->generate_key(device(), params_.data(), params_.size(), &blob_,
+                                     &characteristics_));
 }
 
 TEST_F(NewKeyGeneration, EcdsaAllValidSizes) {
     size_t valid_sizes[] = {224, 256, 384, 521};
     for (size_t size : valid_sizes) {
-        GenerateKeyResponse rsp;
-        req_.key_description.Reinitialize(key_generation_base_params,
-                                          array_length(key_generation_base_params));
-        req_.key_description.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
-        req_.key_description.push_back(Authorization(TAG_KEY_SIZE, size));
-        device.GenerateKey(req_, &rsp);
-        EXPECT_EQ(KM_ERROR_OK, rsp.error) << "Failed to generate size: " << size;
+        params_.Reinitialize(key_generation_base_params, array_length(key_generation_base_params));
+        params_.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
+        params_.push_back(Authorization(TAG_KEY_SIZE, size));
+        EXPECT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(),
+                                                      &blob_, &characteristics_))
+            << "Failed to generate size: " << size;
+
+        FreeCharacteristics();
+        FreeKeyBlob();
     }
 }
 
@@ -320,9 +426,9 @@
         Authorization(TAG_BLOCK_MODE, KM_MODE_OCB), Authorization(TAG_CHUNK_LENGTH, 4096),
         Authorization(TAG_MAC_LENGTH, 16), Authorization(TAG_PADDING, KM_PAD_NONE),
     };
-    req_.key_description.Reinitialize(params, array_length(params));
-    device.GenerateKey(req_, &rsp_);
-    EXPECT_EQ(KM_ERROR_OK, rsp_.error);
+    params_.Reinitialize(params, array_length(params));
+    EXPECT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(), &blob_,
+                                                  &characteristics_));
 }
 
 TEST_F(NewKeyGeneration, AesOcbInvalidKeySize) {
@@ -333,9 +439,10 @@
         Authorization(TAG_BLOCK_MODE, KM_MODE_OCB), Authorization(TAG_CHUNK_LENGTH, 4096),
         Authorization(TAG_MAC_LENGTH, 16), Authorization(TAG_PADDING, KM_PAD_NONE),
     };
-    req_.key_description.Reinitialize(params, array_length(params));
-    device.GenerateKey(req_, &rsp_);
-    EXPECT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE, rsp_.error);
+    params_.Reinitialize(params, array_length(params));
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE,
+              device()->generate_key(device(), params_.data(), params_.size(), &blob_,
+                                     &characteristics_));
 }
 
 TEST_F(NewKeyGeneration, AesOcbAllValidSizes) {
@@ -349,11 +456,14 @@
 
     size_t valid_sizes[] = {128, 192, 256};
     for (size_t size : valid_sizes) {
-        GenerateKeyResponse rsp;
-        req_.key_description.Reinitialize(params, array_length(params));
-        req_.key_description.push_back(Authorization(TAG_KEY_SIZE, size));
-        device.GenerateKey(req_, &rsp);
-        EXPECT_EQ(KM_ERROR_OK, rsp.error) << "Failed to generate size: " << size;
+        params_.Reinitialize(params, array_length(params));
+        params_.push_back(Authorization(TAG_KEY_SIZE, size));
+        EXPECT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(),
+                                                      &blob_, &characteristics_))
+            << "Failed to generate size: " << size;
+
+        FreeCharacteristics();
+        FreeKeyBlob();
     }
 }
 
@@ -364,9 +474,10 @@
         Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES), Authorization(TAG_KEY_SIZE, 128),
         Authorization(TAG_BLOCK_MODE, KM_MODE_OCB), Authorization(TAG_PADDING, KM_PAD_NONE),
     };
-    req_.key_description.Reinitialize(params, array_length(params));
-    device.GenerateKey(req_, &rsp_);
-    EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, rsp_.error);
+    params_.Reinitialize(params, array_length(params));
+    EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT,
+              device()->generate_key(device(), params_.data(), params_.size(), &blob_,
+                                     &characteristics_));
 }
 
 TEST_F(NewKeyGeneration, AesEcbUnsupported) {
@@ -376,9 +487,10 @@
         Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES), Authorization(TAG_KEY_SIZE, 128),
         Authorization(TAG_BLOCK_MODE, KM_MODE_ECB), Authorization(TAG_PADDING, KM_PAD_NONE),
     };
-    req_.key_description.Reinitialize(params, array_length(params));
-    device.GenerateKey(req_, &rsp_);
-    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE, rsp_.error);
+    params_.Reinitialize(params, array_length(params));
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_BLOCK_MODE,
+              device()->generate_key(device(), params_.data(), params_.size(), &blob_,
+                                     &characteristics_));
 }
 
 TEST_F(NewKeyGeneration, AesOcbPaddingUnsupported) {
@@ -389,9 +501,10 @@
         Authorization(TAG_BLOCK_MODE, KM_MODE_OCB), Authorization(TAG_CHUNK_LENGTH, 4096),
         Authorization(TAG_PADDING, KM_PAD_ZERO),
     };
-    req_.key_description.Reinitialize(params, array_length(params));
-    device.GenerateKey(req_, &rsp_);
-    EXPECT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE, rsp_.error);
+    params_.Reinitialize(params, array_length(params));
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE,
+              device()->generate_key(device(), params_.data(), params_.size(), &blob_,
+                                     &characteristics_));
 }
 
 TEST_F(NewKeyGeneration, AesOcbInvalidMacLength) {
@@ -402,9 +515,10 @@
         Authorization(TAG_BLOCK_MODE, KM_MODE_OCB), Authorization(TAG_CHUNK_LENGTH, 4096),
         Authorization(TAG_MAC_LENGTH, 17), Authorization(TAG_PADDING, KM_PAD_NONE),
     };
-    req_.key_description.Reinitialize(params, array_length(params));
-    device.GenerateKey(req_, &rsp_);
-    EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, rsp_.error);
+    params_.Reinitialize(params, array_length(params));
+    EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT,
+              device()->generate_key(device(), params_.data(), params_.size(), &blob_,
+                                     &characteristics_));
 }
 
 typedef KeymasterTest GetKeyCharacteristics;
@@ -416,23 +530,17 @@
         Authorization(TAG_APPLICATION_ID, "app_id", 6), Authorization(TAG_AUTH_TIMEOUT, 300),
     };
 
-    GenerateKeyRequest gen_req;
-    gen_req.key_description.Reinitialize(params, array_length(params));
-    GenerateKeyResponse gen_rsp;
+    ASSERT_EQ(KM_ERROR_OK, device()->generate_key(device(), params, array_length(params), &blob_,
+                                                  &characteristics_));
+    AuthorizationSet original(characteristics_->sw_enforced);
+    FreeCharacteristics();
 
-    device.GenerateKey(gen_req, &gen_rsp);
-    ASSERT_EQ(KM_ERROR_OK, gen_rsp.error);
-
-    GetKeyCharacteristicsRequest req;
-    req.SetKeyMaterial(gen_rsp.key_blob);
-    req.additional_params.push_back(TAG_APPLICATION_ID, "app_id", 6);
-
-    GetKeyCharacteristicsResponse rsp;
-    device.GetKeyCharacteristics(req, &rsp);
-    ASSERT_EQ(KM_ERROR_OK, rsp.error);
-
-    EXPECT_EQ(gen_rsp.enforced, rsp.enforced);
-    EXPECT_EQ(gen_rsp.unenforced, rsp.unenforced);
+    keymaster_blob_t client_id = {.data = reinterpret_cast<const uint8_t*>("app_id"),
+                                  .data_length = 6};
+    ASSERT_EQ(KM_ERROR_OK,
+              device()->get_key_characteristics(device(), &blob_, &client_id, NULL /* app_data */,
+                                                &characteristics_));
+    EXPECT_EQ(original, AuthorizationSet(characteristics_->sw_enforced));
 }
 
 /**
@@ -440,75 +548,80 @@
  */
 class SigningOperationsTest : public KeymasterTest {
   protected:
+    SigningOperationsTest() : out_params_(NULL), output_(NULL), signature_(NULL) {}
+    ~SigningOperationsTest() {
+        // Clean up so (most) tests won't have to.
+        FreeOutput();
+        FreeSignature();
+    }
+
     void GenerateKey(keymaster_algorithm_t algorithm, keymaster_digest_t digest,
                      keymaster_padding_t padding, uint32_t key_size) {
-        keymaster_key_param_t params[] = {
-            Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
-            Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY), Authorization(TAG_ALGORITHM, algorithm),
-            Authorization(TAG_KEY_SIZE, key_size), Authorization(TAG_USER_ID, 7),
-            Authorization(TAG_USER_AUTH_ID, 8), Authorization(TAG_APPLICATION_ID, "app_id", 6),
-            Authorization(TAG_AUTH_TIMEOUT, 300),
-        };
-        GenerateKeyRequest generate_request;
-        generate_request.key_description.Reinitialize(params, array_length(params));
+        params_.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+        params_.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY));
+        params_.push_back(Authorization(TAG_ALGORITHM, algorithm));
+        params_.push_back(Authorization(TAG_KEY_SIZE, key_size));
+        params_.push_back(Authorization(TAG_USER_ID, 7));
+        params_.push_back(Authorization(TAG_USER_AUTH_ID, 8));
+        params_.push_back(Authorization(TAG_APPLICATION_ID, "app_id", 6));
+        params_.push_back(Authorization(TAG_AUTH_TIMEOUT, 300));
         if (static_cast<int>(digest) != -1)
-            generate_request.key_description.push_back(TAG_DIGEST, digest);
+            params_.push_back(TAG_DIGEST, digest);
         if (static_cast<int>(padding) != -1)
-            generate_request.key_description.push_back(TAG_PADDING, padding);
-        device.GenerateKey(generate_request, &generate_response_);
-        EXPECT_EQ(KM_ERROR_OK, generate_response_.error);
+            params_.push_back(TAG_PADDING, padding);
+
+        EXPECT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(),
+                                                      &blob_, &characteristics_));
     }
 
     void SignMessage(const void* message, size_t size) {
-        SignMessage(generate_response_.key_blob, message, size);
+        EXPECT_EQ(KM_ERROR_OK, device()->begin(device(), KM_PURPOSE_SIGN, &blob_, client_params_,
+                                               array_length(client_params_), &out_params_,
+                                               &out_params_count_, &op_handle_));
+
+        EXPECT_EQ(KM_ERROR_OK,
+                  device()->update(device(), op_handle_, reinterpret_cast<const uint8_t*>(message),
+                                   size, &input_consumed_, &output_, &output_length_));
+        EXPECT_EQ(0, output_length_);
+        FreeOutput();
+        EXPECT_EQ(size, input_consumed_);
+
+        EXPECT_EQ(KM_ERROR_OK,
+                  device()->finish(device(), op_handle_, NULL /* signature to verify */,
+                                   0 /* signature to verify length */, &signature_,
+                                   &signature_length_));
+        EXPECT_GT(signature_length_, 0);
     }
 
-    void SignMessage(const keymaster_key_blob_t& key_blob, const void* message, size_t size) {
-        BeginOperationRequest begin_request;
-        BeginOperationResponse begin_response;
-        begin_request.SetKeyMaterial(key_blob);
-        begin_request.purpose = KM_PURPOSE_SIGN;
-        AddClientParams(&begin_request.additional_params);
-
-        device.BeginOperation(begin_request, &begin_response);
-        ASSERT_EQ(KM_ERROR_OK, begin_response.error);
-
-        UpdateOperationRequest update_request;
-        UpdateOperationResponse update_response;
-        update_request.op_handle = begin_response.op_handle;
-        update_request.input.Reinitialize(message, size);
-        EXPECT_EQ(size, update_request.input.available_read());
-
-        device.UpdateOperation(update_request, &update_response);
-        ASSERT_EQ(KM_ERROR_OK, update_response.error);
-        EXPECT_EQ(0U, update_response.output.available_read());
-        EXPECT_EQ(size, update_response.input_consumed);
-
-        FinishOperationRequest finish_request;
-        finish_request.op_handle = begin_response.op_handle;
-        device.FinishOperation(finish_request, &finish_response_);
-        ASSERT_EQ(KM_ERROR_OK, finish_response_.error);
-        EXPECT_GT(finish_response_.output.available_read(), 0U);
+    void FreeOutput() {
+        free(out_params_);
+        out_params_ = NULL;
+        free(output_);
+        output_ = NULL;
     }
 
-    void AddClientParams(AuthorizationSet* set) { set->push_back(TAG_APPLICATION_ID, "app_id", 6); }
-
-    const keymaster_key_blob_t& key_blob() { return generate_response_.key_blob; }
-
-    const keymaster_key_blob_t& corrupt_key_blob() {
-        uint8_t* tmp = const_cast<uint8_t*>(generate_response_.key_blob.key_material);
-        ++tmp[generate_response_.key_blob.key_material_size / 2];
-        return generate_response_.key_blob;
+    void FreeSignature() {
+        free(signature_);
+        signature_ = NULL;
     }
 
-    Buffer* signature() {
-        if (finish_response_.error == KM_ERROR_OK)
-            return &finish_response_.output;
-        return NULL;
+    void corrupt_key_blob() {
+        uint8_t* tmp = const_cast<uint8_t*>(blob_.key_material);
+        ++tmp[blob_.key_material_size / 2];
     }
 
-    GenerateKeyResponse generate_response_;
-    FinishOperationResponse finish_response_;
+    keymaster_blob_t client_id_ = {.data = reinterpret_cast<const uint8_t*>("app_id"),
+                                   .data_length = 6};
+    keymaster_key_param_t client_params_[1] = {
+        Authorization(TAG_APPLICATION_ID, client_id_.data, client_id_.data_length)};
+    keymaster_key_param_t* out_params_;
+    size_t out_params_count_;
+    uint64_t op_handle_;
+    size_t input_consumed_;
+    uint8_t* output_;
+    size_t output_length_;
+    uint8_t* signature_;
+    size_t signature_length_;
 };
 
 TEST_F(SigningOperationsTest, RsaSuccess) {
@@ -525,157 +638,90 @@
 
 TEST_F(SigningOperationsTest, RsaAbort) {
     GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_NONE, 256 /* key size */);
+    ASSERT_EQ(KM_ERROR_OK, device()->begin(device(), KM_PURPOSE_SIGN, &blob_, client_params_,
+                                           array_length(client_params_), &out_params_,
+                                           &out_params_count_, &op_handle_));
 
-    BeginOperationRequest begin_request;
-    BeginOperationResponse begin_response;
-    begin_request.SetKeyMaterial(key_blob());
-    begin_request.purpose = KM_PURPOSE_SIGN;
-    AddClientParams(&begin_request.additional_params);
-
-    device.BeginOperation(begin_request, &begin_response);
-    ASSERT_EQ(KM_ERROR_OK, begin_response.error);
-
-    EXPECT_EQ(KM_ERROR_OK, device.AbortOperation(begin_response.op_handle));
-
-    // Another abort should fail
-    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
+    EXPECT_EQ(KM_ERROR_OK, device()->abort(device(), op_handle_));
+    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device()->abort(device(), op_handle_));
 }
 
 TEST_F(SigningOperationsTest, RsaUnsupportedDigest) {
     GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_SHA_2_256, KM_PAD_NONE, 256 /* key size */);
-
-    BeginOperationRequest begin_request;
-    BeginOperationResponse begin_response;
-    begin_request.purpose = KM_PURPOSE_SIGN;
-    begin_request.SetKeyMaterial(key_blob());
-    AddClientParams(&begin_request.additional_params);
-
-    device.BeginOperation(begin_request, &begin_response);
-    ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST, begin_response.error);
-
-    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST,
+              device()->begin(device(), KM_PURPOSE_SIGN, &blob_, client_params_,
+                              array_length(client_params_), &out_params_, &out_params_count_,
+                              &op_handle_));
+    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device()->abort(device(), op_handle_));
 }
 
 TEST_F(SigningOperationsTest, RsaUnsupportedPadding) {
     GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_RSA_OAEP, 256 /* key size */);
-
-    BeginOperationRequest begin_request;
-    BeginOperationResponse begin_response;
-    begin_request.purpose = KM_PURPOSE_SIGN;
-    begin_request.SetKeyMaterial(key_blob());
-    AddClientParams(&begin_request.additional_params);
-
-    device.BeginOperation(begin_request, &begin_response);
-    ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE, begin_response.error);
-
-    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE,
+              device()->begin(device(), KM_PURPOSE_SIGN, &blob_, client_params_,
+                              array_length(client_params_), &out_params_, &out_params_count_,
+                              &op_handle_));
+    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device()->abort(device(), op_handle_));
 }
 
 TEST_F(SigningOperationsTest, RsaNoDigest) {
     GenerateKey(KM_ALGORITHM_RSA, static_cast<keymaster_digest_t>(-1), KM_PAD_NONE,
                 256 /* key size */);
-
-    BeginOperationRequest begin_request;
-    BeginOperationResponse begin_response;
-    begin_request.purpose = KM_PURPOSE_SIGN;
-    begin_request.SetKeyMaterial(key_blob());
-    AddClientParams(&begin_request.additional_params);
-
-    device.BeginOperation(begin_request, &begin_response);
-    ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST, begin_response.error);
-
-    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST,
+              device()->begin(device(), KM_PURPOSE_SIGN, &blob_, client_params_,
+                              array_length(client_params_), &out_params_, &out_params_count_,
+                              &op_handle_));
+    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device()->abort(device(), op_handle_));
 }
 
 TEST_F(SigningOperationsTest, RsaNoPadding) {
     GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, static_cast<keymaster_padding_t>(-1),
                 256 /* key size */);
-
-    BeginOperationRequest begin_request;
-    BeginOperationResponse begin_response;
-    begin_request.purpose = KM_PURPOSE_SIGN;
-    begin_request.SetKeyMaterial(key_blob());
-    AddClientParams(&begin_request.additional_params);
-
-    device.BeginOperation(begin_request, &begin_response);
-    ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE, begin_response.error);
-
-    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE,
+              device()->begin(device(), KM_PURPOSE_SIGN, &blob_, client_params_,
+                              array_length(client_params_), &out_params_, &out_params_count_,
+                              &op_handle_));
+    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device()->abort(device(), op_handle_));
 }
 
 TEST_F(SigningOperationsTest, RsaTooShortMessage) {
     GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_NONE, 256 /* key size */);
+    ASSERT_EQ(KM_ERROR_OK, device()->begin(device(), KM_PURPOSE_SIGN, &blob_, client_params_,
+                                           array_length(client_params_), &out_params_,
+                                           &out_params_count_, &op_handle_));
+    ASSERT_EQ(KM_ERROR_OK,
+              device()->update(device(), op_handle_,
+                               reinterpret_cast<const uint8_t*>("01234567890123456789012345678901"),
+                               31, &input_consumed_, &output_, &output_length_));
+    EXPECT_EQ(0U, output_length_);
+    EXPECT_EQ(31U, input_consumed_);
 
-    BeginOperationRequest begin_request;
-    BeginOperationResponse begin_response;
-    begin_request.SetKeyMaterial(key_blob());
-    begin_request.purpose = KM_PURPOSE_SIGN;
-    AddClientParams(&begin_request.additional_params);
+    ASSERT_EQ(KM_ERROR_UNKNOWN_ERROR,
+              device()->finish(device(), op_handle_, NULL, 0, &signature_, &signature_length_));
 
-    device.BeginOperation(begin_request, &begin_response);
-    ASSERT_EQ(KM_ERROR_OK, begin_response.error);
-
-    UpdateOperationRequest update_request;
-    UpdateOperationResponse update_response;
-    update_request.op_handle = begin_response.op_handle;
-    update_request.input.Reinitialize("01234567890123456789012345678901", 31);
-    EXPECT_EQ(31U, update_request.input.available_read());
-
-    device.UpdateOperation(update_request, &update_response);
-    ASSERT_EQ(KM_ERROR_OK, update_response.error);
-    EXPECT_EQ(0U, update_response.output.available_read());
-    EXPECT_EQ(31U, update_response.input_consumed);
-
-    FinishOperationRequest finish_request;
-    finish_request.op_handle = begin_response.op_handle;
-    FinishOperationResponse finish_response;
-    device.FinishOperation(finish_request, &finish_response);
-    ASSERT_EQ(KM_ERROR_UNKNOWN_ERROR, finish_response.error);
-    EXPECT_EQ(0U, finish_response.output.available_read());
-
-    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
+    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device()->abort(device(), op_handle_));
 }
 
 class VerificationOperationsTest : public SigningOperationsTest {
   protected:
     void VerifyMessage(const void* message, size_t message_len) {
-        VerifyMessage(generate_response_.key_blob, message, message_len);
-    }
+        EXPECT_TRUE(signature_ != NULL);
 
-    void VerifyMessage(const keymaster_key_blob_t& key_blob, const void* message,
-                       size_t message_len) {
-        ASSERT_TRUE(signature() != NULL);
+        EXPECT_EQ(KM_ERROR_OK, device()->begin(device(), KM_PURPOSE_VERIFY, &blob_, client_params_,
+                                               array_length(client_params_), &out_params_,
+                                               &out_params_count_, &op_handle_));
+        ASSERT_EQ(KM_ERROR_OK,
+                  device()->update(device(), op_handle_, reinterpret_cast<const uint8_t*>(message),
+                                   message_len, &input_consumed_, &output_, &output_length_));
+        EXPECT_EQ(0U, output_length_);
+        FreeOutput();
+        EXPECT_EQ(message_len, input_consumed_);
 
-        BeginOperationRequest begin_request;
-        BeginOperationResponse begin_response;
-        begin_request.SetKeyMaterial(key_blob);
-        begin_request.purpose = KM_PURPOSE_VERIFY;
-        AddClientParams(&begin_request.additional_params);
+        ASSERT_EQ(KM_ERROR_OK, device()->finish(device(), op_handle_, signature_, signature_length_,
+                                                &output_, &output_length_));
+        EXPECT_EQ(0U, output_length_);
 
-        device.BeginOperation(begin_request, &begin_response);
-        ASSERT_EQ(KM_ERROR_OK, begin_response.error);
-
-        UpdateOperationRequest update_request;
-        UpdateOperationResponse update_response;
-        update_request.op_handle = begin_response.op_handle;
-        update_request.input.Reinitialize(message, message_len);
-        EXPECT_EQ(message_len, update_request.input.available_read());
-
-        device.UpdateOperation(update_request, &update_response);
-        ASSERT_EQ(KM_ERROR_OK, update_response.error);
-        EXPECT_EQ(0U, update_response.output.available_read());
-        EXPECT_EQ(message_len, update_response.input_consumed);
-
-        FinishOperationRequest finish_request;
-        finish_request.op_handle = begin_response.op_handle;
-        finish_request.signature.Reinitialize(*signature());
-        FinishOperationResponse finish_response;
-        device.FinishOperation(finish_request, &finish_response);
-        ASSERT_EQ(KM_ERROR_OK, finish_response.error);
-        EXPECT_EQ(0U, finish_response.output.available_read());
-
-        EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE,
-                  device.AbortOperation(begin_response.op_handle));
+        EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device()->abort(device(), op_handle_));
     }
 };
 
@@ -693,67 +739,60 @@
     VerifyMessage(message, array_size(message) - 1);
 }
 
-typedef SigningOperationsTest ExportKeyTest;
+typedef VerificationOperationsTest ExportKeyTest;
 TEST_F(ExportKeyTest, RsaSuccess) {
     GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_NONE, 256 /* key size */);
 
-    ExportKeyRequest request;
-    ExportKeyResponse response;
-    AddClientParams(&request.additional_params);
-    request.key_format = KM_KEY_FORMAT_X509;
-    request.SetKeyMaterial(key_blob());
-
-    device.ExportKey(request, &response);
-    ASSERT_EQ(KM_ERROR_OK, response.error);
-    EXPECT_TRUE(response.key_data != NULL);
+    uint8_t* export_data;
+    size_t export_data_length;
+    ASSERT_EQ(KM_ERROR_OK,
+              device()->export_key(device(), KM_KEY_FORMAT_X509, &blob_, &client_id_,
+                                   NULL /* app_data */, &export_data, &export_data_length));
+    EXPECT_TRUE(export_data != NULL);
+    EXPECT_GT(export_data_length, 0);
 
     // TODO(swillden): Verify that the exported key is actually usable to verify signatures.
+    free(export_data);
 }
 
 TEST_F(ExportKeyTest, EcdsaSuccess) {
     GenerateKey(KM_ALGORITHM_ECDSA, KM_DIGEST_NONE, KM_PAD_NONE, 224 /* key size */);
 
-    ExportKeyRequest request;
-    ExportKeyResponse response;
-    AddClientParams(&request.additional_params);
-    request.key_format = KM_KEY_FORMAT_X509;
-    request.SetKeyMaterial(key_blob());
-
-    device.ExportKey(request, &response);
-    ASSERT_EQ(KM_ERROR_OK, response.error);
-    EXPECT_TRUE(response.key_data != NULL);
+    uint8_t* export_data;
+    size_t export_data_length;
+    ASSERT_EQ(KM_ERROR_OK,
+              device()->export_key(device(), KM_KEY_FORMAT_X509, &blob_, &client_id_,
+                                   NULL /* app_data */, &export_data, &export_data_length));
+    EXPECT_TRUE(export_data != NULL);
+    EXPECT_GT(export_data_length, 0);
 
     // TODO(swillden): Verify that the exported key is actually usable to verify signatures.
+    free(export_data);
 }
 
 TEST_F(ExportKeyTest, RsaUnsupportedKeyFormat) {
     GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_NONE, 256);
 
-    ExportKeyRequest request;
-    ExportKeyResponse response;
-    AddClientParams(&request.additional_params);
-
-    /* We have no other defined export formats defined. */
-    request.key_format = KM_KEY_FORMAT_PKCS8;
-    request.SetKeyMaterial(key_blob());
-
-    device.ExportKey(request, &response);
-    ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT, response.error);
-    EXPECT_TRUE(response.key_data == NULL);
+    uint8_t dummy[] = {1};
+    uint8_t* export_data = dummy;  // So it's not NULL;
+    size_t export_data_length;
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT,
+              device()->export_key(device(), KM_KEY_FORMAT_PKCS8, &blob_, &client_id_,
+                                   NULL /* app_data */, &export_data, &export_data_length));
+    ASSERT_TRUE(export_data == NULL);
 }
 
 TEST_F(ExportKeyTest, RsaCorruptedKeyBlob) {
     GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_NONE, 256);
+    corrupt_key_blob();
 
-    ExportKeyRequest request;
-    ExportKeyResponse response;
-    AddClientParams(&request.additional_params);
-    request.key_format = KM_KEY_FORMAT_X509;
-    request.SetKeyMaterial(corrupt_key_blob());
-
-    device.ExportKey(request, &response);
-    ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, response.error);
-    ASSERT_TRUE(response.key_data == NULL);
+    uint8_t dummy[] = {1};
+    uint8_t* export_data = dummy;  // So it's not NULL
+    size_t export_data_length;
+    ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+              device()->export_key(device(), KM_KEY_FORMAT_X509, &blob_, &client_id_,
+                                   NULL /* app_data */, &export_data, &export_data_length));
+    ASSERT_TRUE(export_data == NULL);
 }
 
 static string read_file(const string& file_name) {
@@ -763,194 +802,114 @@
     return string(file_begin, file_end);
 }
 
-typedef VerificationOperationsTest ImportKeyTest;
-TEST_F(ImportKeyTest, RsaSuccess) {
-    keymaster_key_param_t params[] = {
-        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
-        Authorization(TAG_DIGEST, KM_DIGEST_NONE), Authorization(TAG_PADDING, KM_PAD_NONE),
-        Authorization(TAG_USER_ID, 7), Authorization(TAG_USER_AUTH_ID, 8),
-        Authorization(TAG_APPLICATION_ID, "app_id", 6), Authorization(TAG_AUTH_TIMEOUT, 300),
-    };
+class ImportKeyTest : public VerificationOperationsTest {
+  protected:
+    ImportKeyTest() {
+        params_.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+        params_.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY));
+        params_.push_back(Authorization(TAG_DIGEST, KM_DIGEST_NONE));
+        params_.push_back(Authorization(TAG_PADDING, KM_PAD_NONE));
+        params_.push_back(Authorization(TAG_USER_ID, 7));
+        params_.push_back(Authorization(TAG_USER_AUTH_ID, 8));
+        params_.push_back(Authorization(TAG_APPLICATION_ID, "app_id", 6));
+        params_.push_back(Authorization(TAG_AUTH_TIMEOUT, 300));
+    }
+};
 
+TEST_F(ImportKeyTest, RsaSuccess) {
     string pk8_key = read_file("rsa_privkey_pk8.der");
     ASSERT_EQ(633U, pk8_key.size());
 
-    ImportKeyRequest import_request;
-    import_request.key_description.Reinitialize(params, array_length(params));
-    import_request.key_format = KM_KEY_FORMAT_PKCS8;
-    import_request.SetKeyMaterial(pk8_key.data(), pk8_key.size());
-
-    ImportKeyResponse import_response;
-    device.ImportKey(import_request, &import_response);
-    ASSERT_EQ(KM_ERROR_OK, import_response.error);
-    EXPECT_EQ(0U, import_response.enforced.size());
-    EXPECT_GT(import_response.unenforced.size(), 0U);
+    ASSERT_EQ(KM_ERROR_OK,
+              device()->import_key(device(), params_.data(), params_.size(), KM_KEY_FORMAT_PKCS8,
+                                   reinterpret_cast<const uint8_t*>(pk8_key.data()), pk8_key.size(),
+                                   &blob_, &characteristics_));
+    EXPECT_EQ(0U, characteristics_->hw_enforced.length);
+    AuthorizationSet auths(characteristics_->sw_enforced);
 
     // Check values derived from the key.
-    EXPECT_TRUE(contains(import_response.unenforced, TAG_ALGORITHM, KM_ALGORITHM_RSA));
-    EXPECT_TRUE(contains(import_response.unenforced, TAG_KEY_SIZE, 1024));
-    EXPECT_TRUE(contains(import_response.unenforced, TAG_RSA_PUBLIC_EXPONENT, 65537U));
+    EXPECT_TRUE(contains(auths, TAG_ALGORITHM, KM_ALGORITHM_RSA));
+    EXPECT_TRUE(contains(auths, TAG_KEY_SIZE, 1024));
+    EXPECT_TRUE(contains(auths, TAG_RSA_PUBLIC_EXPONENT, 65537U));
 
     // And values provided by GoogleKeymaster
-    EXPECT_TRUE(contains(import_response.unenforced, TAG_ORIGIN, KM_ORIGIN_IMPORTED));
-    EXPECT_TRUE(contains(import_response.unenforced, KM_TAG_CREATION_DATETIME));
+    EXPECT_TRUE(contains(auths, TAG_ORIGIN, KM_ORIGIN_IMPORTED));
+    EXPECT_TRUE(contains(auths, KM_TAG_CREATION_DATETIME));
 
     size_t message_len = 1024 / 8;
     UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
     std::fill(message.get(), message.get() + message_len, 'a');
-    SignMessage(import_response.key_blob, message.get(), message_len);
-    ASSERT_TRUE(signature() != NULL);
-    VerifyMessage(import_response.key_blob, message.get(), message_len);
+    SignMessage(message.get(), message_len);
+    VerifyMessage(message.get(), message_len);
 }
 
 TEST_F(ImportKeyTest, RsaKeySizeMismatch) {
-    keymaster_key_param_t params[] = {
-        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
-        Authorization(TAG_DIGEST, KM_DIGEST_NONE), Authorization(TAG_PADDING, KM_PAD_NONE),
-        Authorization(TAG_KEY_SIZE, 2048),  // Doesn't match key
-        Authorization(TAG_USER_ID, 7), Authorization(TAG_USER_AUTH_ID, 8),
-        Authorization(TAG_APPLICATION_ID, "app_id", 6), Authorization(TAG_AUTH_TIMEOUT, 300),
-    };
+    params_.push_back(Authorization(TAG_KEY_SIZE, 2048));  // Doesn't match key
 
     string pk8_key = read_file("rsa_privkey_pk8.der");
     ASSERT_EQ(633U, pk8_key.size());
 
-    ImportKeyRequest import_request;
-    import_request.key_description.Reinitialize(params, array_length(params));
-    import_request.key_format = KM_KEY_FORMAT_PKCS8;
-    import_request.SetKeyMaterial(pk8_key.data(), pk8_key.size());
-
-    ImportKeyResponse import_response;
-    device.ImportKey(import_request, &import_response);
-    ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH, import_response.error);
+    ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH,
+              device()->import_key(device(), params_.data(), params_.size(), KM_KEY_FORMAT_PKCS8,
+                                   reinterpret_cast<const uint8_t*>(pk8_key.data()), pk8_key.size(),
+                                   &blob_, &characteristics_));
 }
 
 TEST_F(ImportKeyTest, RsaPublicExponenMismatch) {
-    keymaster_key_param_t params[] = {
-        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
-        Authorization(TAG_DIGEST, KM_DIGEST_NONE), Authorization(TAG_PADDING, KM_PAD_NONE),
-        Authorization(TAG_RSA_PUBLIC_EXPONENT, 3), Authorization(TAG_USER_ID, 7),
-        Authorization(TAG_USER_AUTH_ID, 8), Authorization(TAG_APPLICATION_ID, "app_id", 6),
-        Authorization(TAG_AUTH_TIMEOUT, 300),
-    };
+    params_.push_back(Authorization(TAG_RSA_PUBLIC_EXPONENT, 3));  // Doesn't match key
 
     string pk8_key = read_file("rsa_privkey_pk8.der");
     ASSERT_EQ(633U, pk8_key.size());
 
-    ImportKeyRequest import_request;
-    import_request.key_description.Reinitialize(params, array_length(params));
-    import_request.key_format = KM_KEY_FORMAT_PKCS8;
-    import_request.SetKeyMaterial(pk8_key.data(), pk8_key.size());
-
-    ImportKeyResponse import_response;
-    device.ImportKey(import_request, &import_response);
-    ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH, import_response.error);
+    ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH,
+              device()->import_key(device(), params_.data(), params_.size(), KM_KEY_FORMAT_PKCS8,
+                                   reinterpret_cast<const uint8_t*>(pk8_key.data()), pk8_key.size(),
+                                   &blob_, &characteristics_));
 }
 
 TEST_F(ImportKeyTest, EcdsaSuccess) {
-    keymaster_key_param_t params[] = {
-        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
-        Authorization(TAG_DIGEST, KM_DIGEST_NONE), Authorization(TAG_PADDING, KM_PAD_NONE),
-        Authorization(TAG_USER_ID, 7), Authorization(TAG_USER_AUTH_ID, 8),
-        Authorization(TAG_APPLICATION_ID, "app_id", 6), Authorization(TAG_AUTH_TIMEOUT, 300),
-    };
-
     string pk8_key = read_file("ec_privkey_pk8.der");
     ASSERT_EQ(138U, pk8_key.size());
 
-    ImportKeyRequest import_request;
-    import_request.key_description.Reinitialize(params, array_length(params));
-    import_request.key_format = KM_KEY_FORMAT_PKCS8;
-    import_request.SetKeyMaterial(pk8_key.data(), pk8_key.size());
-
-    ImportKeyResponse import_response;
-    device.ImportKey(import_request, &import_response);
-    ASSERT_EQ(KM_ERROR_OK, import_response.error);
-    EXPECT_EQ(0U, import_response.enforced.size());
-    EXPECT_GT(import_response.unenforced.size(), 0U);
+    ASSERT_EQ(KM_ERROR_OK,
+              device()->import_key(device(), params_.data(), params_.size(), KM_KEY_FORMAT_PKCS8,
+                                   reinterpret_cast<const uint8_t*>(pk8_key.data()), pk8_key.size(),
+                                   &blob_, &characteristics_));
+    EXPECT_EQ(0U, characteristics_->hw_enforced.length);
+    AuthorizationSet auths(characteristics_->sw_enforced);
 
     // Check values derived from the key.
-    EXPECT_TRUE(contains(import_response.unenforced, TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
-    EXPECT_TRUE(contains(import_response.unenforced, TAG_KEY_SIZE, 256));
+    EXPECT_TRUE(contains(auths, TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
+    EXPECT_TRUE(contains(auths, TAG_KEY_SIZE, 256));
 
     // And values provided by GoogleKeymaster
-    EXPECT_TRUE(contains(import_response.unenforced, TAG_ORIGIN, KM_ORIGIN_IMPORTED));
-    EXPECT_TRUE(contains(import_response.unenforced, KM_TAG_CREATION_DATETIME));
+    EXPECT_TRUE(contains(auths, TAG_ORIGIN, KM_ORIGIN_IMPORTED));
+    EXPECT_TRUE(contains(auths, KM_TAG_CREATION_DATETIME));
 
-    size_t message_len = 1024 / 8;
+    size_t message_len = 1024;
     UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
     std::fill(message.get(), message.get() + message_len, 'a');
-    SignMessage(import_response.key_blob, message.get(), message_len);
-    ASSERT_TRUE(signature() != NULL);
-    VerifyMessage(import_response.key_blob, message.get(), message_len);
+    SignMessage(message.get(), message_len);
+    VerifyMessage(message.get(), message_len);
 }
 
-TEST_F(ImportKeyTest, EcdsaSizeSpecified) {
-    keymaster_key_param_t params[] = {
-        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
-        Authorization(TAG_DIGEST, KM_DIGEST_NONE), Authorization(TAG_PADDING, KM_PAD_NONE),
-        Authorization(TAG_USER_ID, 7), Authorization(TAG_USER_AUTH_ID, 8),
-        Authorization(TAG_APPLICATION_ID, "app_id", 6), Authorization(TAG_AUTH_TIMEOUT, 300),
-        Authorization(TAG_KEY_SIZE, 256),
-    };
+TEST_F(ImportKeyTest, EcdsaKeySizeMismatch) {
+    params_.push_back(Authorization(TAG_KEY_SIZE, 224));  // Doesn't match key
 
-    string pk8_key = read_file("ec_privkey_pk8.der");
-    ASSERT_EQ(138U, pk8_key.size());
+    string pk8_key = read_file("rsa_privkey_pk8.der");
+    ASSERT_EQ(633U, pk8_key.size());
 
-    ImportKeyRequest import_request;
-    import_request.key_description.Reinitialize(params, array_length(params));
-    import_request.key_format = KM_KEY_FORMAT_PKCS8;
-    import_request.SetKeyMaterial(pk8_key.data(), pk8_key.size());
-
-    ImportKeyResponse import_response;
-    device.ImportKey(import_request, &import_response);
-    ASSERT_EQ(KM_ERROR_OK, import_response.error);
-    EXPECT_EQ(0U, import_response.enforced.size());
-    EXPECT_GT(import_response.unenforced.size(), 0U);
-
-    // Check values derived from the key.
-    EXPECT_TRUE(contains(import_response.unenforced, TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
-    EXPECT_TRUE(contains(import_response.unenforced, TAG_KEY_SIZE, 256));
-
-    // And values provided by GoogleKeymaster
-    EXPECT_TRUE(contains(import_response.unenforced, TAG_ORIGIN, KM_ORIGIN_IMPORTED));
-    EXPECT_TRUE(contains(import_response.unenforced, KM_TAG_CREATION_DATETIME));
-
-    size_t message_len = 1024 / 8;
-    UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
-    std::fill(message.get(), message.get() + message_len, 'a');
-    SignMessage(import_response.key_blob, message.get(), message_len);
-    ASSERT_TRUE(signature() != NULL);
-    VerifyMessage(import_response.key_blob, message.get(), message_len);
-}
-
-TEST_F(ImportKeyTest, EcdsaSizeMismatch) {
-    keymaster_key_param_t params[] = {
-        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
-        Authorization(TAG_DIGEST, KM_DIGEST_NONE), Authorization(TAG_PADDING, KM_PAD_NONE),
-        Authorization(TAG_USER_ID, 7), Authorization(TAG_USER_AUTH_ID, 8),
-        Authorization(TAG_APPLICATION_ID, "app_id", 6), Authorization(TAG_AUTH_TIMEOUT, 300),
-        Authorization(TAG_KEY_SIZE, 224),
-    };
-
-    string pk8_key = read_file("ec_privkey_pk8.der");
-    ASSERT_EQ(138U, pk8_key.size());
-
-    ImportKeyRequest import_request;
-    import_request.key_description.Reinitialize(params, array_length(params));
-    import_request.key_format = KM_KEY_FORMAT_PKCS8;
-    import_request.SetKeyMaterial(pk8_key.data(), pk8_key.size());
-
-    ImportKeyResponse import_response;
-    device.ImportKey(import_request, &import_response);
-    ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH, import_response.error);
+    ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH,
+              device()->import_key(device(), params_.data(), params_.size(), KM_KEY_FORMAT_PKCS8,
+                                   reinterpret_cast<const uint8_t*>(pk8_key.data()), pk8_key.size(),
+                                   &blob_, &characteristics_));
 }
 
 typedef KeymasterTest VersionTest;
 TEST_F(VersionTest, GetVersion) {
     GetVersionRequest req;
     GetVersionResponse rsp;
-    device.GetVersion(req, &rsp);
+    device_.GetVersion(req, &rsp);
     EXPECT_EQ(KM_ERROR_OK, rsp.error);
     EXPECT_EQ(1, rsp.major_ver);
     EXPECT_EQ(0, rsp.minor_ver);
@@ -964,75 +923,67 @@
   protected:
     void GenerateKey(keymaster_algorithm_t algorithm, keymaster_padding_t padding,
                      uint32_t key_size) {
-        keymaster_key_param_t params[] = {
-            Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT),
-            Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT), Authorization(TAG_ALGORITHM, algorithm),
-            Authorization(TAG_KEY_SIZE, key_size), Authorization(TAG_USER_ID, 7),
-            Authorization(TAG_USER_AUTH_ID, 8), Authorization(TAG_APPLICATION_ID, "app_id", 6),
-            Authorization(TAG_AUTH_TIMEOUT, 300),
-        };
-        GenerateKeyRequest generate_request;
-        generate_request.key_description.Reinitialize(params, array_length(params));
+        params_.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT));
+        params_.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT));
+        params_.push_back(Authorization(TAG_ALGORITHM, algorithm));
+        params_.push_back(Authorization(TAG_KEY_SIZE, key_size));
+        params_.push_back(Authorization(TAG_USER_ID, 7));
+        params_.push_back(Authorization(TAG_USER_AUTH_ID, 8));
+        params_.push_back(Authorization(TAG_APPLICATION_ID, "app_id", 6));
+        params_.push_back(Authorization(TAG_AUTH_TIMEOUT, 300));
         if (static_cast<int>(padding) != -1)
-            generate_request.key_description.push_back(TAG_PADDING, padding);
-        device.GenerateKey(generate_request, &generate_response_);
-        EXPECT_EQ(KM_ERROR_OK, generate_response_.error);
+            params_.push_back(TAG_PADDING, padding);
+        EXPECT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(),
+                                                      &blob_, &characteristics_));
     }
 
     void GenerateSymmetricKey(keymaster_algorithm_t algorithm, uint32_t key_size,
                               keymaster_block_mode_t block_mode, uint32_t chunk_length) {
-        keymaster_key_param_t params[] = {
-            Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT),
-            Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT), Authorization(TAG_ALGORITHM, algorithm),
-            Authorization(TAG_BLOCK_MODE, block_mode),
-            Authorization(TAG_CHUNK_LENGTH, chunk_length), Authorization(TAG_KEY_SIZE, key_size),
-            Authorization(TAG_MAC_LENGTH, 16), Authorization(TAG_USER_ID, 7),
-            Authorization(TAG_USER_AUTH_ID, 8), Authorization(TAG_APPLICATION_ID, "app_id", 6),
-            Authorization(TAG_AUTH_TIMEOUT, 300),
-        };
-        GenerateKeyRequest generate_request;
-        generate_request.key_description.Reinitialize(params, array_length(params));
-        device.GenerateKey(generate_request, &generate_response_);
-        EXPECT_EQ(KM_ERROR_OK, generate_response_.error);
+        params_.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT));
+        params_.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT));
+        params_.push_back(Authorization(TAG_ALGORITHM, algorithm));
+        params_.push_back(Authorization(TAG_BLOCK_MODE, block_mode));
+        params_.push_back(Authorization(TAG_CHUNK_LENGTH, chunk_length));
+        params_.push_back(Authorization(TAG_KEY_SIZE, key_size));
+        params_.push_back(Authorization(TAG_MAC_LENGTH, 16));
+        params_.push_back(Authorization(TAG_USER_ID, 7));
+        params_.push_back(Authorization(TAG_USER_AUTH_ID, 8));
+        params_.push_back(Authorization(TAG_APPLICATION_ID, "app_id", 6));
+        params_.push_back(Authorization(TAG_AUTH_TIMEOUT, 300));
+
+        EXPECT_EQ(KM_ERROR_OK, device()->generate_key(device(), params_.data(), params_.size(),
+                                                      &blob_, &characteristics_));
     }
 
     keymaster_error_t BeginOperation(keymaster_purpose_t purpose,
                                      const keymaster_key_blob_t& key_blob, uint64_t* op_handle) {
-        BeginOperationRequest begin_request;
-        begin_request.SetKeyMaterial(key_blob);
-        begin_request.purpose = purpose;
-        AddClientParams(&begin_request.additional_params);
-
-        BeginOperationResponse begin_response;
-        device.BeginOperation(begin_request, &begin_response);
-        *op_handle = begin_response.op_handle;
-        return begin_response.error;
+        return device()->begin(device(), purpose, &key_blob, client_params_,
+                               array_length(client_params_), &out_params_, &out_params_count_,
+                               op_handle);
     }
 
     keymaster_error_t UpdateOperation(uint64_t op_handle, const void* message, size_t size,
                                       string* output, size_t* input_consumed) {
-        UpdateOperationRequest update_request;
-        update_request.op_handle = op_handle;
-        update_request.input.Reinitialize(message, size);
-
-        UpdateOperationResponse update_response;
-        device.UpdateOperation(update_request, &update_response);
-        if (update_response.error == KM_ERROR_OK)
-            output->append(reinterpret_cast<const char*>(update_response.output.peek_read()),
-                           update_response.output.available_read());
-        *input_consumed = update_response.input_consumed;
-        return update_response.error;
+        uint8_t* out_tmp = NULL;
+        size_t out_length;
+        keymaster_error_t error =
+            device()->update(device(), op_handle, reinterpret_cast<const uint8_t*>(message), size,
+                             input_consumed, &out_tmp, &out_length);
+        if (out_tmp)
+            *output = string(reinterpret_cast<char*>(out_tmp), out_length);
+        free(out_tmp);
+        return error;
     }
 
     keymaster_error_t FinishOperation(uint64_t op_handle, string* output) {
-        FinishOperationRequest finish_request;
-        finish_request.op_handle = op_handle;
-        FinishOperationResponse finish_response;
-        device.FinishOperation(finish_request, &finish_response);
-        if (finish_response.error == KM_ERROR_OK)
-            output->append(reinterpret_cast<const char*>(finish_response.output.peek_read()),
-                           finish_response.output.available_read());
-        return finish_response.error;
+        uint8_t* out_tmp = NULL;
+        size_t out_length;
+        keymaster_error_t error = device()->finish(device(), op_handle, NULL /* signature */,
+                                                   0 /* signature_length */, &out_tmp, &out_length);
+        if (out_tmp)
+            *output = string(reinterpret_cast<char*>(out_tmp), out_length);
+        free(out_tmp);
+        return error;
     }
 
     string ProcessMessage(keymaster_purpose_t purpose, const keymaster_key_blob_t& key_blob,
@@ -1050,25 +1001,27 @@
     }
 
     string EncryptMessage(const void* message, size_t size) {
-        return ProcessMessage(KM_PURPOSE_ENCRYPT, generate_response_.key_blob, message, size);
+        return ProcessMessage(KM_PURPOSE_ENCRYPT, blob_, message, size);
     }
 
     string DecryptMessage(const void* ciphertext, size_t size) {
-        return ProcessMessage(KM_PURPOSE_DECRYPT, generate_response_.key_blob, ciphertext, size);
+        return ProcessMessage(KM_PURPOSE_DECRYPT, blob_, ciphertext, size);
     }
 
     void AddClientParams(AuthorizationSet* set) { set->push_back(TAG_APPLICATION_ID, "app_id", 6); }
 
-    const keymaster_key_blob_t& key_blob() { return generate_response_.key_blob; }
-
-    const keymaster_key_blob_t& corrupt_key_blob() {
-        uint8_t* tmp = const_cast<uint8_t*>(generate_response_.key_blob.key_material);
-        ++tmp[generate_response_.key_blob.key_material_size / 2];
-        return generate_response_.key_blob;
+    const void corrupt_key_blob() {
+        uint8_t* tmp = const_cast<uint8_t*>(blob_.key_material);
+        ++tmp[blob_.key_material_size / 2];
     }
 
-  protected:
-    GenerateKeyResponse generate_response_;
+    keymaster_blob_t client_id_ = {.data = reinterpret_cast<const uint8_t*>("app_id"),
+                                   .data_length = 6};
+    keymaster_key_param_t client_params_[1] = {
+        Authorization(TAG_APPLICATION_ID, client_id_.data, client_id_.data_length)};
+
+    keymaster_key_param_t* out_params_;
+    size_t out_params_count_;
 };
 
 TEST_F(EncryptionOperationsTest, RsaOaepSuccess) {
@@ -1101,8 +1054,7 @@
     string result;
     size_t input_consumed;
 
-    EXPECT_EQ(KM_ERROR_OK,
-              BeginOperation(KM_PURPOSE_ENCRYPT, generate_response_.key_blob, &op_handle));
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, blob_, &op_handle));
     EXPECT_EQ(KM_ERROR_OK,
               UpdateOperation(op_handle, message, array_size(message), &result, &input_consumed));
     EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(op_handle, &result));
@@ -1121,8 +1073,7 @@
     uint64_t op_handle;
     string result;
     size_t input_consumed;
-    EXPECT_EQ(KM_ERROR_OK,
-              BeginOperation(KM_PURPOSE_DECRYPT, generate_response_.key_blob, &op_handle));
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, blob_, &op_handle));
     EXPECT_EQ(KM_ERROR_OK, UpdateOperation(op_handle, ciphertext.data(), ciphertext.size(), &result,
                                            &input_consumed));
     EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, FinishOperation(op_handle, &result));
@@ -1159,8 +1110,7 @@
     string result;
     size_t input_consumed;
 
-    EXPECT_EQ(KM_ERROR_OK,
-              BeginOperation(KM_PURPOSE_ENCRYPT, generate_response_.key_blob, &op_handle));
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, blob_, &op_handle));
     EXPECT_EQ(KM_ERROR_OK,
               UpdateOperation(op_handle, message, array_size(message), &result, &input_consumed));
     EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(op_handle, &result));
@@ -1179,8 +1129,7 @@
     uint64_t op_handle;
     string result;
     size_t input_consumed;
-    EXPECT_EQ(KM_ERROR_OK,
-              BeginOperation(KM_PURPOSE_DECRYPT, generate_response_.key_blob, &op_handle));
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, blob_, &op_handle));
     EXPECT_EQ(KM_ERROR_OK, UpdateOperation(op_handle, ciphertext.data(), ciphertext.size(), &result,
                                            &input_consumed));
     EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, FinishOperation(op_handle, &result));
diff --git a/soft_keymaster_device.cpp b/soft_keymaster_device.cpp
new file mode 100644
index 0000000..d2b9470
--- /dev/null
+++ b/soft_keymaster_device.cpp
@@ -0,0 +1,767 @@
+/*
+ * 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 "soft_keymaster_device.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <stddef.h>
+
+#include <algorithm>
+
+#include <type_traits>
+
+#include <hardware/keymaster.h>
+#define LOG_TAG "SoftKeymasterDevice"
+#include <cutils/log.h>
+
+#include <keymaster/authorization_set.h>
+#include <keymaster/google_keymaster_messages.h>
+#include <keymaster/key_blob.h>
+
+#include "google_softkeymaster.h"
+#include "soft_keymaster_logger.h"
+
+const uint32_t SEND_BUF_SIZE = 8192;
+const uint32_t RECV_BUF_SIZE = 8192;
+
+struct keystore_module soft_keymaster_device_module = {
+    .common =
+        {
+         .tag = HARDWARE_MODULE_TAG,
+         .module_api_version = KEYMASTER_MODULE_API_VERSION_0_4,
+         .hal_api_version = HARDWARE_HAL_API_VERSION,
+         .id = KEYSTORE_HARDWARE_MODULE_ID,
+         .name = "Keymaster OpenSSL HAL",
+         .author = "The Android Open Source Project",
+         .methods = NULL,
+         .dso = 0,
+         .reserved = {},
+        },
+};
+
+namespace keymaster {
+
+SoftKeymasterDevice::SoftKeymasterDevice(Logger* logger)
+    : impl_(new GoogleSoftKeymaster(16, logger)) {
+#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
+    static_assert(std::is_standard_layout<SoftKeymasterDevice>::value,
+                  "SoftKeymasterDevice must be standard layout");
+    static_assert(offsetof(SoftKeymasterDevice, device_) == 0,
+                  "device_ must be the first member of KeymasterOpenSsl");
+    static_assert(offsetof(SoftKeymasterDevice, device_.common) == 0,
+                  "common must be the first member of keymaster_device");
+#else
+    assert(reinterpret_cast<keymaster_device*>(this) == &device_);
+    assert(reinterpret_cast<hw_device_t*>(this) == &(device_.common));
+#endif
+    logger->info("Creating device");
+    logger->debug("Device address: %p", this);
+
+    memset(&device_, 0, sizeof(device_));
+
+    device_.common.tag = HARDWARE_DEVICE_TAG;
+    device_.common.version = 1;
+    device_.common.module = reinterpret_cast<hw_module_t*>(&soft_keymaster_device_module);
+    device_.common.close = &close_device;
+
+    device_.flags =
+        KEYMASTER_SOFTWARE_ONLY | KEYMASTER_BLOBS_ARE_STANDALONE | KEYMASTER_SUPPORTS_EC;
+
+    // V0.3 APIs
+    device_.generate_keypair = generate_keypair;
+    device_.import_keypair = import_keypair;
+    device_.get_keypair_public = get_keypair_public;
+    device_.delete_keypair = NULL;
+    device_.delete_all = NULL;
+    device_.sign_data = sign_data;
+    device_.verify_data = verify_data;
+
+    // V0.4 APIs
+    device_.get_supported_algorithms = get_supported_algorithms;
+    device_.get_supported_block_modes = get_supported_block_modes;
+    device_.get_supported_padding_modes = get_supported_padding_modes;
+    device_.get_supported_digests = get_supported_digests;
+    device_.get_supported_import_formats = get_supported_import_formats;
+    device_.get_supported_export_formats = get_supported_export_formats;
+    device_.add_rng_entropy = add_rng_entropy;
+    device_.generate_key = generate_key;
+    device_.get_key_characteristics = get_key_characteristics;
+    device_.rescope = rescope;
+    device_.import_key = import_key;
+    device_.export_key = export_key;
+    device_.delete_key = NULL;
+    device_.delete_all_keys = NULL;
+    device_.begin = begin;
+    device_.update = update;
+    device_.finish = finish;
+    device_.abort = abort;
+
+    device_.context = NULL;
+}
+
+const uint64_t HUNDRED_YEARS = 1000LL * 60 * 60 * 24 * 365 * 100;
+
+hw_device_t* SoftKeymasterDevice::hw_device() {
+    return &device_.common;
+}
+
+static keymaster_key_characteristics_t* BuildCharacteristics(const AuthorizationSet& hw_enforced,
+                                                             const AuthorizationSet& sw_enforced) {
+    keymaster_key_characteristics_t* characteristics =
+        reinterpret_cast<keymaster_key_characteristics_t*>(
+            malloc(sizeof(keymaster_key_characteristics_t)));
+    if (characteristics) {
+        hw_enforced.CopyToParamSet(&characteristics->hw_enforced);
+        sw_enforced.CopyToParamSet(&characteristics->sw_enforced);
+    }
+    return characteristics;
+}
+
+template <typename RequestType>
+static void AddClientAndAppData(const keymaster_blob_t* client_id, const keymaster_blob_t* app_data,
+                                RequestType* request) {
+    request->additional_params.Clear();
+    if (client_id)
+        request->additional_params.push_back(TAG_APPLICATION_ID, *client_id);
+    if (app_data)
+        request->additional_params.push_back(TAG_APPLICATION_DATA, *app_data);
+}
+
+static inline SoftKeymasterDevice* convert_device(const keymaster_device* dev) {
+    return reinterpret_cast<SoftKeymasterDevice*>(const_cast<keymaster_device*>(dev));
+}
+
+/* static */
+int SoftKeymasterDevice::close_device(hw_device_t* dev) {
+    delete reinterpret_cast<SoftKeymasterDevice*>(dev);
+    return 0;
+}
+
+/* static */
+int SoftKeymasterDevice::generate_keypair(const keymaster_device_t* dev,
+                                          const keymaster_keypair_t key_type,
+                                          const void* key_params, uint8_t** key_blob,
+                                          size_t* key_blob_length) {
+    convert_device(dev)->impl_->logger().debug("Device received generate_keypair");
+
+    GenerateKeyRequest req;
+    StoreDefaultNewKeyParams(&req.key_description);
+
+    switch (key_type) {
+    case TYPE_RSA: {
+        req.key_description.push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
+        const keymaster_rsa_keygen_params_t* rsa_params =
+            static_cast<const keymaster_rsa_keygen_params_t*>(key_params);
+        convert_device(dev)->impl_->logger().debug(
+            "Generating RSA pair, modulus size: %u, public exponent: %lu", rsa_params->modulus_size,
+            rsa_params->public_exponent);
+        req.key_description.push_back(TAG_KEY_SIZE, rsa_params->modulus_size);
+        req.key_description.push_back(TAG_RSA_PUBLIC_EXPONENT, rsa_params->public_exponent);
+        break;
+    }
+
+    case TYPE_EC: {
+        req.key_description.push_back(TAG_ALGORITHM, KM_ALGORITHM_ECDSA);
+        const keymaster_ec_keygen_params_t* ec_params =
+            static_cast<const keymaster_ec_keygen_params_t*>(key_params);
+        convert_device(dev)->impl_->logger().debug("Generating ECDSA pair, key size: %u",
+                                                   ec_params->field_size);
+        req.key_description.push_back(TAG_KEY_SIZE, ec_params->field_size);
+        break;
+    }
+
+    default:
+        convert_device(dev)->impl_->logger().debug("Received request for unsuported key type %d",
+                                                   key_type);
+        return KM_ERROR_UNSUPPORTED_ALGORITHM;
+    }
+
+    GenerateKeyResponse rsp;
+    convert_device(dev)->impl_->GenerateKey(req, &rsp);
+
+    *key_blob_length = rsp.key_blob.key_material_size;
+    *key_blob = static_cast<uint8_t*>(malloc(*key_blob_length));
+    if (!*key_blob)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    memcpy(*key_blob, rsp.key_blob.key_material, *key_blob_length);
+    convert_device(dev)->impl_->logger().debug("Returning %d bytes in key blob\n",
+                                               (int)*key_blob_length);
+
+    return KM_ERROR_OK;
+}
+
+/* static */
+int SoftKeymasterDevice::import_keypair(const keymaster_device_t* dev, const uint8_t* key,
+                                        const size_t key_length, uint8_t** key_blob,
+                                        size_t* key_blob_length) {
+    convert_device(dev)->impl_->logger().debug("Device received import_keypair");
+
+    ImportKeyRequest request;
+    StoreDefaultNewKeyParams(&request.key_description);
+    request.SetKeyMaterial(key, key_length);
+    request.key_format = KM_KEY_FORMAT_PKCS8;
+
+    ImportKeyResponse response;
+    convert_device(dev)->impl_->ImportKey(request, &response);
+
+    *key_blob_length = response.key_blob.key_material_size;
+    *key_blob = static_cast<uint8_t*>(malloc(*key_blob_length));
+    if (!*key_blob)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    memcpy(*key_blob, response.key_blob.key_material, *key_blob_length);
+    convert_device(dev)->impl_->logger().debug("Returning %d bytes in key blob\n",
+                                               (int)*key_blob_length);
+
+    return KM_ERROR_OK;
+}
+
+/* static */
+int SoftKeymasterDevice::get_keypair_public(const struct keymaster_device* dev,
+                                            const uint8_t* key_blob, const size_t key_blob_length,
+                                            uint8_t** x509_data, size_t* x509_data_length) {
+    convert_device(dev)->impl_->logger().debug("Device received get_keypair_public");
+
+    ExportKeyRequest req;
+    req.SetKeyMaterial(key_blob, key_blob_length);
+    req.key_format = KM_KEY_FORMAT_X509;
+
+    ExportKeyResponse rsp;
+    convert_device(dev)->impl_->ExportKey(req, &rsp);
+
+    *x509_data_length = rsp.key_data_length;
+    *x509_data = static_cast<uint8_t*>(malloc(*x509_data_length));
+    if (!*x509_data)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    memcpy(*x509_data, rsp.key_data, *x509_data_length);
+    convert_device(dev)->impl_->logger().debug("Returning %d bytes in x509 key\n",
+                                               (int)*x509_data_length);
+
+    return KM_ERROR_OK;
+}
+
+/* static */
+int SoftKeymasterDevice::sign_data(const keymaster_device_t* dev, const void* params,
+                                   const uint8_t* key_blob, const size_t key_blob_length,
+                                   const uint8_t* data, const size_t data_length,
+                                   uint8_t** signed_data, size_t* signed_data_length) {
+    convert_device(dev)->impl_->logger().debug("Device received sign_data");
+
+    *signed_data_length = 0;
+
+    BeginOperationRequest begin_request;
+    begin_request.purpose = KM_PURPOSE_SIGN;
+    begin_request.SetKeyMaterial(key_blob, key_blob_length);
+    keymaster_error_t err =
+        ExtractSigningParams(params, key_blob, key_blob_length, &begin_request.additional_params);
+    if (err != KM_ERROR_OK)
+        return err;
+
+    BeginOperationResponse begin_response;
+    convert_device(dev)->impl_->BeginOperation(begin_request, &begin_response);
+    if (begin_response.error != KM_ERROR_OK)
+        return begin_response.error;
+
+    UpdateOperationRequest update_request;
+    update_request.op_handle = begin_response.op_handle;
+    update_request.input.Reinitialize(data, data_length);
+    UpdateOperationResponse update_response;
+    convert_device(dev)->impl_->UpdateOperation(update_request, &update_response);
+    if (update_response.error != KM_ERROR_OK)
+        return update_response.error;
+
+    FinishOperationRequest finish_request;
+    finish_request.op_handle = begin_response.op_handle;
+    FinishOperationResponse finish_response;
+    convert_device(dev)->impl_->FinishOperation(finish_request, &finish_response);
+    if (finish_response.error != KM_ERROR_OK)
+        return finish_response.error;
+
+    *signed_data_length = finish_response.output.available_read();
+    *signed_data = static_cast<uint8_t*>(malloc(*signed_data_length));
+    if (!*signed_data)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!finish_response.output.read(*signed_data, *signed_data_length))
+        return KM_ERROR_UNKNOWN_ERROR;
+    return KM_ERROR_OK;
+}
+
+/* static */
+int SoftKeymasterDevice::verify_data(const keymaster_device_t* dev, const void* params,
+                                     const uint8_t* key_blob, const size_t key_blob_length,
+                                     const uint8_t* signed_data, const size_t signed_data_length,
+                                     const uint8_t* signature, const size_t signature_length) {
+    convert_device(dev)->impl_->logger().debug("Device received verify_data");
+
+    BeginOperationRequest begin_request;
+    begin_request.purpose = KM_PURPOSE_VERIFY;
+    begin_request.SetKeyMaterial(key_blob, key_blob_length);
+    {
+        keymaster_error_t err = ExtractSigningParams(params, key_blob, key_blob_length,
+                                                     &begin_request.additional_params);
+        if (err != KM_ERROR_OK)
+            return err;
+    }
+
+    BeginOperationResponse begin_response;
+    convert_device(dev)->impl_->BeginOperation(begin_request, &begin_response);
+    if (begin_response.error != KM_ERROR_OK)
+        return begin_response.error;
+
+    UpdateOperationRequest update_request;
+    update_request.op_handle = begin_response.op_handle;
+    update_request.input.Reinitialize(signed_data, signed_data_length);
+    UpdateOperationResponse update_response;
+    convert_device(dev)->impl_->UpdateOperation(update_request, &update_response);
+    if (update_response.error != KM_ERROR_OK)
+        return update_response.error;
+
+    FinishOperationRequest finish_request;
+    finish_request.op_handle = begin_response.op_handle;
+    finish_request.signature.Reinitialize(signature, signature_length);
+    FinishOperationResponse finish_response;
+    convert_device(dev)->impl_->FinishOperation(finish_request, &finish_response);
+    if (finish_response.error != KM_ERROR_OK)
+        return finish_response.error;
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_supported_algorithms(const struct keymaster_device* dev,
+                                                                keymaster_algorithm_t** algorithms,
+                                                                size_t* algorithms_length) {
+    if (!algorithms || !algorithms_length)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    SupportedResponse<keymaster_algorithm_t> response;
+    convert_device(dev)->impl_->SupportedAlgorithms(&response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    *algorithms_length = response.results_length;
+    *algorithms =
+        reinterpret_cast<keymaster_algorithm_t*>(malloc(*algorithms_length * sizeof(**algorithms)));
+    if (!*algorithms)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    std::copy(response.results, response.results + response.results_length, *algorithms);
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_supported_block_modes(const struct keymaster_device* dev,
+                                                                 keymaster_algorithm_t algorithm,
+                                                                 keymaster_purpose_t purpose,
+                                                                 keymaster_block_mode_t** modes,
+                                                                 size_t* modes_length) {
+    if (!modes || !modes_length)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    SupportedResponse<keymaster_block_mode_t> response;
+    convert_device(dev)->impl_->SupportedBlockModes(algorithm, purpose, &response);
+
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    *modes_length = response.results_length;
+    *modes = reinterpret_cast<keymaster_block_mode_t*>(malloc(*modes_length * sizeof(**modes)));
+    if (!*modes)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    std::copy(response.results, response.results + response.results_length, *modes);
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_supported_padding_modes(
+    const struct keymaster_device* dev, keymaster_algorithm_t algorithm,
+    keymaster_purpose_t purpose, keymaster_padding_t** modes, size_t* modes_length) {
+    if (!modes || !modes_length)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    SupportedResponse<keymaster_padding_t> response;
+    convert_device(dev)->impl_->SupportedPaddingModes(algorithm, purpose, &response);
+
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    *modes_length = response.results_length;
+    *modes = reinterpret_cast<keymaster_padding_t*>(malloc(*modes_length * sizeof(**modes)));
+    if (!*modes)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    std::copy(response.results, response.results + response.results_length, *modes);
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_supported_digests(const struct keymaster_device* dev,
+                                                             keymaster_algorithm_t algorithm,
+                                                             keymaster_purpose_t purpose,
+                                                             keymaster_digest_t** digests,
+                                                             size_t* digests_length) {
+    if (!digests || !digests_length)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    SupportedResponse<keymaster_digest_t> response;
+    convert_device(dev)->impl_->SupportedDigests(algorithm, purpose, &response);
+
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    *digests_length = response.results_length;
+    *digests = reinterpret_cast<keymaster_digest_t*>(malloc(*digests_length * sizeof(**digests)));
+    if (!*digests)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    std::copy(response.results, response.results + response.results_length, *digests);
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_supported_import_formats(
+    const struct keymaster_device* dev, keymaster_algorithm_t algorithm,
+    keymaster_key_format_t** formats, size_t* formats_length) {
+    if (!formats || !formats_length)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    SupportedResponse<keymaster_key_format_t> response;
+    convert_device(dev)->impl_->SupportedImportFormats(algorithm, &response);
+
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    *formats_length = response.results_length;
+    *formats =
+        reinterpret_cast<keymaster_key_format_t*>(malloc(*formats_length * sizeof(**formats)));
+    if (!*formats)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    std::copy(response.results, response.results + response.results_length, *formats);
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_supported_export_formats(
+    const struct keymaster_device* dev, keymaster_algorithm_t algorithm,
+    keymaster_key_format_t** formats, size_t* formats_length) {
+    if (!formats || !formats_length)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    SupportedResponse<keymaster_key_format_t> response;
+    convert_device(dev)->impl_->SupportedExportFormats(algorithm, &response);
+
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    *formats_length = response.results_length;
+    *formats =
+        reinterpret_cast<keymaster_key_format_t*>(malloc(*formats_length * sizeof(**formats)));
+    if (!*formats)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    std::copy(response.results, response.results + *formats_length, *formats);
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::add_rng_entropy(const struct keymaster_device* /* dev */,
+                                                       const uint8_t* /* data */,
+                                                       size_t /* data_length */) {
+    return KM_ERROR_UNIMPLEMENTED;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::generate_key(
+    const struct keymaster_device* dev, const keymaster_key_param_t* params, size_t params_count,
+    keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t** characteristics) {
+
+    if (!key_blob)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    GenerateKeyRequest request;
+    request.key_description.Reinitialize(params, params_count);
+
+    GenerateKeyResponse response;
+    convert_device(dev)->impl_->GenerateKey(request, &response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    key_blob->key_material_size = response.key_blob.key_material_size;
+    uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(key_blob->key_material_size));
+    if (!tmp)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    memcpy(tmp, response.key_blob.key_material, response.key_blob.key_material_size);
+    key_blob->key_material = tmp;
+
+    if (characteristics) {
+        *characteristics = BuildCharacteristics(response.enforced, response.unenforced);
+        if (!*characteristics)
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_key_characteristics(
+    const struct keymaster_device* dev, const keymaster_key_blob_t* key_blob,
+    const keymaster_blob_t* client_id, const keymaster_blob_t* app_data,
+    keymaster_key_characteristics_t** characteristics) {
+    if (!key_blob)
+        return KM_ERROR_INVALID_KEY_BLOB;
+
+    if (!characteristics)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    GetKeyCharacteristicsRequest request;
+    request.SetKeyMaterial(*key_blob);
+    AddClientAndAppData(client_id, app_data, &request);
+
+    GetKeyCharacteristicsResponse response;
+    convert_device(dev)->impl_->GetKeyCharacteristics(request, &response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    *characteristics = BuildCharacteristics(response.enforced, response.unenforced);
+    if (!*characteristics)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::rescope(
+    const struct keymaster_device* /* dev */, const keymaster_key_param_t* /* new_params */,
+    size_t /* new_params_count */, const keymaster_key_blob_t* /* key_blob */,
+    const keymaster_blob_t* /* client_id */, const keymaster_blob_t* /* app_data */,
+    keymaster_key_blob_t* /* rescoped_key_blob */,
+    keymaster_key_characteristics_t** /* characteristics */) {
+    return KM_ERROR_UNIMPLEMENTED;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::import_key(
+    const struct keymaster_device* dev, const keymaster_key_param_t* params, size_t params_count,
+    keymaster_key_format_t key_format, const uint8_t* key_data, size_t key_data_length,
+    keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t** characteristics) {
+    if (!params || !key_data)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!key_blob)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    *characteristics = NULL;
+
+    ImportKeyRequest request;
+    request.key_description.Reinitialize(params, params_count);
+    request.key_format = key_format;
+    request.SetKeyMaterial(key_data, key_data_length);
+
+    ImportKeyResponse response;
+    convert_device(dev)->impl_->ImportKey(request, &response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    key_blob->key_material_size = response.key_blob.key_material_size;
+    key_blob->key_material = reinterpret_cast<uint8_t*>(malloc(key_blob->key_material_size));
+    if (!key_blob->key_material)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    memcpy(const_cast<uint8_t*>(key_blob->key_material), response.key_blob.key_material,
+           response.key_blob.key_material_size);
+
+    if (characteristics) {
+        *characteristics = BuildCharacteristics(response.enforced, response.unenforced);
+        if (!*characteristics)
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::export_key(
+    const struct keymaster_device* dev, keymaster_key_format_t export_format,
+    const keymaster_key_blob_t* key_to_export, const keymaster_blob_t* client_id,
+    const keymaster_blob_t* app_data, uint8_t** export_data, size_t* export_data_length) {
+    if (!key_to_export || !key_to_export->key_material)
+        return KM_ERROR_INVALID_KEY_BLOB;
+
+    if (!export_data || !export_data_length)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    *export_data = NULL;
+    *export_data_length = 0;
+
+    ExportKeyRequest request;
+    request.key_format = export_format;
+    request.SetKeyMaterial(*key_to_export);
+    AddClientAndAppData(client_id, app_data, &request);
+
+    ExportKeyResponse response;
+    convert_device(dev)->impl_->ExportKey(request, &response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    *export_data_length = response.key_data_length;
+    *export_data = reinterpret_cast<uint8_t*>(malloc(*export_data_length));
+    if (!export_data)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    memcpy(*export_data, response.key_data, *export_data_length);
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t
+SoftKeymasterDevice::begin(const struct keymaster_device* dev, keymaster_purpose_t purpose,
+                           const keymaster_key_blob_t* key, const keymaster_key_param_t* params,
+                           size_t params_count, keymaster_key_param_t** out_params,
+                           size_t* out_params_count,
+                           keymaster_operation_handle_t* operation_handle) {
+    if (!key || !key->key_material)
+        return KM_ERROR_INVALID_KEY_BLOB;
+
+    if (!operation_handle || !out_params || !out_params_count)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    BeginOperationRequest request;
+    request.purpose = purpose;
+    request.SetKeyMaterial(*key);
+    request.additional_params.Reinitialize(params, params_count);
+
+    BeginOperationResponse response;
+    convert_device(dev)->impl_->BeginOperation(request, &response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    *operation_handle = response.op_handle;
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::update(const struct keymaster_device* dev,
+                                              keymaster_operation_handle_t operation_handle,
+                                              const uint8_t* input, size_t input_length,
+                                              size_t* input_consumed, uint8_t** output,
+                                              size_t* output_length) {
+    if (!input)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!input_consumed || !output || !output_length)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    UpdateOperationRequest request;
+    request.op_handle = operation_handle;
+    request.input.Reinitialize(input, input_length);
+
+    UpdateOperationResponse response;
+    convert_device(dev)->impl_->UpdateOperation(request, &response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    *input_consumed = response.input_consumed;
+    *output_length = response.output.available_read();
+    *output = reinterpret_cast<uint8_t*>(malloc(*output_length));
+    if (!*output)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    memcpy(*output, response.output.peek_read(), *output_length);
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::finish(const struct keymaster_device* dev,
+                                              keymaster_operation_handle_t operation_handle,
+                                              const uint8_t* signature, size_t signature_length,
+                                              uint8_t** output, size_t* output_length) {
+    if (!output || !output_length)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    FinishOperationRequest request;
+    request.op_handle = operation_handle;
+    if (signature)
+        request.signature.Reinitialize(signature, signature_length);
+
+    FinishOperationResponse response;
+    convert_device(dev)->impl_->FinishOperation(request, &response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    *output_length = response.output.available_read();
+    *output = reinterpret_cast<uint8_t*>(malloc(*output_length));
+    if (!*output)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    memcpy(*output, response.output.peek_read(), *output_length);
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::abort(const struct keymaster_device* dev,
+                                             keymaster_operation_handle_t operation_handle) {
+    return convert_device(dev)->impl_->AbortOperation(operation_handle);
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::ExtractSigningParams(const void* signing_params,
+                                                            const uint8_t* key_blob,
+                                                            size_t key_blob_length,
+                                                            AuthorizationSet* auth_set) {
+    KeyBlob blob(key_blob, key_blob_length);
+    if (blob.error() != KM_ERROR_OK)
+        return blob.error();
+
+    switch (blob.algorithm()) {
+    case KM_ALGORITHM_RSA: {
+        const keymaster_rsa_sign_params_t* rsa_params =
+            reinterpret_cast<const keymaster_rsa_sign_params_t*>(signing_params);
+        if (rsa_params->digest_type != DIGEST_NONE)
+            return KM_ERROR_UNSUPPORTED_DIGEST;
+        if (rsa_params->padding_type != PADDING_NONE)
+            return KM_ERROR_UNSUPPORTED_PADDING_MODE;
+        if (!auth_set->push_back(TAG_DIGEST, DIGEST_NONE) ||
+            !auth_set->push_back(TAG_PADDING, KM_PAD_NONE))
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    } break;
+    case KM_ALGORITHM_DSA: {
+        const keymaster_dsa_sign_params_t* dsa_params =
+            reinterpret_cast<const keymaster_dsa_sign_params_t*>(signing_params);
+        if (dsa_params->digest_type != DIGEST_NONE)
+            return KM_ERROR_UNSUPPORTED_DIGEST;
+        if (!auth_set->push_back(TAG_DIGEST, DIGEST_NONE))
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    } break;
+    case KM_ALGORITHM_ECDSA: {
+        const keymaster_ec_sign_params_t* ecdsa_params =
+            reinterpret_cast<const keymaster_ec_sign_params_t*>(signing_params);
+        if (ecdsa_params->digest_type != DIGEST_NONE)
+            return KM_ERROR_UNSUPPORTED_DIGEST;
+        if (!auth_set->push_back(TAG_DIGEST, DIGEST_NONE))
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    } break;
+    default:
+        return KM_ERROR_UNSUPPORTED_ALGORITHM;
+    }
+    return KM_ERROR_OK;
+}
+
+/* static */
+void SoftKeymasterDevice::StoreDefaultNewKeyParams(AuthorizationSet* auth_set) {
+    auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_SIGN);
+    auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_VERIFY);
+    auth_set->push_back(TAG_ALL_USERS);
+    auth_set->push_back(TAG_NO_AUTH_REQUIRED);
+    uint64_t now = java_time(time(NULL));
+    auth_set->push_back(TAG_CREATION_DATETIME, now);
+    auth_set->push_back(TAG_ORIGINATION_EXPIRE_DATETIME, now + HUNDRED_YEARS);
+    auth_set->push_back(TAG_DIGEST, DIGEST_NONE);
+    auth_set->push_back(TAG_PADDING, KM_PAD_NONE);
+}
+
+}  // namespace keymaster
diff --git a/soft_keymaster_device.h b/soft_keymaster_device.h
new file mode 100644
index 0000000..37be566
--- /dev/null
+++ b/soft_keymaster_device.h
@@ -0,0 +1,159 @@
+/*
+ * 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 SYSTEM_KEYMASTER_SOFT_KEYMASTER_DEVICE_H_
+#define SYSTEM_KEYMASTER_SOFT_KEYMASTER_DEVICE_H_
+
+#include <stdlib.h>
+
+#include <hardware/keymaster.h>
+
+#include <keymaster/google_keymaster.h>
+#include <keymaster/logger.h>
+
+#include <UniquePtr.h>
+
+namespace keymaster {
+
+class AuthorizationSet;
+
+/**
+ * Software OpenSSL-based Keymaster implementation.
+ *
+ * IMPORTANT MAINTAINER NOTE: Pointers to instances of this class must be castable to hw_device_t
+ * and keymaster_device. This means it must remain a standard layout class (no virtual functions and
+ * no data members which aren't standard layout), and device_ must be the first data member.
+ * Assertions in the constructor validate compliance with those constraints.
+ */
+class SoftKeymasterDevice {
+  public:
+    SoftKeymasterDevice(Logger* logger);
+
+    hw_device_t* hw_device();
+
+    // Public only for testing
+    void GetVersion(const GetVersionRequest& req, GetVersionResponse* rsp) {
+        impl_->GetVersion(req, rsp);
+    }
+
+  private:
+    static keymaster_error_t ExtractSigningParams(const void* signing_params,
+                                                  const uint8_t* key_blob, size_t key_blob_length,
+                                                  AuthorizationSet* auth_set);
+    static void StoreDefaultNewKeyParams(AuthorizationSet* auth_set);
+
+    static int close_device(hw_device_t* dev);
+
+    /*
+     * These static methods are the functions referenced through the function pointers in
+     * keymaster_device.  They're all trivial wrappers.
+     */
+
+    // Version 0.3 and below APIs
+    static int generate_keypair(const keymaster_device_t* dev, const keymaster_keypair_t key_type,
+                                const void* key_params, uint8_t** keyBlob, size_t* keyBlobLength);
+    static int import_keypair(const struct keymaster_device* dev, const uint8_t* key,
+                              const size_t key_length, uint8_t** key_blob, size_t* key_blob_length);
+    static int get_keypair_public(const struct keymaster_device* dev, const uint8_t* key_blob,
+                                  const size_t key_blob_length, uint8_t** x509_data,
+                                  size_t* x509_data_length);
+    static int sign_data(const struct keymaster_device* dev, const void* signing_params,
+                         const uint8_t* key_blob, const size_t key_blob_length, const uint8_t* data,
+                         const size_t data_length, uint8_t** signed_data,
+                         size_t* signed_data_length);
+    static int verify_data(const struct keymaster_device* dev, const void* signing_params,
+                           const uint8_t* key_blob, const size_t key_blob_length,
+                           const uint8_t* signed_data, const size_t signed_data_length,
+                           const uint8_t* signature, const size_t signature_length);
+
+    // Version 0.4 APIs.
+    static keymaster_error_t get_supported_algorithms(const struct keymaster_device* dev,
+                                                      keymaster_algorithm_t** algorithms,
+                                                      size_t* algorithms_length);
+    static keymaster_error_t get_supported_block_modes(const struct keymaster_device* dev,
+                                                       keymaster_algorithm_t algorithm,
+                                                       keymaster_purpose_t purpose,
+                                                       keymaster_block_mode_t** modes,
+                                                       size_t* modes_length);
+    static keymaster_error_t get_supported_padding_modes(const struct keymaster_device* dev,
+                                                         keymaster_algorithm_t algorithm,
+                                                         keymaster_purpose_t purpose,
+                                                         keymaster_padding_t** modes,
+                                                         size_t* modes_length);
+    static keymaster_error_t get_supported_digests(const struct keymaster_device* dev,
+                                                   keymaster_algorithm_t algorithm,
+                                                   keymaster_purpose_t purpose,
+                                                   keymaster_digest_t** digests,
+                                                   size_t* digests_length);
+    static keymaster_error_t get_supported_import_formats(const struct keymaster_device* dev,
+                                                          keymaster_algorithm_t algorithm,
+                                                          keymaster_key_format_t** formats,
+                                                          size_t* formats_length);
+    static keymaster_error_t get_supported_export_formats(const struct keymaster_device* dev,
+                                                          keymaster_algorithm_t algorithm,
+                                                          keymaster_key_format_t** formats,
+                                                          size_t* formats_length);
+    static keymaster_error_t add_rng_entropy(const struct keymaster_device* dev,
+                                             const uint8_t* data, size_t data_length);
+    static keymaster_error_t generate_key(const struct keymaster_device* dev,
+                                          const keymaster_key_param_t* params, size_t params_count,
+                                          keymaster_key_blob_t* key_blob,
+                                          keymaster_key_characteristics_t** characteristics);
+    static keymaster_error_t get_key_characteristics(const struct keymaster_device* dev,
+                                                     const keymaster_key_blob_t* key_blob,
+                                                     const keymaster_blob_t* client_id,
+                                                     const keymaster_blob_t* app_data,
+                                                     keymaster_key_characteristics_t** character);
+    static keymaster_error_t rescope(const struct keymaster_device* dev,
+                                     const keymaster_key_param_t* new_params,
+                                     size_t new_params_count, const keymaster_key_blob_t* key_blob,
+                                     const keymaster_blob_t* client_id,
+                                     const keymaster_blob_t* app_data,
+                                     keymaster_key_blob_t* rescoped_key_blob,
+                                     keymaster_key_characteristics_t** characteristics);
+    static keymaster_error_t import_key(const struct keymaster_device* dev,
+                                        const keymaster_key_param_t* params, size_t params_count,
+                                        keymaster_key_format_t key_format, const uint8_t* key_data,
+                                        size_t key_data_length, keymaster_key_blob_t* key_blob,
+                                        keymaster_key_characteristics_t** characteristics);
+    static keymaster_error_t
+    export_key(const struct keymaster_device* dev, keymaster_key_format_t export_format,
+               const keymaster_key_blob_t* key_to_export, const keymaster_blob_t* client_id,
+               const keymaster_blob_t* app_data, uint8_t** export_data, size_t* export_data_length);
+    static keymaster_error_t begin(const struct keymaster_device* dev, keymaster_purpose_t purpose,
+                                   const keymaster_key_blob_t* key,
+                                   const keymaster_key_param_t* params, size_t params_count,
+                                   keymaster_key_param_t** out_params, size_t* out_params_count,
+                                   keymaster_operation_handle_t* operation_handle);
+    static keymaster_error_t update(const struct keymaster_device* dev,
+                                    keymaster_operation_handle_t operation_handle,
+                                    const uint8_t* input, size_t input_length,
+                                    size_t* input_consumed, uint8_t** output,
+                                    size_t* output_length);
+    static keymaster_error_t finish(const struct keymaster_device* dev,
+                                    keymaster_operation_handle_t operation_handle,
+                                    const uint8_t* signature, size_t signature_length,
+                                    uint8_t** output, size_t* output_length);
+    static keymaster_error_t abort(const struct keymaster_device* dev,
+                                   keymaster_operation_handle_t operation_handle);
+
+    keymaster_device device_;
+    UniquePtr<GoogleKeymaster> impl_;
+};
+
+}  // namespace keymaster
+
+#endif  // EXTERNAL_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
diff --git a/soft_keymaster_logger.cpp b/soft_keymaster_logger.cpp
new file mode 100644
index 0000000..d7b72f1
--- /dev/null
+++ b/soft_keymaster_logger.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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 "soft_keymaster_logger.h"
+
+#include <stdarg.h>
+#include <syslog.h>
+
+#define LOG_TAG "SoftKeymaster"
+#include <cutils/log.h>
+
+namespace keymaster {
+
+int SoftKeymasterLogger::debug(const char* fmt, ...) const {
+    va_list args;
+    va_start(args, fmt);
+    int retval = LOG_PRI_VA(LOG_DEBUG, LOG_TAG, fmt, args);
+    va_end(args);
+    return retval;
+}
+
+int SoftKeymasterLogger::info(const char* fmt, ...) const {
+    va_list args;
+    va_start(args, fmt);
+    int retval = LOG_PRI_VA(LOG_INFO, LOG_TAG, fmt, args);
+    va_end(args);
+    return retval;
+}
+
+int SoftKeymasterLogger::error(const char* fmt, ...) const {
+    va_list args;
+    va_start(args, fmt);
+    int retval = LOG_PRI_VA(LOG_ERR, LOG_TAG, fmt, args);
+    va_end(args);
+    return retval;
+}
+
+int SoftKeymasterLogger::severe(const char* fmt, ...) const {
+    va_list args;
+    va_start(args, fmt);
+    int retval = LOG_PRI_VA(LOG_CRIT, LOG_TAG, fmt, args);
+    va_end(args);
+    return retval;
+}
+
+}  // namespace keymaster
diff --git a/soft_keymaster_logger.h b/soft_keymaster_logger.h
new file mode 100644
index 0000000..d8d343b
--- /dev/null
+++ b/soft_keymaster_logger.h
@@ -0,0 +1,35 @@
+/*
+ * 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 SYSTEM_KEYMASTER_SOFT_KEYMASTER_LOGGER_H_
+#define SYSTEM_KEYMASTER_SOFT_KEYMASTER_LOGGER_H_
+
+#include <keymaster/logger.h>
+
+namespace keymaster {
+
+class SoftKeymasterLogger : public Logger
+{
+public:
+    virtual int debug(const char* fmt, ...) const;
+    virtual int info(const char* fmt, ...) const;
+    virtual int error(const char* fmt, ...) const;
+    virtual int severe(const char* fmt, ...) const;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_SOFT_KEYMASTER_LOGGER_H_