Revert "Revert "Large refactor to move context out of AndroidKeymaster.""

This reverts commit 13fbe3e93247943c26e7ca2ed27b6d650282b8bf.

Bug: 20912868, 19799085
Change-Id: Iadd6ce5cbe94956c2a2fe277f1bf5b108e4bcf57
diff --git a/Android.mk b/Android.mk
index f5ace96..ef059cf 100644
--- a/Android.mk
+++ b/Android.mk
@@ -24,7 +24,6 @@
 		android_keymaster_messages.cpp \
 		android_keymaster_utils.cpp \
 		authorization_set.cpp \
-		key_blob.cpp \
 		logger.cpp \
 		serializable.cpp
 LOCAL_C_INCLUDES := \
@@ -37,19 +36,19 @@
 
 ###
 # libkeymaster1 contains almost everything needed for a keymaster1
-# implementation, lacking only a subclass of the (abstract) AndroidKeymaster
+# implementation, lacking only a subclass of the (abstract) KeymasterContext
 # class to provide environment-specific services and a wrapper to translate from
 # the function-based keymaster HAL API to the message-based AndroidKeymaster API.
 ###
 include $(CLEAR_VARS)
 LOCAL_MODULE:= libkeymaster1
 LOCAL_SRC_FILES:= \
-		aead_mode_operation.cpp \
 		aes_key.cpp \
 		aes_operation.cpp \
 		android_keymaster.cpp \
 		android_keymaster_messages.cpp \
 		android_keymaster_utils.cpp \
+		auth_encrypted_key_blob.cpp \
 		asymmetric_key.cpp \
 		ec_key.cpp \
 		ecdsa_operation.cpp \
@@ -59,14 +58,14 @@
 		hmac_operation.cpp \
 		key.cpp \
 		ocb.c \
+		ocb_utils.cpp \
 		openssl_err.cpp \
 		openssl_utils.cpp \
 		operation.cpp \
 		operation_table.cpp \
 		rsa_key.cpp \
 		rsa_operation.cpp \
-		symmetric_key.cpp \
-		unencrypted_key_blob.cpp
+		symmetric_key.cpp
 LOCAL_C_INCLUDES := \
 	$(LOCAL_PATH)/include
 LOCAL_SHARED_LIBRARIES := libcrypto libkeymaster_messages
@@ -87,6 +86,7 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := libsoftkeymasterdevice
 LOCAL_SRC_FILES := \
+	soft_keymaster_context.cpp \
 	soft_keymaster_device.cpp \
 	soft_keymaster_logger.cpp
 LOCAL_C_INCLUDES := \
diff --git a/Makefile b/Makefile
index 2aec87d..083c65e 100644
--- a/Makefile
+++ b/Makefile
@@ -66,6 +66,7 @@
 	android_keymaster_test_utils.cpp \
 	android_keymaster_utils.cpp \
 	asymmetric_key.cpp \
+	auth_encrypted_key_blob.cpp \
 	authorization_set.cpp \
 	authorization_set_test.cpp \
 	ec_key.cpp \
@@ -78,11 +79,11 @@
 	hmac_operation.cpp \
 	hmac_test.cpp \
 	key.cpp \
-	key_blob.cpp \
 	key_blob_test.cpp \
 	keymaster_enforcement.cpp \
 	keymaster_enforcement_test.cpp \
 	logger.cpp \
+	ocb_utils.cpp \
 	openssl_err.cpp \
 	openssl_utils.cpp \
 	operation.cpp \
@@ -90,9 +91,9 @@
 	rsa_key.cpp \
 	rsa_operation.cpp \
 	serializable.cpp \
+	soft_keymaster_context.cpp \
 	soft_keymaster_device.cpp \
 	symmetric_key.cpp \
-	unencrypted_key_blob.cpp
 CCSRCS=$(GTEST)/src/gtest-all.cc
 CSRCS=ocb.c
 
@@ -181,13 +182,14 @@
 
 key_blob_test: key_blob_test.o \
 	android_keymaster_test_utils.o \
+	android_keymaster_utils.o \
+	auth_encrypted_key_blob.o \
 	authorization_set.o \
-	key_blob.o \
 	logger.o \
 	ocb.o \
+	ocb_utils.o \
 	openssl_err.o \
 	serializable.o \
-	unencrypted_key_blob.o \
 	$(GTEST_OBJS)
 
 android_keymaster_messages_test: android_keymaster_messages_test.o \
@@ -200,7 +202,6 @@
 	$(GTEST_OBJS)
 
 android_keymaster_test: android_keymaster_test.o \
-	aead_mode_operation.o \
 	aes_key.o \
 	aes_operation.o \
 	android_keymaster.o \
@@ -208,15 +209,16 @@
 	android_keymaster_test_utils.o \
 	android_keymaster_utils.o \
 	asymmetric_key.o \
+	auth_encrypted_key_blob.o \
 	authorization_set.o \
 	ec_key.o \
 	ecdsa_operation.o \
 	hmac_key.o \
 	hmac_operation.o \
 	key.o \
-	key_blob.o \
 	logger.o \
 	ocb.o \
+	ocb_utils.o \
 	openssl_err.o \
 	openssl_utils.o \
 	operation.o \
@@ -224,12 +226,13 @@
 	rsa_key.o \
 	rsa_operation.o \
 	serializable.o \
+	soft_keymaster_context.o \
 	soft_keymaster_device.o \
 	symmetric_key.o \
-	unencrypted_key_blob.o \
 	$(GTEST_OBJS)
 
 abstract_factory_registry_test: abstract_factory_registry_test.o \
+	android_keymaster_utils.o \
 	logger.o \
 	$(GTEST_OBJS)
 
diff --git a/aes_key.cpp b/aes_key.cpp
index 8b2c3fd..e1a890f 100644
--- a/aes_key.cpp
+++ b/aes_key.cpp
@@ -22,16 +22,20 @@
 #include <openssl/rand.h>
 
 #include "aes_operation.h"
-#include "unencrypted_key_blob.h"
 
 namespace keymaster {
 
-Key* AesKeyFactory::LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) {
-    return new AesKey(blob, error);
-}
+keymaster_error_t AesKeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+                                         const AuthorizationSet& hw_enforced,
+                                         const AuthorizationSet& sw_enforced, UniquePtr<Key>* key) {
+    if (!key)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
-SymmetricKey* AesKeyFactory::CreateKey(const AuthorizationSet& auths) {
-    return new AesKey(auths);
+    keymaster_error_t error = KM_ERROR_OK;
+    key->reset(new AesKey(key_material, hw_enforced, sw_enforced, &error));
+    if (!key->get())
+        error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    return error;
 }
 
 }  // namespace keymaster
diff --git a/aes_key.h b/aes_key.h
index fa615f6..28efc39 100644
--- a/aes_key.h
+++ b/aes_key.h
@@ -25,22 +25,25 @@
 
 class AesKeyFactory : public SymmetricKeyFactory {
   public:
+    AesKeyFactory(const KeymasterContext* context) : SymmetricKeyFactory(context) {}
+
     keymaster_algorithm_t registry_key() const { return KM_ALGORITHM_AES; }
 
-    Key* LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) override;
-    SymmetricKey* CreateKey(const AuthorizationSet& auths) override;
+    keymaster_error_t LoadKey(const KeymasterKeyBlob& key_material,
+                              const AuthorizationSet& hw_enforced,
+                              const AuthorizationSet& sw_enforced, UniquePtr<Key>* key) override;
+
+  private:
+    bool key_size_supported(size_t key_size_bits) const override {
+        return key_size_bits == 128 || key_size_bits == 192 || key_size_bits == 256;
+    }
 };
 
 class AesKey : public SymmetricKey {
   public:
-    AesKey(const AuthorizationSet& auths) : SymmetricKey(auths) {}
-    AesKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) : SymmetricKey(blob, error) {}
-
-  private:
-    bool size_supported(size_t key_size) const override {
-        // AES keys only come in three sizes, 128, 192 and 256 bits.
-        return key_size == 128 / 8 || key_size == 192 / 8 || key_size == 256 / 8;
-    }
+    AesKey(const KeymasterKeyBlob& key_material, const AuthorizationSet& hw_enforced,
+           const AuthorizationSet& sw_enforced, keymaster_error_t* error)
+        : SymmetricKey(key_material, hw_enforced, sw_enforced, error) {}
 };
 
 }  // namespace keymaster
diff --git a/aes_operation.h b/aes_operation.h
index d4b4687..2172e2d 100644
--- a/aes_operation.h
+++ b/aes_operation.h
@@ -25,6 +25,8 @@
 
 namespace keymaster {
 
+static const size_t MAX_EVP_KEY_SIZE = 32;
+
 class AesEvpOperation : public Operation {
   public:
     AesEvpOperation(keymaster_purpose_t purpose, keymaster_block_mode_t block_mode,
@@ -54,7 +56,7 @@
     const keymaster_padding_t padding_;
     const bool caller_iv_;
     UniquePtr<uint8_t[]> iv_;
-    uint8_t key_[SymmetricKey::MAX_KEY_SIZE];
+    uint8_t key_[MAX_EVP_KEY_SIZE];
 };
 
 class AesEvpEncryptOperation : public AesEvpOperation {
diff --git a/android_keymaster.cpp b/android_keymaster.cpp
index df1d100..ba5361d 100644
--- a/android_keymaster.cpp
+++ b/android_keymaster.cpp
@@ -27,13 +27,13 @@
 #include <UniquePtr.h>
 
 #include <keymaster/android_keymaster_utils.h>
+#include <keymaster/keymaster_context.h>
 
 #include "ae.h"
 #include "key.h"
 #include "openssl_err.h"
 #include "operation.h"
 #include "operation_table.h"
-#include "unencrypted_key_blob.h"
 
 namespace keymaster {
 
@@ -41,8 +41,8 @@
 const uint8_t MINOR_VER = 0;
 const uint8_t SUBMINOR_VER = 0;
 
-AndroidKeymaster::AndroidKeymaster(size_t operation_table_size)
-    : operation_table_(new OperationTable(operation_table_size)) {
+AndroidKeymaster::AndroidKeymaster(KeymasterContext* context, size_t operation_table_size)
+    : context_(context), operation_table_(new OperationTable(operation_table_size)) {
 }
 
 AndroidKeymaster::~AndroidKeymaster() {
@@ -175,6 +175,11 @@
     response->SetResults(formats, count);
 }
 
+keymaster_error_t AndroidKeymaster::AddRngEntropy(const AddEntropyRequest& request) {
+    return context_->AddRngEntropy(request.random_data.peek_read(),
+                                   request.random_data.available_read());
+}
+
 void AndroidKeymaster::GenerateKey(const GenerateKeyRequest& request,
                                    GenerateKeyResponse* response) {
     if (response == NULL)
@@ -186,14 +191,13 @@
     if (!request.key_description.GetTagValue(TAG_ALGORITHM, &algorithm) ||
         !(factory = KeyFactoryRegistry::Get(algorithm)))
         response->error = KM_ERROR_UNSUPPORTED_ALGORITHM;
-    else
-        key.reset(factory->GenerateKey(request.key_description, &response->error));
-
-    if (response->error != KM_ERROR_OK)
-        return;
-
-    response->error = SerializeKey(key.get(), KM_ORIGIN_GENERATED, &response->key_blob,
-                                   &response->enforced, &response->unenforced);
+    else {
+        KeymasterKeyBlob key_blob;
+        response->error = factory->GenerateKey(request.key_description, &key_blob,
+                                               &response->enforced, &response->unenforced);
+        if (response->error == KM_ERROR_OK)
+            response->key_blob = key_blob.release();
+    }
 }
 
 void AndroidKeymaster::GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
@@ -201,13 +205,25 @@
     if (response == NULL)
         return;
 
-    UniquePtr<KeyBlob> blob(
-        LoadKeyBlob(request.key_blob, request.additional_params, &(response->error)));
-    if (blob.get() == NULL)
+    KeymasterKeyBlob key_material;
+    response->error =
+        context_->ParseKeyBlob(KeymasterKeyBlob(request.key_blob), request.additional_params,
+                               &key_material, &response->enforced, &response->unenforced);
+    if (response->error != KM_ERROR_OK)
         return;
+}
 
-    response->enforced.Reinitialize(blob->enforced());
-    response->unenforced.Reinitialize(blob->unenforced());
+static KeyFactory* GetKeyFactory(const AuthorizationSet& hw_enforced,
+                                 const AuthorizationSet& sw_enforced,
+                                 keymaster_algorithm_t* algorithm, keymaster_error_t* error) {
+    *error = KM_ERROR_UNSUPPORTED_ALGORITHM;
+    if (!hw_enforced.GetTagValue(TAG_ALGORITHM, algorithm) &&
+        !sw_enforced.GetTagValue(TAG_ALGORITHM, algorithm))
+        return nullptr;
+    KeyFactory* factory = KeyFactoryRegistry::Get(*algorithm);
+    if (factory)
+        *error = KM_ERROR_OK;
+    return factory;
 }
 
 void AndroidKeymaster::BeginOperation(const BeginOperationRequest& request,
@@ -216,25 +232,24 @@
         return;
     response->op_handle = 0;
 
+    AuthorizationSet hw_enforced;
+    AuthorizationSet sw_enforced;
     keymaster_algorithm_t algorithm;
-    UniquePtr<Key> key(
-        LoadKey(request.key_blob, request.additional_params, &algorithm, &response->error));
-    if (key.get() == NULL)
-        return;
+    UniquePtr<Key> key;
+    response->error = LoadKey(request.key_blob, request.additional_params, &hw_enforced,
+                              &sw_enforced, &algorithm, &key);
 
     // TODO(swillden): Move this check to a general authorization checker.
-    if (!key->authorizations().Contains(TAG_PURPOSE, request.purpose)) {
-        // TODO(swillden): Consider introducing error codes for unauthorized usages.
-        response->error = KM_ERROR_INCOMPATIBLE_PURPOSE;
+    // TODO(swillden): Consider introducing error codes for unauthorized usages.
+    response->error = KM_ERROR_INCOMPATIBLE_PURPOSE;
+    if (!hw_enforced.Contains(TAG_PURPOSE, request.purpose) &&
+        !sw_enforced.Contains(TAG_PURPOSE, request.purpose))
         return;
-    }
 
-    OperationFactory::KeyType op_type(algorithm, request.purpose);
-    OperationFactory* factory = OperationFactoryRegistry::Get(op_type);
-    if (!factory) {
-        response->error = KM_ERROR_UNSUPPORTED_PURPOSE;
+    response->error = KM_ERROR_UNSUPPORTED_PURPOSE;
+    OperationFactory* factory = OperationFactoryRegistry::Get({algorithm, request.purpose});
+    if (!factory)
         return;
-    }
 
     UniquePtr<Operation> operation(
         factory->CreateOperation(*key, request.additional_params, &response->error));
@@ -298,15 +313,28 @@
     if (response == NULL)
         return;
 
+    AuthorizationSet hw_enforced;
+    AuthorizationSet sw_enforced;
+    KeymasterKeyBlob key_material;
+    response->error =
+        context_->ParseKeyBlob(KeymasterKeyBlob(request.key_blob), request.additional_params,
+                               &key_material, &hw_enforced, &sw_enforced);
+    if (response->error != KM_ERROR_OK)
+        return;
+
     keymaster_algorithm_t algorithm;
-    UniquePtr<Key> to_export(
-        LoadKey(request.key_blob, request.additional_params, &algorithm, &response->error));
-    if (to_export.get() == NULL)
+    KeyFactory* key_factory = GetKeyFactory(hw_enforced, sw_enforced, &algorithm, &response->error);
+    if (!key_factory)
+        return;
+
+    UniquePtr<Key> key;
+    response->error = key_factory->LoadKey(key_material, hw_enforced, sw_enforced, &key);
+    if (response->error != KM_ERROR_OK)
         return;
 
     UniquePtr<uint8_t[]> out_key;
     size_t size;
-    response->error = to_export->formatted_key_material(request.key_format, &out_key, &size);
+    response->error = key->formatted_key_material(request.key_format, &out_key, &size);
     if (response->error == KM_ERROR_OK) {
         response->key_data = out_key.release();
         response->key_data_length = size;
@@ -323,168 +351,35 @@
     if (!request.key_description.GetTagValue(TAG_ALGORITHM, &algorithm) ||
         !(factory = KeyFactoryRegistry::Get(algorithm)))
         response->error = KM_ERROR_UNSUPPORTED_ALGORITHM;
-    else
-        key.reset(factory->ImportKey(request.key_description, request.key_format, request.key_data,
-                                     request.key_data_length, &response->error));
-
-    if (response->error != KM_ERROR_OK)
-        return;
-
-    response->error = SerializeKey(key.get(), KM_ORIGIN_IMPORTED, &response->key_blob,
-                                   &response->enforced, &response->unenforced);
+    else {
+        keymaster_key_blob_t key_material = {request.key_data, request.key_data_length};
+        KeymasterKeyBlob key_blob;
+        response->error = factory->ImportKey(request.key_description, request.key_format,
+                                             KeymasterKeyBlob(key_material), &key_blob,
+                                             &response->enforced, &response->unenforced);
+        if (response->error == KM_ERROR_OK)
+            response->key_blob = key_blob.release();
+    }
 }
 
-keymaster_error_t AndroidKeymaster::SerializeKey(const Key* key, keymaster_key_origin_t origin,
-                                                 keymaster_key_blob_t* keymaster_blob,
-                                                 AuthorizationSet* enforced,
-                                                 AuthorizationSet* unenforced) {
-    keymaster_error_t error;
-
-    error = SetAuthorizations(key->authorizations(), origin, enforced, unenforced);
+keymaster_error_t AndroidKeymaster::LoadKey(const keymaster_key_blob_t& key_blob,
+                                            const AuthorizationSet& additional_params,
+                                            AuthorizationSet* hw_enforced,
+                                            AuthorizationSet* sw_enforced,
+                                            keymaster_algorithm_t* algorithm, UniquePtr<Key>* key) {
+    KeymasterKeyBlob key_material;
+    keymaster_error_t error = context_->ParseKeyBlob(KeymasterKeyBlob(key_blob), additional_params,
+                                                     &key_material, hw_enforced, sw_enforced);
     if (error != KM_ERROR_OK)
         return error;
 
-    AuthorizationSet hidden_auths;
-    error = BuildHiddenAuthorizations(key->authorizations(), &hidden_auths);
-    if (error != KM_ERROR_OK)
+    KeyFactory* key_factory = GetKeyFactory(*hw_enforced, *sw_enforced, algorithm, &error);
+    if (error != KM_ERROR_OK) {
+        assert(!key_factory);
         return error;
-
-    UniquePtr<uint8_t[]> key_material;
-    size_t key_material_size;
-    error = key->key_material(&key_material, &key_material_size);
-    if (error != KM_ERROR_OK)
-        return error;
-
-    uint8_t nonce[KeyBlob::NONCE_LENGTH];
-    GenerateNonce(nonce, array_size(nonce));
-
-    keymaster_key_blob_t master_key = MasterKey();
-    UniquePtr<KeyBlob> blob(new UnencryptedKeyBlob(
-        *enforced, *unenforced, hidden_auths, key_material.get(), key_material_size,
-        master_key.key_material, master_key.key_material_size, nonce));
-    if (blob.get() == NULL)
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-    if (blob->error() != KM_ERROR_OK)
-        return blob->error();
-
-    size_t size = blob->SerializedSize();
-    UniquePtr<uint8_t[]> blob_bytes(new uint8_t[size]);
-    if (blob_bytes.get() == NULL)
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
-    blob->Serialize(blob_bytes.get(), blob_bytes.get() + size);
-    keymaster_blob->key_material_size = size;
-    keymaster_blob->key_material = blob_bytes.release();
-
-    return KM_ERROR_OK;
-}
-
-Key* AndroidKeymaster::LoadKey(const keymaster_key_blob_t& key,
-                               const AuthorizationSet& client_params,
-                               keymaster_algorithm_t* algorithm, keymaster_error_t* error) {
-    UniquePtr<UnencryptedKeyBlob> blob(LoadKeyBlob(key, client_params, error));
-    if (*error != KM_ERROR_OK)
-        return NULL;
-
-    *algorithm = blob->algorithm();
-
-    KeyFactory* factory = 0;
-    if ((factory = KeyFactoryRegistry::Get(*algorithm)))
-        return factory->LoadKey(*blob, error);
-    *error = KM_ERROR_UNSUPPORTED_ALGORITHM;
-    return NULL;
-}
-
-UnencryptedKeyBlob* AndroidKeymaster::LoadKeyBlob(const keymaster_key_blob_t& key,
-                                                  const AuthorizationSet& client_params,
-                                                  keymaster_error_t* error) {
-    AuthorizationSet hidden;
-    BuildHiddenAuthorizations(client_params, &hidden);
-    keymaster_key_blob_t master_key = MasterKey();
-    UniquePtr<UnencryptedKeyBlob> blob(
-        new UnencryptedKeyBlob(key, hidden, master_key.key_material, master_key.key_material_size));
-    if (blob.get() == NULL) {
-        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
-        return NULL;
-    } else if (blob->error() != KM_ERROR_OK) {
-        *error = blob->error();
-        return NULL;
-    }
-    *error = KM_ERROR_OK;
-    return blob.release();
-}
-
-static keymaster_error_t TranslateAuthorizationSetError(AuthorizationSet::Error err) {
-    switch (err) {
-    case AuthorizationSet::OK:
-        return KM_ERROR_OK;
-    case AuthorizationSet::ALLOCATION_FAILURE:
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-    case AuthorizationSet::MALFORMED_DATA:
-        return KM_ERROR_UNKNOWN_ERROR;
-    }
-    return KM_ERROR_OK;
-}
-
-keymaster_error_t AndroidKeymaster::SetAuthorizations(const AuthorizationSet& key_description,
-                                                      keymaster_key_origin_t origin,
-                                                      AuthorizationSet* enforced,
-                                                      AuthorizationSet* unenforced) {
-    enforced->Clear();
-    unenforced->Clear();
-    for (size_t i = 0; i < key_description.size(); ++i) {
-        switch (key_description[i].tag) {
-        // These cannot be specified by the client.
-        case KM_TAG_ROOT_OF_TRUST:
-        case KM_TAG_ORIGIN:
-            LOG_E("Root of trust and origin tags may not be specified", 0);
-            return KM_ERROR_INVALID_TAG;
-
-        // These don't work.
-        case KM_TAG_ROLLBACK_RESISTANT:
-            LOG_E("KM_TAG_ROLLBACK_RESISTANT not supported", 0);
-            return KM_ERROR_UNSUPPORTED_TAG;
-
-        // These are hidden.
-        case KM_TAG_APPLICATION_ID:
-        case KM_TAG_APPLICATION_DATA:
-            break;
-
-        // Everything else we just copy into the appropriate set.
-        default:
-            AddAuthorization(key_description[i], enforced, unenforced);
-            break;
-        }
     }
 
-    AddAuthorization(Authorization(TAG_CREATION_DATETIME, java_time(time(NULL))), enforced,
-                     unenforced);
-    AddAuthorization(Authorization(TAG_ORIGIN, origin), enforced, unenforced);
-
-    if (enforced->is_valid() != AuthorizationSet::OK)
-        return TranslateAuthorizationSetError(enforced->is_valid());
-
-    return TranslateAuthorizationSetError(unenforced->is_valid());
-}
-
-keymaster_error_t AndroidKeymaster::BuildHiddenAuthorizations(const AuthorizationSet& input_set,
-                                                              AuthorizationSet* hidden) {
-    keymaster_blob_t entry;
-    if (input_set.GetTagValue(TAG_APPLICATION_ID, &entry))
-        hidden->push_back(TAG_APPLICATION_ID, entry.data, entry.data_length);
-    if (input_set.GetTagValue(TAG_APPLICATION_DATA, &entry))
-        hidden->push_back(TAG_APPLICATION_DATA, entry.data, entry.data_length);
-    hidden->push_back(RootOfTrustTag());
-
-    return TranslateAuthorizationSetError(hidden->is_valid());
-}
-
-void AndroidKeymaster::AddAuthorization(const keymaster_key_param_t& auth,
-                                        AuthorizationSet* enforced, AuthorizationSet* unenforced) {
-    if (is_enforced(auth.tag))
-        enforced->push_back(auth);
-    else
-        unenforced->push_back(auth);
+    return key_factory->LoadKey(key_material, *hw_enforced, *sw_enforced, key);
 }
 
 }  // namespace keymaster
diff --git a/android_keymaster_messages_test.cpp b/android_keymaster_messages_test.cpp
index 2c888d9..143b03b 100644
--- a/android_keymaster_messages_test.cpp
+++ b/android_keymaster_messages_test.cpp
@@ -18,11 +18,11 @@
 
 #include <gtest/gtest.h>
 
-#include <keymaster/keymaster_tags.h>
+#include <keymaster/android_keymaster.h>
 #include <keymaster/android_keymaster_utils.h>
+#include <keymaster/keymaster_tags.h>
 
 #include "android_keymaster_test_utils.h"
-#include "android_softkeymaster.h"
 
 namespace keymaster {
 namespace test {
diff --git a/android_keymaster_test.cpp b/android_keymaster_test.cpp
index 7f06390..e3faefa 100644
--- a/android_keymaster_test.cpp
+++ b/android_keymaster_test.cpp
@@ -78,7 +78,7 @@
 
     size_t len;
     keymaster_block_mode_t* modes;
-    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_block_modes(device(), KM_ALGORITHM_RSA,
+    ASSERT_EQ(KM_ERROR_OK, device()->get_supported_block_modes(device(), KM_ALGORITHM_RSA,
                                                                KM_PURPOSE_ENCRYPT, &modes, &len));
     EXPECT_EQ(0U, len);
     free(modes);
@@ -87,7 +87,7 @@
               device()->get_supported_block_modes(device(), KM_ALGORITHM_EC, KM_PURPOSE_ENCRYPT,
                                                   &modes, &len));
 
-    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_block_modes(device(), KM_ALGORITHM_AES,
+    ASSERT_EQ(KM_ERROR_OK, device()->get_supported_block_modes(device(), KM_ALGORITHM_AES,
                                                                KM_PURPOSE_ENCRYPT, &modes, &len));
     EXPECT_TRUE(ResponseContains({KM_MODE_ECB, KM_MODE_CBC, KM_MODE_CTR}, modes, len));
     free(modes);
@@ -100,18 +100,18 @@
 
     size_t len;
     keymaster_padding_t* modes;
-    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA,
+    ASSERT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA,
                                                                  KM_PURPOSE_SIGN, &modes, &len));
     EXPECT_TRUE(
         ResponseContains({KM_PAD_NONE, KM_PAD_RSA_PKCS1_1_5_SIGN, KM_PAD_RSA_PSS}, modes, len));
     free(modes);
 
-    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA,
+    ASSERT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA,
                                                                  KM_PURPOSE_ENCRYPT, &modes, &len));
     EXPECT_TRUE(ResponseContains({KM_PAD_RSA_OAEP, KM_PAD_RSA_PKCS1_1_5_ENCRYPT}, modes, len));
     free(modes);
 
-    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_EC,
+    ASSERT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_EC,
                                                                  KM_PURPOSE_SIGN, &modes, &len));
     EXPECT_EQ(0U, len);
     free(modes);
@@ -128,12 +128,12 @@
 
     size_t len;
     keymaster_digest_t* digests;
-    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_RSA,
+    ASSERT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_RSA,
                                                            KM_PURPOSE_SIGN, &digests, &len));
     EXPECT_TRUE(ResponseContains({KM_DIGEST_NONE, KM_DIGEST_SHA_2_256}, digests, len));
     free(digests);
 
-    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_EC,
+    ASSERT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_EC,
                                                            KM_PURPOSE_SIGN, &digests, &len));
     EXPECT_TRUE(ResponseContains(KM_DIGEST_NONE, digests, len));
     free(digests);
@@ -142,7 +142,7 @@
               device()->get_supported_digests(device(), KM_ALGORITHM_AES, KM_PURPOSE_SIGN, &digests,
                                               &len));
 
-    EXPECT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_HMAC,
+    ASSERT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_HMAC,
                                                            KM_PURPOSE_SIGN, &digests, &len));
     EXPECT_TRUE(ResponseContains({KM_DIGEST_SHA_2_224, KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384,
                                   KM_DIGEST_SHA_2_512, KM_DIGEST_SHA1},
@@ -156,17 +156,17 @@
 
     size_t len;
     keymaster_key_format_t* formats;
-    EXPECT_EQ(KM_ERROR_OK,
+    ASSERT_EQ(KM_ERROR_OK,
               device()->get_supported_import_formats(device(), KM_ALGORITHM_RSA, &formats, &len));
     EXPECT_TRUE(ResponseContains(KM_KEY_FORMAT_PKCS8, formats, len));
     free(formats);
 
-    EXPECT_EQ(KM_ERROR_OK,
+    ASSERT_EQ(KM_ERROR_OK,
               device()->get_supported_import_formats(device(), KM_ALGORITHM_AES, &formats, &len));
     EXPECT_TRUE(ResponseContains(KM_KEY_FORMAT_RAW, formats, len));
     free(formats);
 
-    EXPECT_EQ(KM_ERROR_OK,
+    ASSERT_EQ(KM_ERROR_OK,
               device()->get_supported_import_formats(device(), KM_ALGORITHM_HMAC, &formats, &len));
     EXPECT_TRUE(ResponseContains(KM_KEY_FORMAT_RAW, formats, len));
     free(formats);
@@ -178,27 +178,27 @@
 
     size_t len;
     keymaster_key_format_t* formats;
-    EXPECT_EQ(KM_ERROR_OK,
+    ASSERT_EQ(KM_ERROR_OK,
               device()->get_supported_export_formats(device(), KM_ALGORITHM_RSA, &formats, &len));
     EXPECT_TRUE(ResponseContains(KM_KEY_FORMAT_X509, formats, len));
     free(formats);
 
-    EXPECT_EQ(KM_ERROR_OK,
+    ASSERT_EQ(KM_ERROR_OK,
               device()->get_supported_export_formats(device(), KM_ALGORITHM_EC, &formats, &len));
     EXPECT_TRUE(ResponseContains(KM_KEY_FORMAT_X509, formats, len));
     free(formats);
 
-    EXPECT_EQ(KM_ERROR_OK,
+    ASSERT_EQ(KM_ERROR_OK,
               device()->get_supported_export_formats(device(), KM_ALGORITHM_AES, &formats, &len));
     EXPECT_EQ(0U, len);
     free(formats);
 
-    EXPECT_EQ(KM_ERROR_OK,
+    ASSERT_EQ(KM_ERROR_OK,
               device()->get_supported_export_formats(device(), KM_ALGORITHM_AES, &formats, &len));
     EXPECT_EQ(0U, len);
     free(formats);
 
-    EXPECT_EQ(KM_ERROR_OK,
+    ASSERT_EQ(KM_ERROR_OK,
               device()->get_supported_export_formats(device(), KM_ALGORITHM_HMAC, &formats, &len));
     EXPECT_EQ(0U, len);
     free(formats);
@@ -950,13 +950,13 @@
     // Get all supported digests and padding modes.
     size_t digests_len;
     keymaster_digest_t* digests;
-    EXPECT_EQ(KM_ERROR_OK,
+    ASSERT_EQ(KM_ERROR_OK,
               device()->get_supported_digests(device(), KM_ALGORITHM_RSA, KM_PURPOSE_SIGN, &digests,
                                               &digests_len));
 
     size_t padding_modes_len;
     keymaster_padding_t* padding_modes;
-    EXPECT_EQ(KM_ERROR_OK,
+    ASSERT_EQ(KM_ERROR_OK,
               device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA, KM_PURPOSE_SIGN,
                                                     &padding_modes, &padding_modes_len));
 
diff --git a/android_softkeymaster.h b/android_softkeymaster.h
deleted file mode 100644
index 6b9efac..0000000
--- a/android_softkeymaster.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2014 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_ANDROID_SOFT_KEYMASTER_H_
-#define SYSTEM_KEYMASTER_ANDROID_SOFT_KEYMASTER_H_
-
-#include <keymaster/android_keymaster.h>
-
-#include <openssl/rand.h>
-
-#include "openssl_err.h"
-
-namespace keymaster {
-
-class AndroidSoftKeymaster : public AndroidKeymaster {
-  public:
-    AndroidSoftKeymaster(size_t operation_table_size) : AndroidKeymaster(operation_table_size) {
-        root_of_trust.tag = KM_TAG_ROOT_OF_TRUST;
-        root_of_trust.blob.data = reinterpret_cast<const uint8_t*>("SW");
-        root_of_trust.blob.data_length = 2;
-    }
-    bool is_enforced(keymaster_tag_t /* tag */) { return false; }
-    bool is_hardware() { return false; }
-
-    keymaster_error_t AddRngEntropy(const AddEntropyRequest& request) {
-        RAND_add(request.random_data.peek_read(), request.random_data.available_read(),
-                 0 /* Don't assume any entropy is added to the pool. */);
-        return KM_ERROR_OK;
-    }
-
-  private:
-    static uint8_t master_key_[];
-
-    keymaster_key_blob_t MasterKey() {
-        keymaster_key_blob_t blob;
-        blob.key_material = master_key_;
-        blob.key_material_size = 16;
-        return blob;
-    }
-
-    void GenerateNonce(uint8_t* nonce, size_t length) {
-        for (size_t i = 0; i < length; ++i)
-            nonce[i] = 0;
-    }
-
-    keymaster_key_param_t RootOfTrustTag() { return root_of_trust; }
-
-    keymaster_key_param_t root_of_trust;
-};
-
-uint8_t AndroidSoftKeymaster::master_key_[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
-}  // namespace
-
-#endif  // SYSTEM_KEYMASTER_ANDROID_SOFT_KEYMASTER_H_
diff --git a/asymmetric_key.cpp b/asymmetric_key.cpp
index 1af58ca..72c24a1 100644
--- a/asymmetric_key.cpp
+++ b/asymmetric_key.cpp
@@ -20,28 +20,36 @@
 
 #include <hardware/keymaster_defs.h>
 
-#include "ec_key.h"
 #include "openssl_err.h"
 #include "openssl_utils.h"
-#include "rsa_key.h"
-#include "unencrypted_key_blob.h"
 
 namespace keymaster {
 
-EVP_PKEY* AsymmetricKeyFactory::ExtractEvpKey(keymaster_key_format_t key_format,
-                                              keymaster_algorithm_t expected_algorithm,
-                                              const uint8_t* key_data, size_t key_data_length,
-                                              keymaster_error_t* error) {
-    *error = KM_ERROR_UNSUPPORTED_KEY_FORMAT;
+keymaster_error_t
+AsymmetricKeyFactory::KeyMaterialToEvpKey(keymaster_key_format_t key_format,
+                                          const KeymasterKeyBlob& key_material,
+                                          UniquePtr<EVP_PKEY, EVP_PKEY_Delete>* pkey) {
     if (key_format != KM_KEY_FORMAT_PKCS8)
-        return NULL;
+        return KM_ERROR_UNSUPPORTED_KEY_FORMAT;
 
-    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey;
-    *error = convert_pkcs8_blob_to_evp(key_data, key_data_length, expected_algorithm, &pkey);
-    if (*error != KM_ERROR_OK)
-        return NULL;
+    return convert_pkcs8_blob_to_evp(key_material.key_material, key_material.key_material_size,
+                                     registry_key(), pkey);
+}
 
-    return pkey.release();
+keymaster_error_t AsymmetricKeyFactory::EvpKeyToKeyMaterial(const EVP_PKEY* pkey,
+                                                            KeymasterKeyBlob* key_blob) {
+    int key_data_size = i2d_PrivateKey(pkey, NULL /* key_data*/);
+    if (key_data_size <= 0)
+        return TranslateLastOpenSslError();
+
+    key_blob->Reset(key_data_size);
+    if (!key_blob->key_material)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    uint8_t* tmp = key_blob->writable_data();
+    i2d_PrivateKey(pkey, &tmp);
+
+    return KM_ERROR_OK;
 }
 
 static const keymaster_key_format_t supported_import_formats[] = {KM_KEY_FORMAT_PKCS8};
@@ -56,20 +64,28 @@
     return supported_export_formats;
 }
 
-keymaster_error_t AsymmetricKey::LoadKey(const UnencryptedKeyBlob& blob) {
-    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> evp_key(EVP_PKEY_new());
-    if (evp_key.get() == NULL)
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+keymaster_error_t AsymmetricKeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+                                                const AuthorizationSet& hw_enforced,
+                                                const AuthorizationSet& sw_enforced,
+                                                UniquePtr<Key>* key) {
+    UniquePtr<AsymmetricKey> asymmetric_key;
+    keymaster_error_t error = CreateEmptyKey(hw_enforced, sw_enforced, &asymmetric_key);
+    if (error != KM_ERROR_OK)
+        return error;
 
-    EVP_PKEY* tmp_pkey = evp_key.get();
-    const uint8_t* key_material = blob.unencrypted_key_material();
-    if (d2i_PrivateKey(evp_key_type(), &tmp_pkey, &key_material, blob.key_material_length()) ==
-        NULL)
+    const uint8_t* tmp = key_material.key_material;
+    EVP_PKEY* pkey =
+        d2i_PrivateKey(evp_key_type(), NULL /* pkey */, &tmp, key_material.key_material_size);
+    if (!pkey)
         return TranslateLastOpenSslError();
-    if (!EvpToInternal(evp_key.get()))
-        return TranslateLastOpenSslError();
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey_deleter(pkey);
 
-    return KM_ERROR_OK;
+    if (!asymmetric_key->EvpToInternal(pkey))
+        error = TranslateLastOpenSslError();
+    else
+        key->reset(asymmetric_key.release());
+
+    return error;
 }
 
 keymaster_error_t AsymmetricKey::key_material(UniquePtr<uint8_t[]>* material, size_t* size) const {
diff --git a/asymmetric_key.h b/asymmetric_key.h
index c638dc6..04dac15 100644
--- a/asymmetric_key.h
+++ b/asymmetric_key.h
@@ -20,14 +20,29 @@
 #include <openssl/evp.h>
 
 #include "key.h"
+#include "openssl_utils.h"
 
 namespace keymaster {
 
+class AsymmetricKey;
+
 class AsymmetricKeyFactory : public KeyFactory {
-  protected:
-    EVP_PKEY* ExtractEvpKey(keymaster_key_format_t key_format,
-                            keymaster_algorithm_t expected_algorithm, const uint8_t* key_data,
-                            size_t key_data_length, keymaster_error_t* error);
+  public:
+    AsymmetricKeyFactory(const KeymasterContext* context) : KeyFactory(context) {}
+
+    keymaster_error_t KeyMaterialToEvpKey(keymaster_key_format_t key_format,
+                                          const KeymasterKeyBlob& key_material,
+                                          UniquePtr<EVP_PKEY, EVP_PKEY_Delete>* evp_pkey);
+    keymaster_error_t EvpKeyToKeyMaterial(const EVP_PKEY* evp_pkey, KeymasterKeyBlob* key_blob);
+
+    keymaster_error_t LoadKey(const KeymasterKeyBlob& key_material,
+                              const AuthorizationSet& hw_enforced,
+                              const AuthorizationSet& sw_enforced, UniquePtr<Key>* key) override;
+
+    virtual keymaster_error_t CreateEmptyKey(const AuthorizationSet& hw_enforced,
+                                             const AuthorizationSet& sw_enforced,
+                                             UniquePtr<AsymmetricKey>* key) = 0;
+    virtual int evp_key_type() = 0;
 
     virtual const keymaster_key_format_t* SupportedImportFormats(size_t* format_count);
     virtual const keymaster_key_format_t* SupportedExportFormats(size_t* format_count);
@@ -35,27 +50,15 @@
 
 class AsymmetricKey : public Key {
   public:
-  protected:
-    AsymmetricKey(const KeyBlob& blob) : Key(blob) {}
-    keymaster_error_t LoadKey(const UnencryptedKeyBlob& blob);
+    AsymmetricKey(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+                  keymaster_error_t* error)
+        : Key(hw_enforced, sw_enforced, error) {}
 
-    /**
-     * Return a copy of raw key material, in the key's preferred binary format.
-     */
-    virtual keymaster_error_t key_material(UniquePtr<uint8_t[]>* material, size_t* size) const;
+    keymaster_error_t key_material(UniquePtr<uint8_t[]>* material, size_t* size) const override;
+    keymaster_error_t formatted_key_material(keymaster_key_format_t format,
+                                             UniquePtr<uint8_t[]>* material,
+                                             size_t* size) const override;
 
-    /**
-     * Return a copy of raw key material, in the specified format.
-     */
-    virtual keymaster_error_t formatted_key_material(keymaster_key_format_t format,
-                                                     UniquePtr<uint8_t[]>* material,
-                                                     size_t* size) const;
-
-  protected:
-    AsymmetricKey(const AuthorizationSet& auths) : Key(auths) {}
-
-  private:
-    virtual int evp_key_type() = 0;
     virtual bool InternalToEvp(EVP_PKEY* pkey) const = 0;
     virtual bool EvpToInternal(const EVP_PKEY* pkey) = 0;
 };
diff --git a/auth_encrypted_key_blob.cpp b/auth_encrypted_key_blob.cpp
new file mode 100644
index 0000000..eb9e2ca
--- /dev/null
+++ b/auth_encrypted_key_blob.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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 "auth_encrypted_key_blob.h"
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/logger.h>
+
+#include "ocb_utils.h"
+
+namespace keymaster {
+
+const uint32_t CURRENT_BLOB_VERSION = 0;
+
+keymaster_error_t SerializeAuthEncryptedBlob(const KeymasterKeyBlob& encrypted_key_material,
+                                             const AuthorizationSet& hw_enforced,
+                                             const AuthorizationSet& sw_enforced,
+
+                                             const Buffer& nonce, const Buffer& tag,
+                                             KeymasterKeyBlob* key_blob) {
+    size_t size = 1 /* version byte */ + nonce.SerializedSize() +
+                  encrypted_key_material.SerializedSize() + tag.SerializedSize() +
+                  hw_enforced.SerializedSize() + sw_enforced.SerializedSize();
+
+    if (!key_blob->Reset(size))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    uint8_t* buf = key_blob->writable_data();
+    const uint8_t* end = key_blob->key_material + key_blob->key_material_size;
+
+    *buf++ = CURRENT_BLOB_VERSION;
+    buf = nonce.Serialize(buf, end);
+    buf = encrypted_key_material.Serialize(buf, end);
+    buf = tag.Serialize(buf, end);
+    buf = hw_enforced.Serialize(buf, end);
+    buf = sw_enforced.Serialize(buf, end);
+    if (buf != key_blob->key_material + key_blob->key_material_size)
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t DeserializeAuthEncryptedBlob(const KeymasterKeyBlob& key_blob,
+                                               KeymasterKeyBlob* encrypted_key_material,
+                                               AuthorizationSet* hw_enforced,
+                                               AuthorizationSet* sw_enforced, Buffer* nonce,
+                                               Buffer* tag) {
+    const uint8_t* tmp = key_blob.key_material;
+    const uint8_t** buf_ptr = &tmp;
+    const uint8_t* end = tmp + key_blob.key_material_size;
+
+    uint8_t version = *(*buf_ptr)++;
+    if (version != CURRENT_BLOB_VERSION ||  //
+        !nonce->Deserialize(buf_ptr, end) || nonce->available_read() != OCB_NONCE_LENGTH ||
+        !encrypted_key_material->Deserialize(buf_ptr, end) ||  //
+        !tag->Deserialize(buf_ptr, end) || tag->available_read() != OCB_TAG_LENGTH ||
+        !hw_enforced->Deserialize(buf_ptr, end) ||  //
+        !sw_enforced->Deserialize(buf_ptr, end))
+        return KM_ERROR_INVALID_KEY_BLOB;
+    return KM_ERROR_OK;
+}
+
+}  // namespace keymaster
diff --git a/auth_encrypted_key_blob.h b/auth_encrypted_key_blob.h
new file mode 100644
index 0000000..b987d77
--- /dev/null
+++ b/auth_encrypted_key_blob.h
@@ -0,0 +1,42 @@
+/*
+ * 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_AUTH_ENCRYPTED_KEY_BLOB_H_
+#define SYSTEM_KEYMASTER_AUTH_ENCRYPTED_KEY_BLOB_H_
+
+#include <hardware/keymaster_defs.h>
+
+namespace keymaster {
+
+class AuthorizationSet;
+class Buffer;
+struct KeymasterKeyBlob;
+
+keymaster_error_t SerializeAuthEncryptedBlob(const KeymasterKeyBlob& encrypted_key_material,
+                                             const AuthorizationSet& hw_enforced,
+                                             const AuthorizationSet& sw_enforced,
+                                             const Buffer& nonce, const Buffer& tag,
+                                             KeymasterKeyBlob* key_blob);
+
+keymaster_error_t DeserializeAuthEncryptedBlob(const KeymasterKeyBlob& key_blob,
+                                               KeymasterKeyBlob* encrypted_key_material,
+                                               AuthorizationSet* hw_enforced,
+                                               AuthorizationSet* sw_enforced, Buffer* nonce,
+                                               Buffer* tag);
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_AUTH_ENCRYPTED_KEY_BLOB_H_
diff --git a/ec_key.cpp b/ec_key.cpp
index 456ffb8..4deb1c0 100644
--- a/ec_key.cpp
+++ b/ec_key.cpp
@@ -15,43 +15,44 @@
  */
 
 #include "ec_key.h"
-#include "operation.h"
+
+#include <keymaster/keymaster_context.h>
+
 #include "openssl_err.h"
 #include "openssl_utils.h"
-#include "unencrypted_key_blob.h"
+
+#if defined(OPENSSL_IS_BORINGSSL)
+typedef size_t openssl_size_t;
+#else
+typedef int openssl_size_t;
+#endif
 
 namespace keymaster {
 
-Key* EcKeyFactory::LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) {
-    return new EcKey(blob, error);
-}
-
-Key* EcKeyFactory::GenerateKey(const AuthorizationSet& key_description,
-                               keymaster_error_t* error) {
-    if (!error)
-        return NULL;
+keymaster_error_t EcKeyFactory::GenerateKey(const AuthorizationSet& key_description,
+                                            KeymasterKeyBlob* key_blob,
+                                            AuthorizationSet* hw_enforced,
+                                            AuthorizationSet* sw_enforced) {
+    if (!key_blob || !hw_enforced || !sw_enforced)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     AuthorizationSet authorizations(key_description);
 
     uint32_t key_size;
-
     if (!authorizations.GetTagValue(TAG_KEY_SIZE, &key_size)) {
         LOG_E("%s", "No key size specified for EC key generation");
-        *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
+        return KM_ERROR_UNSUPPORTED_KEY_SIZE;
     }
 
     UniquePtr<EC_KEY, EcKey::EC_Delete> ec_key(EC_KEY_new());
     UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
-    if (ec_key.get() == NULL || pkey.get() == NULL) {
-        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
-        return NULL;
-    }
+    if (ec_key.get() == NULL || pkey.get() == NULL)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
     UniquePtr<EC_GROUP, EC_GROUP_Delete> group(choose_group(key_size));
     if (group.get() == NULL) {
-        // Technically, could also have been a memory allocation problem.
         LOG_E("Unable to get EC group for key of size %d", key_size);
-        *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
-        return NULL;
+        return KM_ERROR_UNSUPPORTED_KEY_SIZE;
     }
 
 #if !defined(OPENSSL_IS_BORINGSSL)
@@ -61,47 +62,52 @@
 
     if (EC_KEY_set_group(ec_key.get(), group.get()) != 1 ||
         EC_KEY_generate_key(ec_key.get()) != 1 || EC_KEY_check_key(ec_key.get()) < 0) {
-        *error = TranslateLastOpenSslError();
-        return NULL;
+        return TranslateLastOpenSslError();
     }
 
-    EcKey* new_key = new EcKey(ec_key.release(), authorizations);
-    *error = new_key ? KM_ERROR_OK : KM_ERROR_MEMORY_ALLOCATION_FAILED;
-    return new_key;
+    if (EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get()) != 1)
+        return TranslateLastOpenSslError();
+
+    KeymasterKeyBlob key_material;
+    keymaster_error_t error = EvpKeyToKeyMaterial(pkey.get(), &key_material);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    return context_->CreateKeyBlob(authorizations, KM_ORIGIN_GENERATED, key_material, key_blob,
+                                   hw_enforced, sw_enforced);
 }
 
-Key* EcKeyFactory::ImportKey(const AuthorizationSet& key_description,
-                             keymaster_key_format_t key_format, const uint8_t* key_data,
-                             size_t key_data_length, keymaster_error_t* error) {
-    if (!error)
-        return NULL;
+keymaster_error_t EcKeyFactory::ImportKey(const AuthorizationSet& key_description,
+                                          keymaster_key_format_t input_key_material_format,
+                                          const KeymasterKeyBlob& input_key_material,
+                                          KeymasterKeyBlob* output_key_blob,
+                                          AuthorizationSet* hw_enforced,
+                                          AuthorizationSet* sw_enforced) {
+    if (!output_key_blob || !hw_enforced || !sw_enforced)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
-    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(
-        ExtractEvpKey(key_format, registry_key(), key_data, key_data_length, error));
-    if (*error != KM_ERROR_OK)
-        return NULL;
-    assert(pkey.get());
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey;
+    keymaster_error_t error =
+        KeyMaterialToEvpKey(input_key_material_format, input_key_material, &pkey);
+    if (error != KM_ERROR_OK)
+        return error;
 
     UniquePtr<EC_KEY, EcKey::EC_Delete> ec_key(EVP_PKEY_get1_EC_KEY(pkey.get()));
-    if (!ec_key.get()) {
-        *error = TranslateLastOpenSslError();
-        return NULL;
-    }
-
-    size_t extracted_key_size_bits;
-    *error = get_group_size(*EC_KEY_get0_group(ec_key.get()), &extracted_key_size_bits);
-    if (*error != KM_ERROR_OK)
-        return NULL;
+    if (!ec_key.get())
+        return TranslateLastOpenSslError();
 
     AuthorizationSet authorizations(key_description);
 
+    size_t extracted_key_size_bits;
+    error = get_group_size(*EC_KEY_get0_group(ec_key.get()), &extracted_key_size_bits);
+    if (error != KM_ERROR_OK)
+        return error;
+
     uint32_t key_size_bits;
     if (authorizations.GetTagValue(TAG_KEY_SIZE, &key_size_bits)) {
         // key_size_bits specified, make sure it matches the key.
-        if (key_size_bits != extracted_key_size_bits) {
-            *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH;
-            return NULL;
-        }
+        if (key_size_bits != extracted_key_size_bits)
+            return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
     } else {
         // key_size_bits not specified, add it.
         authorizations.push_back(TAG_KEY_SIZE, extracted_key_size_bits);
@@ -109,18 +115,14 @@
 
     keymaster_algorithm_t algorithm;
     if (authorizations.GetTagValue(TAG_ALGORITHM, &algorithm)) {
-        if (algorithm != registry_key()) {
-            *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH;
-            return NULL;
-        }
+        if (algorithm != registry_key())
+            return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
     } else {
         authorizations.push_back(TAG_ALGORITHM, registry_key());
     }
-    // Don't bother with the other parameters.  If the necessary padding, digest, purpose, etc. are
-    // missing, the error will be diagnosed when the key is used (when auth checking is
-    // implemented).
-    *error = KM_ERROR_OK;
-    return new EcKey(ec_key.release(), authorizations);
+
+    return context_->CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material,
+                                   output_key_blob, hw_enforced, sw_enforced);
 }
 
 /* static */
@@ -164,9 +166,14 @@
     return KM_ERROR_OK;
 }
 
-EcKey::EcKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) : AsymmetricKey(blob) {
-    if (error)
-        *error = LoadKey(blob);
+keymaster_error_t EcKeyFactory::CreateEmptyKey(const AuthorizationSet& hw_enforced,
+                                               const AuthorizationSet& sw_enforced,
+                                               UniquePtr<AsymmetricKey>* key) {
+    keymaster_error_t error;
+    key->reset(new EcKey(hw_enforced, sw_enforced, &error));
+    if (!key->get())
+        error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    return error;
 }
 
 bool EcKey::EvpToInternal(const EVP_PKEY* pkey) {
diff --git a/ec_key.h b/ec_key.h
index 1748fe0..e3e15f6 100644
--- a/ec_key.h
+++ b/ec_key.h
@@ -25,11 +25,20 @@
 
 class EcKeyFactory : public AsymmetricKeyFactory {
   public:
-    Key* GenerateKey(const AuthorizationSet& key_description, keymaster_error_t* error) override;
-    Key* ImportKey(const AuthorizationSet& key_description, keymaster_key_format_t key_format,
-                   const uint8_t* key_data, size_t key_data_length,
-                   keymaster_error_t* error) override;
-    Key* LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) override;
+    EcKeyFactory(const KeymasterContext* context) : AsymmetricKeyFactory(context) {}
+
+    keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+                                  KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
+                                  AuthorizationSet* sw_enforced) override;
+    keymaster_error_t ImportKey(const AuthorizationSet& key_description,
+                                keymaster_key_format_t input_key_material_format,
+                                const KeymasterKeyBlob& input_key_material,
+                                KeymasterKeyBlob* output_key_blob, AuthorizationSet* hw_enforced,
+                                AuthorizationSet* sw_enforced) override;
+
+    keymaster_error_t CreateEmptyKey(const AuthorizationSet& hw_enforced,
+                                     const AuthorizationSet& sw_enforced,
+                                     UniquePtr<AsymmetricKey>* key) override;
 
   private:
     static EC_GROUP* choose_group(size_t key_size_bits);
@@ -42,23 +51,22 @@
 
 class EcdsaKeyFactory : public EcKeyFactory {
   public:
-    virtual keymaster_algorithm_t registry_key() const { return KM_ALGORITHM_EC; }
+    EcdsaKeyFactory(const KeymasterContext* context) : EcKeyFactory(context) {}
+
+    keymaster_algorithm_t registry_key() const override { return KM_ALGORITHM_EC; }
+    int evp_key_type() override { return EVP_PKEY_EC; }
 };
 
 class EcdsaOperationFactory;
 
 class EcKey : public AsymmetricKey {
-  private:
-    friend EcKeyFactory;
-    friend EcdsaKeyFactory;
-    friend EcdsaOperationFactory;
+  public:
+    EcKey(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+          keymaster_error_t* error)
+        : AsymmetricKey(hw_enforced, sw_enforced, error) {}
 
-    EcKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error);
-    EcKey(EC_KEY* ec_key, const AuthorizationSet auths) : AsymmetricKey(auths), ec_key_(ec_key) {}
-
-    virtual int evp_key_type() { return EVP_PKEY_EC; }
-    virtual bool InternalToEvp(EVP_PKEY* pkey) const;
-    virtual bool EvpToInternal(const EVP_PKEY* pkey);
+    bool InternalToEvp(EVP_PKEY* pkey) const override;
+    bool EvpToInternal(const EVP_PKEY* pkey) override;
 
     struct EC_Delete {
         void operator()(EC_KEY* p) { EC_KEY_free(p); }
diff --git a/ecdsa_operation.h b/ecdsa_operation.h
index 85a54d3..dd5a61f 100644
--- a/ecdsa_operation.h
+++ b/ecdsa_operation.h
@@ -21,8 +21,6 @@
 
 #include <UniquePtr.h>
 
-#include <keymaster/key_blob.h>
-
 #include "operation.h"
 
 namespace keymaster {
diff --git a/hmac_key.cpp b/hmac_key.cpp
index 294832d..1f2e4a4 100644
--- a/hmac_key.cpp
+++ b/hmac_key.cpp
@@ -23,12 +23,18 @@
 
 namespace keymaster {
 
-Key* HmacKeyFactory::LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) {
-    return new HmacKey(blob, error);
-}
+keymaster_error_t HmacKeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+                                          const AuthorizationSet& hw_enforced,
+                                          const AuthorizationSet& sw_enforced,
+                                          UniquePtr<Key>* key) {
+    if (!key)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
-SymmetricKey* HmacKeyFactory::CreateKey(const AuthorizationSet& auths) {
-    return new HmacKey(auths);
+    keymaster_error_t error;
+    key->reset(new HmacKey(key_material, hw_enforced, sw_enforced, &error));
+    if (!key->get())
+        error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    return error;
 }
 
 }  // namespace keymaster
diff --git a/hmac_key.h b/hmac_key.h
index 065effc..c5a7b91 100644
--- a/hmac_key.h
+++ b/hmac_key.h
@@ -23,21 +23,26 @@
 
 class HmacKeyFactory : public SymmetricKeyFactory {
   public:
+    HmacKeyFactory(const KeymasterContext* context) : SymmetricKeyFactory(context) {}
+
     keymaster_algorithm_t registry_key() const override { return KM_ALGORITHM_HMAC; }
 
-    Key* LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) override;
-    SymmetricKey* CreateKey(const AuthorizationSet& auths) override;
+    keymaster_error_t LoadKey(const KeymasterKeyBlob& key_material,
+                              const AuthorizationSet& hw_enforced,
+                              const AuthorizationSet& sw_enforced, UniquePtr<Key>* key) override;
+
+  private:
+    bool key_size_supported(size_t key_size_bits) const override {
+        return key_size_bits > 0 && key_size_bits % 8 == 00 &&
+               key_size_bits <= 2048 /* Some RFC test cases require >1024-bit keys */;
+    }
 };
 
 class HmacKey : public SymmetricKey {
-    static const size_t MAX_HMAC_KEY_SIZE = 256; /* Arbitrary limit, for DoS prevention */
-
   public:
-    HmacKey(const AuthorizationSet& auths) : SymmetricKey(auths) {}
-    HmacKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) : SymmetricKey(blob, error) {}
-
-  private:
-    bool size_supported(size_t key_size) const override { return key_size < MAX_HMAC_KEY_SIZE; }
+    HmacKey(const KeymasterKeyBlob& key_material, const AuthorizationSet& hw_enforced,
+            const AuthorizationSet& sw_enforced, keymaster_error_t* error)
+        : SymmetricKey(key_material, hw_enforced, sw_enforced, error) {}
 };
 
 }  // namespace keymaster
diff --git a/include/keymaster/android_keymaster.h b/include/keymaster/android_keymaster.h
index 7f8e65f..c7a3f41 100644
--- a/include/keymaster/android_keymaster.h
+++ b/include/keymaster/android_keymaster.h
@@ -23,7 +23,7 @@
 namespace keymaster {
 
 class Key;
-class UnencryptedKeyBlob;
+class KeymasterContext;
 class OperationTable;
 
 /**
@@ -46,7 +46,7 @@
  */
 class AndroidKeymaster {
   public:
-    AndroidKeymaster(size_t operation_table_size);
+    AndroidKeymaster(KeymasterContext* context, size_t operation_table_size);
     virtual ~AndroidKeymaster();
 
     void SupportedAlgorithms(SupportedResponse<keymaster_algorithm_t>* response) const;
@@ -61,7 +61,7 @@
     void SupportedExportFormats(keymaster_algorithm_t algorithm,
                                 SupportedResponse<keymaster_key_format_t>* response) const;
 
-    virtual keymaster_error_t AddRngEntropy(const AddEntropyRequest& request) = 0;
+    keymaster_error_t AddRngEntropy(const AddEntropyRequest& request);
     void GenerateKey(const GenerateKeyRequest& request, GenerateKeyResponse* response);
     void GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
                                GetKeyCharacteristicsResponse* response);
@@ -74,30 +74,12 @@
     void GetVersion(const GetVersionRequest& request, GetVersionResponse* response);
 
   private:
-    virtual bool is_enforced(keymaster_tag_t tag) = 0;
-    virtual bool is_hardware() = 0;
-    virtual keymaster_key_param_t RootOfTrustTag() = 0;
-    virtual keymaster_key_blob_t MasterKey() = 0;
-    virtual void GenerateNonce(uint8_t* nonce, size_t length) = 0;
+    keymaster_error_t LoadKey(const keymaster_key_blob_t& key_blob,
+                              const AuthorizationSet& additional_params,
+                              AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced,
+                              keymaster_algorithm_t* algorithm, UniquePtr<Key>* key);
 
-    keymaster_error_t SerializeKey(const Key* key, keymaster_key_origin_t origin,
-                                   keymaster_key_blob_t* keymaster_blob, AuthorizationSet* enforced,
-                                   AuthorizationSet* unenforced);
-    Key* LoadKey(const keymaster_key_blob_t& key, const AuthorizationSet& client_params,
-                 keymaster_algorithm_t* algorithm, keymaster_error_t* error);
-    UnencryptedKeyBlob* LoadKeyBlob(const keymaster_key_blob_t& key,
-                                    const AuthorizationSet& client_params,
-                                    keymaster_error_t* error);
-
-    keymaster_error_t SetAuthorizations(const AuthorizationSet& key_description,
-                                        keymaster_key_origin_t origin, AuthorizationSet* enforced,
-                                        AuthorizationSet* unenforced);
-    keymaster_error_t BuildHiddenAuthorizations(const AuthorizationSet& input_set,
-                                                AuthorizationSet* hidden);
-
-    void AddAuthorization(const keymaster_key_param_t& auth, AuthorizationSet* enforced,
-                          AuthorizationSet* unenforced);
-
+    UniquePtr<KeymasterContext> context_;
     UniquePtr<OperationTable> operation_table_;
 };
 
diff --git a/include/keymaster/android_keymaster_utils.h b/include/keymaster/android_keymaster_utils.h
index 20afcdd..c636f5c 100644
--- a/include/keymaster/android_keymaster_utils.h
+++ b/include/keymaster/android_keymaster_utils.h
@@ -23,6 +23,7 @@
 
 #include <UniquePtr.h>
 
+#include <hardware/keymaster_defs.h>
 #include <keymaster/serializable.h>
 
 namespace keymaster {
@@ -49,14 +50,14 @@
 /**
  * Return the size in bytes of the array \p a.
  */
-template <typename T, size_t N> inline size_t array_size(const T (&a)[N]) {
+template <typename T, size_t N> inline size_t array_size(const T(&a)[N]) {
     return sizeof(a);
 }
 
 /**
  * Return the number of elements in array \p a.
  */
-template <typename T, size_t N> inline size_t array_length(const T (&)[N]) {
+template <typename T, size_t N> inline size_t array_length(const T(&)[N]) {
     return N;
 }
 
@@ -77,7 +78,7 @@
  * responsibility.  Note that the dup is necessarily returned as a pointer, so size is lost.  Call
  * array_length() on the original array to discover the size.
  */
-template <typename T, size_t N> inline T* dup_array(const T (&a)[N]) {
+template <typename T, size_t N> inline T* dup_array(const T(&a)[N]) {
     return dup_array(a, N);
 }
 
@@ -90,7 +91,7 @@
 /**
  * Copy the contents of array \p arr to \p dest.
  */
-template <typename T, size_t N> inline void copy_array(const T (&arr)[N], T* dest) {
+template <typename T, size_t N> inline void copy_array(const T(&arr)[N], T* dest) {
     for (size_t i = 0; i < N; ++i)
         dest[i] = arr[i];
 }
@@ -100,7 +101,7 @@
  * early-exit, meaning that it should not be used in contexts where timing analysis attacks could be
  * a concern.
  */
-template <typename T, size_t N> inline bool array_contains(const T (&a)[N], T val) {
+template <typename T, size_t N> inline bool array_contains(const T(&a)[N], T val) {
     for (size_t i = 0; i < N; ++i) {
         if (a[i] == val) {
             return true;
@@ -144,9 +145,9 @@
 
     template <typename T>
     explicit Eraser(T& t)
-        : buf_(reinterpret_cast<uint8_t*> (&t)), size_(sizeof(t)) {}
+        : buf_(reinterpret_cast<uint8_t*>(&t)), size_(sizeof(t)) {}
 
-    template <size_t N> explicit Eraser(uint8_t (&arr)[N]) : buf_(arr), size_(N) {}
+    template <size_t N> explicit Eraser(uint8_t(&arr)[N]) : buf_(arr), size_(N) {}
 
     Eraser(void* buf, size_t size) : buf_(static_cast<uint8_t*>(buf)), size_(size) {}
     ~Eraser() { memset_s(buf_, 0, size_); }
@@ -206,6 +207,85 @@
     return retval;
 }
 
+/**
+ * KeymasterKeyBlob is a very simple extension of the C struct keymaster_key_blob_t.  It manages its
+ * own memory, which makes avoiding memory leaks much easier.
+ */
+struct KeymasterKeyBlob : public keymaster_key_blob_t {
+    KeymasterKeyBlob() {
+        key_material = nullptr;
+        key_material_size = 0;
+    }
+
+    KeymasterKeyBlob(const uint8_t* data, size_t size) {
+        key_material = dup_buffer(data, size);
+        key_material_size = size;
+    }
+
+    explicit KeymasterKeyBlob(size_t size) {
+        key_material = new uint8_t[size];
+        key_material_size = size;
+    }
+
+    explicit KeymasterKeyBlob(const keymaster_key_blob_t& blob) {
+        key_material = dup_buffer(blob.key_material, blob.key_material_size);
+        key_material_size = blob.key_material_size;
+    }
+
+    KeymasterKeyBlob(const KeymasterKeyBlob& blob) {
+        key_material = dup_buffer(blob.key_material, blob.key_material_size);
+        key_material_size = blob.key_material_size;
+    }
+
+    ~KeymasterKeyBlob() { Clear(); }
+
+    const uint8_t* begin() const { return key_material; }
+    const uint8_t* end() const { return key_material + key_material_size; }
+
+    void Clear() {
+        memset_s(const_cast<uint8_t*>(key_material), 0, key_material_size);
+        delete[] key_material;
+        key_material = nullptr;
+        key_material_size = 0;
+    }
+
+    const uint8_t* Reset(size_t new_size) {
+        Clear();
+        key_material = new uint8_t[new_size];
+        key_material_size = new_size;
+        return key_material;
+    }
+
+    // The key_material in keymaster_key_blob_t is const, which is the right thing in most
+    // circumstances, but occasionally we do need to write into it.  This method exposes a non-const
+    // version of the pointer.  Use sparingly.
+    uint8_t* writable_data() { return const_cast<uint8_t*>(key_material); }
+
+    keymaster_key_blob_t release() {
+        keymaster_key_blob_t tmp = {key_material, key_material_size};
+        key_material = nullptr;
+        key_material_size = 0;
+        return tmp;
+    }
+
+    size_t SerializedSize() const { return sizeof(uint32_t) + key_material_size; }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const {
+        return append_size_and_data_to_buf(buf, end, key_material, key_material_size);
+    }
+
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+        Clear();
+        UniquePtr<uint8_t[]> tmp;
+        if (!copy_size_and_data_from_buf(buf_ptr, end, &key_material_size, &tmp)) {
+            key_material = nullptr;
+            key_material_size = 0;
+            return false;
+        }
+        key_material = tmp.release();
+        return true;
+    }
+};
+
 }  // namespace keymaster
 
 #endif  // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_
diff --git a/include/keymaster/key_blob.h b/include/keymaster/key_blob.h
deleted file mode 100644
index b2a3778..0000000
--- a/include/keymaster/key_blob.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright 2014 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_KEY_BLOB_H_
-#define SYSTEM_KEYMASTER_KEY_BLOB_H_
-
-#include <cstddef>
-
-#include <stdint.h>
-
-#include <UniquePtr.h>
-
-#include <hardware/keymaster_defs.h>
-#include <keymaster/android_keymaster_utils.h>
-#include <keymaster/authorization_set.h>
-#include <keymaster/serializable.h>
-
-namespace keymaster {
-
-/**
- * This class represents a Keymaster key blob, including authorization sets and encrypted key
- * material.  It serializes and deserializes blob arrays, and provides access to the data in the
- * blob.
- */
-class KeyBlob : public Serializable {
-  public:
-    static const size_t NONCE_LENGTH = 12;
-    static const size_t TAG_LENGTH = 128 / 8;
-
-    /**
-     * Create a KeyBlob, extracting the enforced and unenforced sets.  The KeyBlob does *not* take
-     * ownership of \p key_blob.
-     *
-     * IMPORTANT: After constructing a KeyBlob, call error() to verify that the blob is usable.
-     */
-    KeyBlob(const uint8_t* key_blob, size_t key_blob_length);
-
-    /**
-     * Create a KeyBlob, extracting the enforced and unenforced sets.  The KeyBlob does *not* take
-     * ownership of \p key_blob's contents.
-     *
-     * IMPORTANT: After constructing a KeyBlob, call error() to verify that the blob is usable.
-     */
-    KeyBlob(const keymaster_key_blob_t& key_blob);
-
-    ~KeyBlob() {
-        ClearKeyData();
-        // AuthorizationSets clear themselves.
-    }
-
-    size_t SerializedSize() const;
-    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const;
-    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end);
-
-    /**
-     * Returns KM_ERROR_OK if all is well, or an appropriate error code if there is a problem.  This
-     * error code should be checked after construction or deserialization, and if it does not return
-     * KM_ERROR_OK, then don't call any other methods.
-     */
-    inline keymaster_error_t error() { return error_; }
-
-    inline const uint8_t* nonce() const { return nonce_.get(); }
-    inline const uint8_t* encrypted_key_material() const { return encrypted_key_material_.get(); }
-    inline size_t key_material_length() const { return key_material_length_; }
-    inline const uint8_t* tag() const { return tag_.get(); }
-
-    inline const AuthorizationSet& enforced() const { return enforced_; }
-    inline const AuthorizationSet& unenforced() const { return unenforced_; }
-    inline keymaster_algorithm_t algorithm() const { return algorithm_; }
-    inline size_t key_size_bits() const { return key_size_bits_; }
-    keymaster_key_origin_t origin() const;
-    bool is_hardware() const;
-
-  protected:
-    /**
-     * Create a KeyBlob containing the specified authorization data.
-     *
-     * IMPORTANT: After constructing a KeyBlob, call error() to verify that the blob is usable.
-     */
-    KeyBlob(const AuthorizationSet& enforced, const AuthorizationSet& unenforced);
-
-    /**
-     * Set encrypted key and supporting nonce and tag.  Takes ownership of all arguments.
-     */
-    void SetEncryptedKey(uint8_t* encrypted_key_material, size_t encrypted_key_material_length,
-                         uint8_t* nonce, uint8_t* tag);
-
-    keymaster_error_t error_;
-
-  private:
-    void ClearKeyData() {
-        // None of these are sensitive, but clear them anyway.
-        if (encrypted_key_material_.get())
-            memset_s(encrypted_key_material_.get(), 0, key_material_length_);
-        if (nonce_.get())
-            memset_s(nonce_.get(), 0, NONCE_LENGTH);
-        if (tag_.get())
-            memset_s(tag_.get(), 0, TAG_LENGTH);
-    }
-
-    bool DeserializeUnversionedBlob(const uint8_t** buf_ptr, const uint8_t* end);
-
-    bool ExtractKeyCharacteristics();
-
-    UniquePtr<uint8_t[]> nonce_;
-    UniquePtr<uint8_t[]> encrypted_key_material_;
-    UniquePtr<uint8_t[]> tag_;
-    size_t key_material_length_;
-    AuthorizationSet enforced_;
-    AuthorizationSet unenforced_;
-    keymaster_algorithm_t algorithm_;
-    uint32_t key_size_bits_;
-};
-
-}  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_KEY_BLOB_H_
diff --git a/include/keymaster/keymaster_context.h b/include/keymaster/keymaster_context.h
new file mode 100644
index 0000000..68410f8
--- /dev/null
+++ b/include/keymaster/keymaster_context.h
@@ -0,0 +1,110 @@
+/*
+ * 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_KEYMASTER_CONTEXT_H_
+#define SYSTEM_KEYMASTER_KEYMASTER_CONTEXT_H_
+
+#include <assert.h>
+
+#include <keymaster/authorization_set.h>
+#include <keymaster/android_keymaster_utils.h>
+
+namespace keymaster {
+
+/**
+ * KeymasterContext provides a singleton abstract interface that encapsulates various
+ * environment-dependent elements of AndroidKeymaster.
+ *
+ * AndroidKeymaster runs in multiple contexts.  Primarily:
+ *
+ * - In a trusted execution environment (TEE) as a "secure hardware" implementation.  In this
+ *   context keys are wrapped with an master key that never leaves the TEE, TEE-specific routines
+ *   are used for random number generation, all AndroidKeymaster-enforced authorizations are
+ *   considered hardware-enforced, and there's a bootloader-provided root of trust.
+ *
+ * - In the non-secure world as a software-only implementation.  In this context keys are not
+ *   encrypted (though they are integrity-checked) because there is no place to securely store a
+ *   key, OpenSSL is used for random number generation, no AndroidKeymaster-enforced authorizations
+ *   are considered hardware enforced and the root of trust is a static string.
+ *
+ * - In the non-secure world as a hybrid implementation fronting a less-capable hardware
+ *   implementation.  For example, a keymaster0 hardware implementation.  In this context keys are
+ *   not encrypted by AndroidKeymaster, but some may be opaque blobs provided by the backing
+ *   hardware, but blobs that lack the extended authorization lists of keymaster1.  In addition,
+ *   keymaster0 lacks many features of keymaster1, including modes of operation related to the
+ *   backing keymaster0 keys.  AndroidKeymaster must extend the blobs to add authorization lists,
+ *   and must provide the missing operation mode implementations in software, which means that
+ *   authorization lists are partially hardware-enforced (the bits that are enforced by the
+ *   underlying keymaster0) and partially software-enforced (the rest). OpenSSL is used for number
+ *   generation and the root of trust is a static string.
+ *
+ * More contexts are possible.
+ */
+class KeymasterContext {
+  public:
+    KeymasterContext() {}
+    virtual ~KeymasterContext() {};
+
+    /**
+     * CreateKeyBlob takes authorization sets and key material and produces a key blob and hardware
+     * and software authorization lists ready to be returned to the AndroidKeymaster client
+     * (Keystore, generally).  The blob is integrity-checked and may be encrypted, depending on the
+     * needs of the context.
+     *
+     * This method is generally called only by KeyFactory subclassses.
+     */
+    virtual keymaster_error_t CreateKeyBlob(const AuthorizationSet& key_description,
+                                            keymaster_key_origin_t origin,
+                                            const KeymasterKeyBlob& key_material,
+                                            KeymasterKeyBlob* blob, AuthorizationSet* hw_enforced,
+                                            AuthorizationSet* sw_enforced) const = 0;
+
+    /**
+     * ParseKeyBlob takes a blob and extracts authorization sets and key material, returning an
+     * error if the blob fails integrity checking or decryption.  Note that the returned key
+     * material may itself be an opaque blob usable only by secure hardware (in the hybrid case).
+     *
+     * This method is called by AndroidKeymaster.
+     */
+    virtual keymaster_error_t ParseKeyBlob(const KeymasterKeyBlob& blob,
+                                           const AuthorizationSet& additional_params,
+                                           KeymasterKeyBlob* key_material,
+                                           AuthorizationSet* hw_enforced,
+                                           AuthorizationSet* sw_enforced) const = 0;
+
+    /**
+     * Adds entropy to the Cryptographic Pseudo Random Number Generator used to generate key
+     * material, and other cryptographic protocol elements.  Note that if the underlying CPRNG
+     * tracks the size of its entropy pool, it should not assume that the provided data contributes
+     * any entropy, and it should also ensure that data provided through this interface cannot
+     * "poison" the CPRNG outputs, making them predictable.
+     */
+    virtual keymaster_error_t AddRngEntropy(const uint8_t* buf, size_t length) const = 0;
+
+    /**
+     * Generates \p length random bytes, placing them in \p buf.
+     */
+    virtual keymaster_error_t GenerateRandom(uint8_t* buf, size_t length) const = 0;
+
+  private:
+    // Uncopyable.
+    KeymasterContext(const KeymasterContext&);
+    void operator=(const KeymasterContext&);
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_KEYMASTER_CONTEXT_H_
diff --git a/include/keymaster/serializable.h b/include/keymaster/serializable.h
index b183367..e996fd8 100644
--- a/include/keymaster/serializable.h
+++ b/include/keymaster/serializable.h
@@ -194,6 +194,9 @@
         return Reinitialize(buffer.peek_read(), buffer.available_read());
     }
 
+    const uint8_t* begin() const { return peek_read(); }
+    const uint8_t* end() const { return peek_read() + available_read(); }
+
     void Clear();
 
     size_t available_write() const;
diff --git a/include/keymaster/soft_keymaster_context.h b/include/keymaster/soft_keymaster_context.h
new file mode 100644
index 0000000..1dba59d
--- /dev/null
+++ b/include/keymaster/soft_keymaster_context.h
@@ -0,0 +1,52 @@
+/*
+ * 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_CONTEXT_H_
+#define SYSTEM_KEYMASTER_SOFT_KEYMASTER_CONTEXT_H_
+
+#include <memory>
+
+#include <keymaster/keymaster_context.h>
+
+namespace keymaster {
+
+class SoftKeymasterKeyRegistrations;
+
+/**
+ * SoftKeymasterContext provides the context for a non-secure implementation of AndroidKeymaster.
+ */
+class SoftKeymasterContext : public KeymasterContext {
+  public:
+    SoftKeymasterContext();
+
+    keymaster_error_t CreateKeyBlob(const AuthorizationSet& auths, keymaster_key_origin_t origin,
+                                    const KeymasterKeyBlob& key_material, KeymasterKeyBlob* blob,
+                                    AuthorizationSet* hw_enforced,
+                                    AuthorizationSet* sw_enforced) const override;
+    keymaster_error_t ParseKeyBlob(const KeymasterKeyBlob& blob,
+                                   const AuthorizationSet& additional_params,
+                                   KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced,
+                                   AuthorizationSet* sw_enforced) const override;
+    keymaster_error_t AddRngEntropy(const uint8_t* buf, size_t length) const override;
+    keymaster_error_t GenerateRandom(uint8_t* buf, size_t length) const override;
+
+  private:
+    std::unique_ptr<SoftKeymasterKeyRegistrations> registrations_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_SOFT_KEYMASTER_CONTEXT_H_
diff --git a/include/keymaster/soft_keymaster_device.h b/include/keymaster/soft_keymaster_device.h
index 58dd2d9..44e64e9 100644
--- a/include/keymaster/soft_keymaster_device.h
+++ b/include/keymaster/soft_keymaster_device.h
@@ -51,7 +51,8 @@
     }
 
   private:
-    static keymaster_error_t ExtractSigningParams(const void* signing_params,
+    static keymaster_error_t ExtractSigningParams(const keymaster1_device_t* dev,
+                                                  const void* signing_params,
                                                   const uint8_t* key_blob, size_t key_blob_length,
                                                   AuthorizationSet* auth_set);
     static void StoreDefaultNewKeyParams(AuthorizationSet* auth_set);
diff --git a/key.cpp b/key.cpp
index ffc2b83..776ca1b 100644
--- a/key.cpp
+++ b/key.cpp
@@ -19,16 +19,19 @@
 #include <openssl/x509.h>
 
 #include "openssl_utils.h"
-#include "unencrypted_key_blob.h"
 
 namespace keymaster {
 
 /* static */
 template <> KeyFactoryRegistry* KeyFactoryRegistry::instance_ptr = 0;
 
-Key::Key(const KeyBlob& blob) {
-    authorizations_.push_back(blob.unenforced());
-    authorizations_.push_back(blob.enforced());
+Key::Key(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+         keymaster_error_t* error) {
+    assert(error);
+    authorizations_.push_back(hw_enforced);
+    authorizations_.push_back(sw_enforced);
+    *error = KM_ERROR_OK;
+    if (authorizations_.is_valid() != AuthorizationSet::OK)
+        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
 }
-
 }  // namespace keymaster
diff --git a/key.h b/key.h
index f7d2a1c..0eb1539 100644
--- a/key.h
+++ b/key.h
@@ -22,18 +22,19 @@
 #include <keymaster/logger.h>
 
 #include "abstract_factory_registry.h"
-#include "unencrypted_key_blob.h"
 
 namespace keymaster {
 
 class Key;
+class KeymasterContext;
 
 /**
- * KeyFactory is a pure interface whose subclasses know how to construct a specific subclass of Key.
+ * KeyFactory is a abstraction whose subclasses know how to construct a specific subclass of Key.
  * There is a one to one correspondence between Key subclasses and KeyFactory subclasses.
  */
 class KeyFactory {
   public:
+    KeyFactory(const KeymasterContext* context) : context_(context) {}
     virtual ~KeyFactory() {}
 
     // Required for registry
@@ -41,15 +42,27 @@
     virtual keymaster_algorithm_t registry_key() const = 0;
 
     // Factory methods.
-    virtual Key* GenerateKey(const AuthorizationSet& key_description, keymaster_error_t* error) = 0;
-    virtual Key* ImportKey(const AuthorizationSet& key_description,
-                           keymaster_key_format_t key_format, const uint8_t* key_data,
-                           size_t key_data_length, keymaster_error_t* error) = 0;
-    virtual Key* LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) = 0;
+    virtual keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+                                          KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
+                                          AuthorizationSet* sw_enforced) = 0;
+
+    virtual keymaster_error_t ImportKey(const AuthorizationSet& key_description,
+                                        keymaster_key_format_t input_key_material_format,
+                                        const KeymasterKeyBlob& input_key_material,
+                                        KeymasterKeyBlob* output_key_blob,
+                                        AuthorizationSet* hw_enforced,
+                                        AuthorizationSet* sw_enforced) = 0;
+
+    virtual keymaster_error_t LoadKey(const KeymasterKeyBlob& key_material,
+                                      const AuthorizationSet& hw_enforced,
+                                      const AuthorizationSet& sw_enforced, UniquePtr<Key>* key) = 0;
 
     // Informational methods.
     virtual const keymaster_key_format_t* SupportedImportFormats(size_t* format_count) = 0;
     virtual const keymaster_key_format_t* SupportedExportFormats(size_t* format_count) = 0;
+
+  protected:
+    const KeymasterContext* context_;
 };
 
 typedef AbstractFactoryRegistry<KeyFactory> KeyFactoryRegistry;
@@ -77,8 +90,8 @@
     const AuthorizationSet& authorizations() const { return authorizations_; }
 
   protected:
-    Key(const KeyBlob& blob);
-    Key(const AuthorizationSet& authorizations) : authorizations_(authorizations) {}
+    Key(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+        keymaster_error_t* error);
 
   private:
     AuthorizationSet authorizations_;
diff --git a/key_blob.cpp b/key_blob.cpp
deleted file mode 100644
index 4dfdc60..0000000
--- a/key_blob.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright 2014 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 <assert.h>
-
-#include <keymaster/android_keymaster_utils.h>
-#include <keymaster/key_blob.h>
-#include <keymaster/logger.h>
-
-namespace keymaster {
-
-const size_t KeyBlob::NONCE_LENGTH;
-const size_t KeyBlob::TAG_LENGTH;
-
-KeyBlob::KeyBlob(const uint8_t* key_blob, size_t key_blob_length) : error_(KM_ERROR_OK) {
-    Deserialize(&key_blob, key_blob + key_blob_length);
-}
-
-KeyBlob::KeyBlob(const keymaster_key_blob_t& key_blob) : error_(KM_ERROR_OK) {
-    const uint8_t* key_material = key_blob.key_material;
-    Deserialize(&key_material, key_blob.key_material + key_blob.key_material_size);
-}
-
-size_t KeyBlob::SerializedSize() const {
-    return 1 /* version byte */ + sizeof(uint32_t) /* nonce length */ + NONCE_LENGTH +
-           sizeof(uint32_t) + key_material_length() + sizeof(uint32_t) /* tag length */ +
-           TAG_LENGTH + enforced_.SerializedSize() + unenforced_.SerializedSize();
-}
-
-const uint8_t BLOB_VERSION = 0;
-
-uint8_t* KeyBlob::Serialize(uint8_t* buf, const uint8_t* end) const {
-    const uint8_t* start __attribute__((__unused__)) = buf;
-    *buf++ = BLOB_VERSION;
-    buf = append_size_and_data_to_buf(buf, end, nonce(), NONCE_LENGTH);
-    buf = append_size_and_data_to_buf(buf, end, encrypted_key_material(), key_material_length());
-    buf = append_size_and_data_to_buf(buf, end, tag(), TAG_LENGTH);
-    buf = enforced_.Serialize(buf, end);
-    buf = unenforced_.Serialize(buf, end);
-    assert(buf - start == static_cast<ptrdiff_t>(SerializedSize()));
-    return buf;
-}
-
-bool KeyBlob::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
-    const uint8_t* start = *buf_ptr;
-    uint8_t version = *(*buf_ptr)++;
-    size_t nonce_length;
-    size_t tag_length;
-    if (version != BLOB_VERSION ||
-        !copy_size_and_data_from_buf(buf_ptr, end, &nonce_length, &nonce_) ||
-        nonce_length != NONCE_LENGTH ||
-        !copy_size_and_data_from_buf(buf_ptr, end, &key_material_length_,
-                                     &encrypted_key_material_) ||
-        !copy_size_and_data_from_buf(buf_ptr, end, &tag_length, &tag_) ||
-        tag_length != TAG_LENGTH || !enforced_.Deserialize(buf_ptr, end) ||
-        !unenforced_.Deserialize(buf_ptr, end)) {
-        *buf_ptr = start;
-        // This blob failed to parse.  Either it's corrupted or it's a blob generated by an earlier
-        // version of keymaster using a previous blob format which did not include the version byte
-        // or the nonce or tag length fields.  So we try to parse it as that previous version.
-        //
-        // Note that it's not really a problem if we erronously parse a corrupted blob, because
-        // decryption will fail the authentication check.
-        //
-        // A bigger potential problem is: What if a valid unversioned blob appears to parse
-        // correctly as a versioned blob?  It would then be rejected during decryption, causing a
-        // valid key to become unusable.  If this is a disk encryption key, upgrading to a keymaster
-        // version with the new format would destroy the user's data.
-        //
-        // What is the probability that an unversioned key could be successfully parsed as a version
-        // 0 key?  The first 12 bytes of an unversioned key are the nonce, which, in the only
-        // keymaster version released with unversioned keys, is chosen randomly.  In order for an
-        // unversioned key to parse as a version 0 key, the following must be true about the first
-        // five of those random bytes:
-        //
-        // 1.  The first byte must be zero.  This will happen with probability 1/2^8.
-        //
-        // 2.  The second through fifth bytes must contain an unsigned integer value equal to
-        //     NONCE_LENGTH.  This will happen with probability 1/2^32.
-        //
-        // Based on those two checks alone, the probability of interpreting an unversioned blob as a
-        // version 0 blob is 1/2^40.  That's small enough to be negligible, but there are additional
-        // checks which lower it further.
-        LOG_I("Failed to deserialize versioned key blob.  Assuming unversioned.");
-        *buf_ptr = start;
-        if (!DeserializeUnversionedBlob(buf_ptr, end))
-            return false;
-    }
-    return ExtractKeyCharacteristics();
-}
-
-bool KeyBlob::DeserializeUnversionedBlob(const uint8_t** buf_ptr, const uint8_t* end) {
-    nonce_.reset(new uint8_t[NONCE_LENGTH]);
-    tag_.reset(new uint8_t[TAG_LENGTH]);
-    if (!nonce_.get() || !tag_.get()) {
-        error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
-        return false;
-    }
-
-    if (!copy_from_buf(buf_ptr, end, nonce_.get(), NONCE_LENGTH) ||
-        !copy_size_and_data_from_buf(buf_ptr, end, &key_material_length_,
-                                     &encrypted_key_material_) ||
-        !copy_from_buf(buf_ptr, end, tag_.get(), TAG_LENGTH) ||
-        !enforced_.Deserialize(buf_ptr, end) || !unenforced_.Deserialize(buf_ptr, end)) {
-        encrypted_key_material_.reset();
-        LOG_E("Failed to deserialize unversioned blob", 0);
-        error_ = KM_ERROR_INVALID_KEY_BLOB;
-        return false;
-    }
-    return ExtractKeyCharacteristics();
-}
-
-KeyBlob::KeyBlob(const AuthorizationSet& enforced, const AuthorizationSet& unenforced)
-    : error_(KM_ERROR_OK), enforced_(enforced), unenforced_(unenforced) {
-}
-
-void KeyBlob::SetEncryptedKey(uint8_t* encrypted_key_material, size_t encrypted_key_material_length,
-                              uint8_t* nonce, uint8_t* tag) {
-    ClearKeyData();
-    encrypted_key_material_.reset(encrypted_key_material);
-    key_material_length_ = encrypted_key_material_length;
-    nonce_.reset(nonce);
-    tag_.reset(tag);
-}
-
-bool KeyBlob::ExtractKeyCharacteristics() {
-    if (!enforced_.GetTagValue(TAG_ALGORITHM, &algorithm_) &&
-        !unenforced_.GetTagValue(TAG_ALGORITHM, &algorithm_)) {
-        error_ = KM_ERROR_UNSUPPORTED_ALGORITHM;
-        return false;
-    }
-    if (!enforced_.GetTagValue(TAG_KEY_SIZE, &key_size_bits_) &&
-        !unenforced_.GetTagValue(TAG_KEY_SIZE, &key_size_bits_)) {
-        error_ = KM_ERROR_UNSUPPORTED_KEY_SIZE;
-        return false;
-    }
-    return true;
-}
-
-keymaster_key_origin_t KeyBlob::origin() const {
-    keymaster_key_origin_t origin;
-    if (!enforced_.GetTagValue(TAG_ORIGIN, &origin) &&
-        !unenforced_.GetTagValue(TAG_ORIGIN, &origin))
-        // This should be impossible.
-        assert(false);
-    return origin;
-}
-
-bool KeyBlob::is_hardware() const {
-    keymaster_key_origin_t origin;
-    return enforced_.GetTagValue(TAG_ORIGIN, &origin);
-}
-
-}  // namespace keymaster
diff --git a/key_blob_test.cpp b/key_blob_test.cpp
index fc4d8cd..0c60ad2 100644
--- a/key_blob_test.cpp
+++ b/key_blob_test.cpp
@@ -25,7 +25,9 @@
 #include <keymaster/android_keymaster_utils.h>
 #include <keymaster/keymaster_tags.h>
 
-#include "unencrypted_key_blob.h"
+#include "android_keymaster_test_utils.h"
+#include "auth_encrypted_key_blob.h"
+#include "ocb_utils.h"
 
 namespace keymaster {
 
@@ -36,277 +38,254 @@
 
 class KeyBlobTest : public testing::Test {
   protected:
-    KeyBlobTest() {
-        enforced_.push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
-        enforced_.push_back(TAG_KEY_SIZE, 256);
-        enforced_.push_back(TAG_BLOB_USAGE_REQUIREMENTS, KM_BLOB_STANDALONE);
-        enforced_.push_back(TAG_MIN_SECONDS_BETWEEN_OPS, 10);
-        enforced_.push_back(TAG_ALL_USERS);
-        enforced_.push_back(TAG_NO_AUTH_REQUIRED);
-        enforced_.push_back(TAG_ORIGIN, KM_ORIGIN_GENERATED);
+    KeyBlobTest()
+        : master_key_(master_key_data, array_length(master_key_data)),
+          key_material_(key_data, array_length(key_data)) {
+        hw_enforced_.push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
+        hw_enforced_.push_back(TAG_KEY_SIZE, 256);
+        hw_enforced_.push_back(TAG_BLOB_USAGE_REQUIREMENTS, KM_BLOB_STANDALONE);
+        hw_enforced_.push_back(TAG_MIN_SECONDS_BETWEEN_OPS, 10);
+        hw_enforced_.push_back(TAG_ALL_USERS);
+        hw_enforced_.push_back(TAG_NO_AUTH_REQUIRED);
+        hw_enforced_.push_back(TAG_ORIGIN, KM_ORIGIN_GENERATED);
 
-        unenforced_.push_back(TAG_ACTIVE_DATETIME, 10);
-        unenforced_.push_back(TAG_ORIGINATION_EXPIRE_DATETIME, 100);
-        unenforced_.push_back(TAG_CREATION_DATETIME, 10);
-        unenforced_.push_back(TAG_CHUNK_LENGTH, 10);
+        sw_enforced_.push_back(TAG_ACTIVE_DATETIME, 10);
+        sw_enforced_.push_back(TAG_ORIGINATION_EXPIRE_DATETIME, 100);
+        sw_enforced_.push_back(TAG_CREATION_DATETIME, 10);
+        sw_enforced_.push_back(TAG_CHUNK_LENGTH, 10);
 
         hidden_.push_back(TAG_ROOT_OF_TRUST, "foo", 3);
         hidden_.push_back(TAG_APPLICATION_ID, "my_app", 6);
 
-        EXPECT_EQ(1, RAND_bytes(nonce_, array_size(nonce_)));
+        nonce_.reserve(OCB_NONCE_LENGTH);
+        EXPECT_EQ(1, RAND_bytes(nonce_.peek_write(), OCB_NONCE_LENGTH));
+        nonce_.advance_write(OCB_NONCE_LENGTH);
 
-        blob_.reset(new UnencryptedKeyBlob(enforced_, unenforced_, hidden_, key_data,
-                                           array_size(key_data), master_key_data,
-                                           array_size(master_key_data), nonce_));
+        tag_.reserve(OCB_TAG_LENGTH);
     }
 
-    AuthorizationSet enforced_;
-    AuthorizationSet unenforced_;
-    AuthorizationSet hidden_;
+    keymaster_error_t Encrypt() {
+        return OcbEncryptKey(hw_enforced_, sw_enforced_, hidden_, master_key_, key_material_,
+                             nonce_, &ciphertext_, &tag_);
+    }
 
-    UniquePtr<UnencryptedKeyBlob> blob_;
-    uint8_t nonce_[KeyBlob::NONCE_LENGTH];
+    keymaster_error_t Decrypt() {
+        return OcbDecryptKey(hw_enforced_, sw_enforced_, hidden_, master_key_, ciphertext_, nonce_,
+                             tag_, &decrypted_plaintext_);
+    }
+
+    keymaster_error_t Serialize() {
+        return SerializeAuthEncryptedBlob(ciphertext_, hw_enforced_, sw_enforced_, nonce_, tag_,
+                                          &serialized_blob_);
+    }
+
+    keymaster_error_t Deserialize() {
+        return DeserializeAuthEncryptedBlob(serialized_blob_, &ciphertext_, &hw_enforced_,
+                                            &sw_enforced_, &nonce_, &tag_);
+    }
+
+    AuthorizationSet hw_enforced_;
+    AuthorizationSet sw_enforced_;
+    AuthorizationSet hidden_;
+    Buffer nonce_, tag_;
+
+    KeymasterKeyBlob master_key_;
+    KeymasterKeyBlob key_material_;
+    KeymasterKeyBlob ciphertext_;
+    KeymasterKeyBlob decrypted_plaintext_;
+    KeymasterKeyBlob serialized_blob_;
 };
 
 TEST_F(KeyBlobTest, EncryptDecrypt) {
-    size_t size = blob_->SerializedSize();
-    UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
-    blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
 
-    // key_data shouldn't be anywhere in the blob.
-    uint8_t* begin = serialized_blob.get();
-    uint8_t* end = begin + size;
-    EXPECT_EQ(end, std::search(begin, end, key_data, key_data + array_size(key_data)));
+    // key_data shouldn't be anywhere in the blob, ciphertext should.
+    EXPECT_EQ(serialized_blob_.end(), std::search(serialized_blob_.begin(), serialized_blob_.end(),
+                                                  key_material_.begin(), key_material_.end()));
+    EXPECT_NE(serialized_blob_.end(), std::search(serialized_blob_.begin(), serialized_blob_.end(),
+                                                  ciphertext_.begin(), ciphertext_.end()));
 
-    // Recover the key material.
-    keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
-    UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
-                                    array_size(master_key_data));
-    EXPECT_EQ(KM_ERROR_OK, deserialized.error());
-    EXPECT_EQ(0, memcmp(deserialized.unencrypted_key_material(), key_data, array_size(key_data)));
+    ciphertext_.Clear();
+    nonce_.Clear();
+    tag_.Clear();
+    AuthorizationSet hw2;
+    AuthorizationSet sw2;
+
+    ASSERT_EQ(KM_ERROR_OK, DeserializeAuthEncryptedBlob(serialized_blob_, &ciphertext_, &hw2, &sw2,
+                                                        &nonce_, &tag_));
+    KeymasterKeyBlob plaintext;
+    OcbDecryptKey(hw2, sw2, hidden_, master_key_, ciphertext_, nonce_, tag_, &plaintext);
+
+    EXPECT_EQ(hw_enforced_, hw2);
+    EXPECT_EQ(sw_enforced_, sw2);
+
+    ASSERT_EQ(key_material_.key_material_size, plaintext.key_material_size);
+    EXPECT_EQ(0, memcmp(plaintext.begin(), key_material_.begin(), plaintext.key_material_size));
 }
 
 TEST_F(KeyBlobTest, WrongKeyLength) {
-    size_t size = blob_->SerializedSize();
-    UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
-    blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
 
-    // Modify the key length
-    serialized_blob[UnencryptedKeyBlob::NONCE_LENGTH]++;
+    // Modify the key length, shouldn't be able to parse.
+    serialized_blob_.writable_data()[1 /* version */ + 4 /* nonce len */ + 12 /* nonce */ + 3]++;
 
-    // Decrypting with wrong nonce should fail.
-    keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
-    UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
-                                    array_size(master_key_data));
-    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
+    ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Deserialize());
 }
 
 TEST_F(KeyBlobTest, WrongNonce) {
-    size_t size = blob_->SerializedSize();
-    UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
-    blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
 
     // Find the nonce, then modify it.
-    uint8_t* begin = serialized_blob.get();
-    uint8_t* end = begin + size;
-    auto nonce_ptr = std::search(begin, end, nonce_, nonce_ + array_size(nonce_));
-    ASSERT_NE(nonce_ptr, end);
-    EXPECT_EQ(end, std::search(nonce_ptr + 1, end, nonce_, nonce_ + array_size(nonce_)));
-    (*nonce_ptr)++;
+    auto nonce_ptr =
+        std::search(serialized_blob_.begin(), serialized_blob_.end(), nonce_.begin(), nonce_.end());
+    ASSERT_NE(nonce_ptr, serialized_blob_.end());
+    EXPECT_EQ(serialized_blob_.end(),
+              std::search(nonce_ptr + 1, serialized_blob_.end(), nonce_.begin(), nonce_.end()));
+    (*const_cast<uint8_t*>(nonce_ptr))++;
 
-    // Decrypting with wrong nonce should fail.
-    keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
-    UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
-                                    array_size(master_key_data));
-    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
-    EXPECT_NE(0, memcmp(deserialized.unencrypted_key_material(), key_data, array_size(key_data)));
+    // Deserialization shouldn't be affected, but decryption should fail.
+    ASSERT_EQ(KM_ERROR_OK, Deserialize());
+    ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
 }
 
 TEST_F(KeyBlobTest, WrongTag) {
-    size_t size = blob_->SerializedSize();
-    UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
-    blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
 
     // Find the tag, them modify it.
-    uint8_t* begin = serialized_blob.get();
-    uint8_t* end = begin + size;
     auto tag_ptr =
-        std::search(begin, end, blob_->tag(), blob_->tag() + UnencryptedKeyBlob::TAG_LENGTH);
-    ASSERT_NE(tag_ptr, end);
-    EXPECT_EQ(end, std::search(tag_ptr + 1, end, blob_->tag(),
-                               blob_->tag() + UnencryptedKeyBlob::TAG_LENGTH));
-    (*tag_ptr)++;
+        std::search(serialized_blob_.begin(), serialized_blob_.end(), tag_.begin(), tag_.end());
+    ASSERT_NE(tag_ptr, serialized_blob_.end());
+    EXPECT_EQ(serialized_blob_.end(),
+              std::search(tag_ptr + 1, serialized_blob_.end(), tag_.begin(), tag_.end()));
+    (*const_cast<uint8_t*>(tag_ptr))++;
 
-    // Decrypting with wrong tag should fail.
-    keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
-    UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
-                                    array_size(master_key_data));
-    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
-    EXPECT_NE(0, memcmp(deserialized.unencrypted_key_material(), key_data, array_size(key_data)));
+    // Deserialization shouldn't be affected, but decryption should fail.
+    ASSERT_EQ(KM_ERROR_OK, Deserialize());
+    ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
 }
 
 TEST_F(KeyBlobTest, WrongCiphertext) {
-    size_t size = blob_->SerializedSize();
-    UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
-    blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
 
     // Find the ciphertext, them modify it.
-    uint8_t* begin = serialized_blob.get();
-    uint8_t* end = begin + size;
-    auto ciphertext_ptr =
-        std::search(begin, end, blob_->encrypted_key_material(),
-                    blob_->encrypted_key_material() + blob_->key_material_length());
-    ASSERT_NE(ciphertext_ptr, end);
-    EXPECT_EQ(end, std::search(ciphertext_ptr + 1, end, blob_->encrypted_key_material(),
-                               blob_->encrypted_key_material() + blob_->key_material_length()));
-    (*ciphertext_ptr)++;
+    auto ciphertext_ptr = std::search(serialized_blob_.begin(), serialized_blob_.end(),
+                                      ciphertext_.begin(), ciphertext_.end());
+    ASSERT_NE(ciphertext_ptr, serialized_blob_.end());
+    EXPECT_EQ(serialized_blob_.end(), std::search(ciphertext_ptr + 1, serialized_blob_.end(),
+                                                  ciphertext_.begin(), ciphertext_.end()));
+    (*const_cast<uint8_t*>(ciphertext_ptr))++;
 
-    // Decrypting with wrong tag should fail.
-    keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
-    UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
-                                    array_size(master_key_data));
-    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
-    EXPECT_NE(0, memcmp(deserialized.unencrypted_key_material(), key_data, array_size(key_data)));
+    // Deserialization shouldn't be affected, but decryption should fail.
+    ASSERT_EQ(KM_ERROR_OK, Deserialize());
+    ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
 }
 
 TEST_F(KeyBlobTest, WrongMasterKey) {
-    size_t size = blob_->SerializedSize();
-    UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
-    blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
 
     uint8_t wrong_master_data[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    KeymasterKeyBlob wrong_master(wrong_master_data, array_length(wrong_master_data));
 
     // Decrypting with wrong master key should fail.
-    keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
-    UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, wrong_master_data,
-                                    array_size(wrong_master_data));
-    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
-    EXPECT_NE(0, memcmp(deserialized.unencrypted_key_material(), key_data, array_size(key_data)));
+    ASSERT_EQ(KM_ERROR_OK, Deserialize());
+    ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+              OcbDecryptKey(hw_enforced_, sw_enforced_, hidden_, wrong_master, ciphertext_, nonce_,
+                            tag_, &decrypted_plaintext_));
 }
 
-TEST_F(KeyBlobTest, WrongEnforced) {
-    size_t size = blob_->SerializedSize();
-    UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
-    blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
-    uint8_t* begin = serialized_blob.get();
-    uint8_t* end = begin + size;
+TEST_F(KeyBlobTest, WrongHwEnforced) {
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
 
     // Find enforced serialization data and modify it.
-    size_t enforced_size = enforced_.SerializedSize();
-    UniquePtr<uint8_t[]> enforced_data(new uint8_t[enforced_size]);
-    enforced_.Serialize(enforced_data.get(), enforced_data.get() + enforced_size);
+    size_t hw_enforced_size = hw_enforced_.SerializedSize();
+    UniquePtr<uint8_t[]> hw_enforced_data(new uint8_t[hw_enforced_size]);
+    hw_enforced_.Serialize(hw_enforced_data.get(), hw_enforced_data.get() + hw_enforced_size);
 
-    auto enforced_ptr =
-        std::search(begin, end, enforced_data.get(), enforced_data.get() + enforced_size);
-    ASSERT_NE(end, enforced_ptr);
-    EXPECT_EQ(end, std::search(enforced_ptr + 1, end, enforced_data.get(),
-                               enforced_data.get() + enforced_size));
-    (*(enforced_ptr + enforced_size - 1))++;
+    auto hw_enforced_ptr =
+        std::search(serialized_blob_.begin(), serialized_blob_.end(), hw_enforced_data.get(),
+                    hw_enforced_data.get() + hw_enforced_size);
+    ASSERT_NE(serialized_blob_.end(), hw_enforced_ptr);
+    EXPECT_EQ(serialized_blob_.end(),
+              std::search(hw_enforced_ptr + 1, serialized_blob_.end(), hw_enforced_data.get(),
+                          hw_enforced_data.get() + hw_enforced_size));
+    (*(const_cast<uint8_t*>(hw_enforced_ptr) + hw_enforced_size - 1))++;
 
-    // Decrypting with wrong unenforced data should fail.
-    keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
-    UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
-                                    array_size(master_key_data));
-    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
+    // Deserialization shouldn't be affected, but decryption should fail.
+    ASSERT_EQ(KM_ERROR_OK, Deserialize());
+    ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
 }
 
-TEST_F(KeyBlobTest, WrongUnenforced) {
-    size_t size = blob_->SerializedSize();
-    UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
-    blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
-    uint8_t* begin = serialized_blob.get();
-    uint8_t* end = begin + size;
+TEST_F(KeyBlobTest, WrongSwEnforced) {
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
 
-    // Find unenforced serialization data and modify it.
-    size_t unenforced_size = unenforced_.SerializedSize();
-    UniquePtr<uint8_t[]> unenforced_data(new uint8_t[unenforced_size]);
-    unenforced_.Serialize(unenforced_data.get(), unenforced_data.get() + unenforced_size);
+    // Find enforced serialization data and modify it.
+    size_t sw_enforced_size = sw_enforced_.SerializedSize();
+    UniquePtr<uint8_t[]> sw_enforced_data(new uint8_t[sw_enforced_size]);
+    sw_enforced_.Serialize(sw_enforced_data.get(), sw_enforced_data.get() + sw_enforced_size);
 
-    auto unenforced_ptr =
-        std::search(begin, end, unenforced_data.get(), unenforced_data.get() + unenforced_size);
-    ASSERT_NE(end, unenforced_ptr);
-    EXPECT_EQ(end, std::search(unenforced_ptr + 1, end, unenforced_data.get(),
-                               unenforced_data.get() + unenforced_size));
-    (*(unenforced_ptr + unenforced_size - 1))++;
+    auto sw_enforced_ptr =
+        std::search(serialized_blob_.begin(), serialized_blob_.end(), sw_enforced_data.get(),
+                    sw_enforced_data.get() + sw_enforced_size);
+    ASSERT_NE(serialized_blob_.end(), sw_enforced_ptr);
+    EXPECT_EQ(serialized_blob_.end(),
+              std::search(sw_enforced_ptr + 1, serialized_blob_.end(), sw_enforced_data.get(),
+                          sw_enforced_data.get() + sw_enforced_size));
+    (*(const_cast<uint8_t*>(sw_enforced_ptr) + sw_enforced_size - 1))++;
 
-    // Decrypting with wrong unenforced data should fail.
-    keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
-    UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
-                                    array_size(master_key_data));
-    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
+    // Deserialization shouldn't be affected, but decryption should fail.
+    ASSERT_EQ(KM_ERROR_OK, Deserialize());
+    ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
 }
 
 TEST_F(KeyBlobTest, EmptyHidden) {
-    size_t size = blob_->SerializedSize();
-    UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
-    blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
 
     AuthorizationSet wrong_hidden;
 
-    // Decrypting with wrong hidden data should fail.
-    keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
-    UnencryptedKeyBlob deserialized(encrypted_blob, wrong_hidden, master_key_data,
-                                    array_size(master_key_data));
-    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
+    // Deserialization shouldn't be affected, but decryption should fail.
+    ASSERT_EQ(KM_ERROR_OK, Deserialize());
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+              OcbDecryptKey(hw_enforced_, sw_enforced_, wrong_hidden, master_key_, ciphertext_,
+                            nonce_, tag_, &decrypted_plaintext_));
 }
 
 TEST_F(KeyBlobTest, WrongRootOfTrust) {
-    size_t size = blob_->SerializedSize();
-    UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
-    blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
 
     AuthorizationSet wrong_hidden;
-    wrong_hidden.push_back(TAG_ROOT_OF_TRUST, "bar", 3);
+    wrong_hidden.push_back(TAG_ROOT_OF_TRUST, "bar", 2);
     wrong_hidden.push_back(TAG_APPLICATION_ID, "my_app", 6);
 
-    // Decrypting with wrong hidden data should fail.
-    keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
-    UnencryptedKeyBlob deserialized(encrypted_blob, wrong_hidden, master_key_data,
-                                    array_size(master_key_data));
-    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
+    // Deserialization shouldn't be affected, but decryption should fail.
+    ASSERT_EQ(KM_ERROR_OK, Deserialize());
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+              OcbDecryptKey(hw_enforced_, sw_enforced_, wrong_hidden, master_key_, ciphertext_,
+                            nonce_, tag_, &decrypted_plaintext_));
 }
 
 TEST_F(KeyBlobTest, WrongAppId) {
-    size_t size = blob_->SerializedSize();
-    UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
-    blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
 
     AuthorizationSet wrong_hidden;
     wrong_hidden.push_back(TAG_ROOT_OF_TRUST, "foo", 3);
     wrong_hidden.push_back(TAG_APPLICATION_ID, "your_app", 7);
 
-    // Decrypting with wrong hidden data should fail.
-    keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
-    UnencryptedKeyBlob deserialized(encrypted_blob, wrong_hidden, master_key_data,
-                                    array_size(master_key_data));
-    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
-}
-
-TEST_F(KeyBlobTest, UnversionedBlob) {
-    // Manually construct an unversioned blob serialization.
-    size_t unversioned_blob_size =
-        KeyBlob::NONCE_LENGTH +                // nonce data
-        sizeof(uint32_t) +                     // length of key material
-        blob_->key_material_length() +         // key material data
-        KeyBlob::TAG_LENGTH +                  // tag data
-        blob_->enforced().SerializedSize() +   // serialization of enforced set
-        blob_->unenforced().SerializedSize();  // serialization of unenforced set
-    UniquePtr<uint8_t[]> unversioned_serialized_blob(new uint8_t[unversioned_blob_size]);
-    uint8_t* buf = unversioned_serialized_blob.get();
-    const uint8_t* end = buf + unversioned_blob_size;
-    buf = append_to_buf(buf, end, blob_->nonce(), KeyBlob::NONCE_LENGTH);
-    buf = append_size_and_data_to_buf(buf, end, blob_->encrypted_key_material(),
-                                      blob_->key_material_length());
-    buf = append_to_buf(buf, end, blob_->tag(), KeyBlob::TAG_LENGTH);
-    buf = blob_->enforced().Serialize(buf, end);
-    buf = blob_->unenforced().Serialize(buf, end);
-    EXPECT_EQ(buf, end);
-
-    keymaster_key_blob_t unversioned_blob = {unversioned_serialized_blob.get(),
-                                             unversioned_blob_size};
-    UnencryptedKeyBlob deserialized(unversioned_blob, hidden_, master_key_data,
-                                    array_size(master_key_data));
-    EXPECT_EQ(KM_ERROR_OK, deserialized.error());
+    // Deserialization shouldn't be affected, but decryption should fail.
+    ASSERT_EQ(KM_ERROR_OK, Deserialize());
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+              OcbDecryptKey(hw_enforced_, sw_enforced_, wrong_hidden, master_key_, ciphertext_,
+                            nonce_, tag_, &decrypted_plaintext_));
 }
 
 }  // namespace test
diff --git a/ocb_utils.cpp b/ocb_utils.cpp
new file mode 100644
index 0000000..171d07e
--- /dev/null
+++ b/ocb_utils.cpp
@@ -0,0 +1,183 @@
+/*
+ * 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 "ocb_utils.h"
+
+#include <assert.h>
+
+#include <openssl/aes.h>
+#include <openssl/sha.h>
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/android_keymaster_utils.h>
+
+#include "openssl_err.h"
+
+namespace keymaster {
+
+class AeCtx {
+  public:
+    AeCtx() : ctx_(ae_allocate(NULL)) {}
+    ~AeCtx() {
+        ae_clear(ctx_);
+        ae_free(ctx_);
+    }
+
+    ae_ctx* get() { return ctx_; }
+
+  private:
+    ae_ctx* ctx_;
+};
+
+static keymaster_error_t BuildDerivationData(const AuthorizationSet& hw_enforced,
+                                             const AuthorizationSet& sw_enforced,
+                                             const AuthorizationSet& hidden,
+                                             UniquePtr<uint8_t[]>* derivation_data,
+                                             size_t* derivation_data_length) {
+    *derivation_data_length =
+        hidden.SerializedSize() + hw_enforced.SerializedSize() + sw_enforced.SerializedSize();
+    derivation_data->reset(new uint8_t[*derivation_data_length]);
+    if (!derivation_data->get())
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    uint8_t* buf = derivation_data->get();
+    uint8_t* end = derivation_data->get() + *derivation_data_length;
+    buf = hidden.Serialize(buf, end);
+    buf = hw_enforced.Serialize(buf, end);
+    buf = sw_enforced.Serialize(buf, end);
+
+    return KM_ERROR_OK;
+}
+
+static keymaster_error_t InitializeKeyWrappingContext(const AuthorizationSet& hw_enforced,
+                                                      const AuthorizationSet& sw_enforced,
+                                                      const AuthorizationSet& hidden,
+                                                      const KeymasterKeyBlob& master_key,
+                                                      AeCtx* ctx) {
+    size_t derivation_data_length;
+    UniquePtr<uint8_t[]> derivation_data;
+    keymaster_error_t error = BuildDerivationData(hw_enforced, sw_enforced, hidden,
+                                                  &derivation_data, &derivation_data_length);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    SHA256_CTX sha256_ctx;
+    UniquePtr<uint8_t[]> hash_buf(new uint8_t[SHA256_DIGEST_LENGTH]);
+    Eraser hash_eraser(hash_buf.get(), SHA256_DIGEST_LENGTH);
+    UniquePtr<uint8_t[]> derived_key(new uint8_t[AES_BLOCK_SIZE]);
+    Eraser derived_key_eraser(derived_key.get(), AES_BLOCK_SIZE);
+
+    if (!ctx->get() || !hash_buf.get() || !derived_key.get())
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Hash derivation data.
+    Eraser sha256_ctx_eraser(sha256_ctx);
+    SHA256_Init(&sha256_ctx);
+    SHA256_Update(&sha256_ctx, derivation_data.get(), derivation_data_length);
+    SHA256_Final(hash_buf.get(), &sha256_ctx);
+
+    // Encrypt hash with master key to build derived key.
+    AES_KEY aes_key;
+    Eraser aes_key_eraser(AES_KEY);
+    if (0 !=
+        AES_set_encrypt_key(master_key.key_material, master_key.key_material_size * 8, &aes_key))
+        return TranslateLastOpenSslError();
+
+    AES_encrypt(hash_buf.get(), derived_key.get(), &aes_key);
+
+    // Set up AES OCB context using derived key.
+    if (ae_init(ctx->get(), derived_key.get(), AES_BLOCK_SIZE /* key length */, OCB_NONCE_LENGTH,
+                OCB_TAG_LENGTH) != AE_SUCCESS) {
+        memset_s(ctx->get(), 0, ae_ctx_sizeof());
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t OcbEncryptKey(const AuthorizationSet& hw_enforced,
+                                const AuthorizationSet& sw_enforced, const AuthorizationSet& hidden,
+                                const KeymasterKeyBlob& master_key,
+                                const KeymasterKeyBlob& plaintext, const Buffer& nonce,
+                                KeymasterKeyBlob* ciphertext, Buffer* tag) {
+    assert(ciphertext && tag);
+
+    if (nonce.available_read() != OCB_NONCE_LENGTH)
+        return KM_ERROR_INVALID_ARGUMENT;
+
+    AeCtx ctx;
+    keymaster_error_t error =
+        InitializeKeyWrappingContext(hw_enforced, sw_enforced, hidden, master_key, &ctx);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    ciphertext->Reset(plaintext.key_material_size);
+    if (!ciphertext->key_material)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    int ae_err = ae_encrypt(ctx.get(), nonce.peek_read(), plaintext.key_material,
+                            plaintext.key_material_size, NULL /* additional data */,
+                            0 /* additional data length */, ciphertext->writable_data(),
+                            tag->peek_write(), 1 /* final */);
+    if (ae_err < 0) {
+        LOG_E("Error %d while encrypting key", ae_err);
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+    tag->advance_write(OCB_TAG_LENGTH);
+    assert(ae_err == static_cast<int>(plaintext.key_material_size));
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t OcbDecryptKey(const AuthorizationSet& hw_enforced,
+                                const AuthorizationSet& sw_enforced, const AuthorizationSet& hidden,
+                                const KeymasterKeyBlob& master_key,
+                                const KeymasterKeyBlob& ciphertext, const Buffer& nonce,
+                                const Buffer& tag, KeymasterKeyBlob* plaintext) {
+    assert(plaintext);
+
+    if (nonce.available_read() != OCB_NONCE_LENGTH || tag.available_read() != OCB_TAG_LENGTH)
+        return KM_ERROR_INVALID_ARGUMENT;
+
+    AeCtx ctx;
+    keymaster_error_t error =
+        InitializeKeyWrappingContext(hw_enforced, sw_enforced, hidden, master_key, &ctx);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    plaintext->Reset(ciphertext.key_material_size);
+    if (!plaintext->key_material)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    int ae_err = ae_decrypt(ctx.get(), nonce.peek_read(), ciphertext.key_material,
+                            ciphertext.key_material_size, NULL /* additional data */,
+                            0 /* additional data length */, plaintext->writable_data(),
+                            tag.peek_read(), 1 /* final */);
+    if (ae_err == AE_INVALID) {
+        // Authentication failed!  Decryption probably succeeded(ish), but we don't want to return
+        // any data when the authentication fails, so clear it.
+        plaintext->Clear();
+        LOG_E("Failed to validate authentication tag during key decryption", 0);
+        return KM_ERROR_INVALID_KEY_BLOB;
+    } else if (ae_err < 0) {
+        LOG_E("Failed to decrypt key, error: %d", ae_err);
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+    assert(ae_err == static_cast<int>(ciphertext.key_material_size));
+    return KM_ERROR_OK;
+}
+
+}  // namespace keymaster
diff --git a/ocb_utils.h b/ocb_utils.h
index 2104742..bae1e08 100644
--- a/ocb_utils.h
+++ b/ocb_utils.h
@@ -19,21 +19,29 @@
 
 #include "ae.h"
 
+#include <hardware/keymaster_defs.h>
+
+#include <keymaster/serializable.h>
+
 namespace keymaster {
 
-class AeCtx {
-  public:
-    AeCtx() : ctx_(ae_allocate(NULL)) {}
-    ~AeCtx() {
-        ae_clear(ctx_);
-        ae_free(ctx_);
-    }
+class AuthorizationSet;
+struct KeymasterKeyBlob;
 
-    ae_ctx* get() { return ctx_; }
+static const int OCB_NONCE_LENGTH = 12;
+static const int OCB_TAG_LENGTH = 16;
 
-  private:
-    ae_ctx* ctx_;
-};
+keymaster_error_t OcbEncryptKey(const AuthorizationSet& hw_enforced,
+                                const AuthorizationSet& sw_enforced, const AuthorizationSet& hidden,
+                                const KeymasterKeyBlob& master_key,
+                                const KeymasterKeyBlob& plaintext, const Buffer& nonce,
+                                KeymasterKeyBlob* ciphertext, Buffer* tag);
+
+keymaster_error_t OcbDecryptKey(const AuthorizationSet& hw_enforced,
+                                const AuthorizationSet& sw_enforced, const AuthorizationSet& hidden,
+                                const KeymasterKeyBlob& master_key,
+                                const KeymasterKeyBlob& ciphertext, const Buffer& nonce,
+                                const Buffer& tag, KeymasterKeyBlob* plaintext);
 
 }  // namespace keymaster
 
diff --git a/rsa_key.cpp b/rsa_key.cpp
index 5150588..293d51e 100644
--- a/rsa_key.cpp
+++ b/rsa_key.cpp
@@ -16,10 +16,10 @@
 
 #include "rsa_key.h"
 
+#include <keymaster/keymaster_context.h>
+
 #include "openssl_err.h"
 #include "openssl_utils.h"
-#include "rsa_operation.h"
-#include "unencrypted_key_blob.h"
 
 #if defined(OPENSSL_IS_BORINGSSL)
 typedef size_t openssl_size_t;
@@ -29,66 +29,67 @@
 
 namespace keymaster {
 
-Key* RsaKeyFactory::LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) {
-    return new RsaKey(blob, error);
-}
-
-Key* RsaKeyFactory::GenerateKey(const AuthorizationSet& key_description, keymaster_error_t* error) {
-    if (!error)
-        return NULL;
+keymaster_error_t RsaKeyFactory::GenerateKey(const AuthorizationSet& key_description,
+                                             KeymasterKeyBlob* key_blob,
+                                             AuthorizationSet* hw_enforced,
+                                             AuthorizationSet* sw_enforced) {
+    if (!key_blob || !hw_enforced || !sw_enforced)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     AuthorizationSet authorizations(key_description);
 
     uint64_t public_exponent;
     if (!authorizations.GetTagValue(TAG_RSA_PUBLIC_EXPONENT, &public_exponent)) {
         LOG_E("%s", "No public exponent specified for RSA key generation");
-        *error = KM_ERROR_INVALID_ARGUMENT;
-        return NULL;
+        return KM_ERROR_INVALID_ARGUMENT;
     }
 
     uint32_t key_size;
     if (!authorizations.GetTagValue(TAG_KEY_SIZE, &key_size)) {
         LOG_E("%s", "No key size specified for RSA key generation");
-        *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
-        return NULL;
+        return KM_ERROR_UNSUPPORTED_KEY_SIZE;
     }
 
     UniquePtr<BIGNUM, BIGNUM_Delete> exponent(BN_new());
     UniquePtr<RSA, RsaKey::RSA_Delete> rsa_key(RSA_new());
     UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
-    if (exponent.get() == NULL || rsa_key.get() == NULL || pkey.get() == NULL) {
-        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
-        return NULL;
-    }
+    if (exponent.get() == NULL || rsa_key.get() == NULL || pkey.get() == NULL)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     if (!BN_set_word(exponent.get(), public_exponent) ||
-        !RSA_generate_key_ex(rsa_key.get(), key_size, exponent.get(), NULL /* callback */)) {
-        *error = TranslateLastOpenSslError();
-        return NULL;
-    }
+        !RSA_generate_key_ex(rsa_key.get(), key_size, exponent.get(), NULL /* callback */))
+        return TranslateLastOpenSslError();
 
-    RsaKey* new_key = new RsaKey(rsa_key.release(), authorizations);
-    *error = new_key ? KM_ERROR_OK : KM_ERROR_MEMORY_ALLOCATION_FAILED;
-    return new_key;
+    if (EVP_PKEY_set1_RSA(pkey.get(), rsa_key.get()) != 1)
+        return TranslateLastOpenSslError();
+
+    KeymasterKeyBlob key_material;
+    keymaster_error_t error = EvpKeyToKeyMaterial(pkey.get(), &key_material);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    return context_->CreateKeyBlob(authorizations, KM_ORIGIN_GENERATED, key_material, key_blob,
+                                   hw_enforced, sw_enforced);
 }
 
-Key* RsaKeyFactory::ImportKey(const AuthorizationSet& key_description,
-                              keymaster_key_format_t key_format, const uint8_t* key_data,
-                              size_t key_data_length, keymaster_error_t* error) {
-    if (!error)
-        return NULL;
+keymaster_error_t RsaKeyFactory::ImportKey(const AuthorizationSet& key_description,
+                                           keymaster_key_format_t input_key_material_format,
+                                           const KeymasterKeyBlob& input_key_material,
+                                           KeymasterKeyBlob* output_key_blob,
+                                           AuthorizationSet* hw_enforced,
+                                           AuthorizationSet* sw_enforced) {
+    if (!output_key_blob || !hw_enforced || !sw_enforced)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
-    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(
-        ExtractEvpKey(key_format, KM_ALGORITHM_RSA, key_data, key_data_length, error));
-    if (*error != KM_ERROR_OK)
-        return NULL;
-    assert(pkey.get());
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey;
+    keymaster_error_t error =
+        KeyMaterialToEvpKey(input_key_material_format, input_key_material, &pkey);
+    if (error != KM_ERROR_OK)
+        return error;
 
     UniquePtr<RSA, RsaKey::RSA_Delete> rsa_key(EVP_PKEY_get1_RSA(pkey.get()));
-    if (!rsa_key.get()) {
-        *error = TranslateLastOpenSslError();
-        return NULL;
-    }
+    if (!rsa_key.get())
+        return TranslateLastOpenSslError();
 
     AuthorizationSet authorizations(key_description);
 
@@ -97,28 +98,22 @@
         // public_exponent specified, make sure it matches the key
         UniquePtr<BIGNUM, BIGNUM_Delete> public_exponent_bn(BN_new());
         if (!BN_set_word(public_exponent_bn.get(), public_exponent))
-            return NULL;
-        if (BN_cmp(public_exponent_bn.get(), rsa_key->e) != 0) {
-            *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH;
-            return NULL;
-        }
+            return KM_ERROR_UNKNOWN_ERROR;
+        if (BN_cmp(public_exponent_bn.get(), rsa_key->e) != 0)
+            return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
     } else {
         // public_exponent not specified, use the one from the key.
         public_exponent = BN_get_word(rsa_key->e);
-        if (public_exponent == 0xffffffffL) {
-            *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH;
-            return NULL;
-        }
+        if (public_exponent == 0xffffffffL)
+            return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
         authorizations.push_back(TAG_RSA_PUBLIC_EXPONENT, public_exponent);
     }
 
     uint32_t key_size;
     if (authorizations.GetTagValue(TAG_KEY_SIZE, &key_size)) {
         // key_size specified, make sure it matches the key.
-        if (RSA_size(rsa_key.get()) * 8 != (openssl_size_t)key_size) {
-            *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH;
-            return NULL;
-        }
+        if (RSA_size(rsa_key.get()) * 8 != (openssl_size_t)key_size)
+            return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
     } else {
         key_size = RSA_size(rsa_key.get()) * 8;
         authorizations.push_back(TAG_KEY_SIZE, key_size);
@@ -126,28 +121,24 @@
 
     keymaster_algorithm_t algorithm;
     if (authorizations.GetTagValue(TAG_ALGORITHM, &algorithm)) {
-        if (algorithm != KM_ALGORITHM_RSA) {
-            *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH;
-            return NULL;
-        }
+        if (algorithm != KM_ALGORITHM_RSA)
+            return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
     } else {
         authorizations.push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
     }
 
-    // Don't bother with the other parameters.  If the necessary padding, digest, purpose, etc. are
-    // missing, the error will be diagnosed when the key is used (when auth checking is
-    // implemented).
-    *error = KM_ERROR_OK;
-    return new RsaKey(rsa_key.release(), authorizations);
+    return context_->CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material,
+                                   output_key_blob, hw_enforced, sw_enforced);
 }
 
-RsaKey::RsaKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) : AsymmetricKey(blob) {
-    if (error)
-        *error = LoadKey(blob);
-}
-
-RSA* RsaKey::key() const {
-    return rsa_key_.get();
+keymaster_error_t RsaKeyFactory::CreateEmptyKey(const AuthorizationSet& hw_enforced,
+                                                const AuthorizationSet& sw_enforced,
+                                                UniquePtr<AsymmetricKey>* key) {
+    keymaster_error_t error;
+    key->reset(new RsaKey(hw_enforced, sw_enforced, &error));
+    if (!key->get())
+        error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    return error;
 }
 
 bool RsaKey::EvpToInternal(const EVP_PKEY* pkey) {
diff --git a/rsa_key.h b/rsa_key.h
index 129f774..e5b4051 100644
--- a/rsa_key.h
+++ b/rsa_key.h
@@ -25,25 +25,33 @@
 
 class RsaKeyFactory : public AsymmetricKeyFactory {
   public:
+    RsaKeyFactory(const KeymasterContext* context) : AsymmetricKeyFactory(context) {}
+
     keymaster_algorithm_t registry_key() const override { return KM_ALGORITHM_RSA; }
-    Key* GenerateKey(const AuthorizationSet& key_description, keymaster_error_t* error);
-    Key* ImportKey(const AuthorizationSet& key_description, keymaster_key_format_t key_format,
-                   const uint8_t* key_data, size_t key_data_length,
-                   keymaster_error_t* error) override;
-    Key* LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) override;
+    int evp_key_type() override { return EVP_PKEY_RSA; }
+
+    keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+                                  KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
+                                  AuthorizationSet* sw_enforced) override;
+    keymaster_error_t ImportKey(const AuthorizationSet& key_description,
+                                keymaster_key_format_t input_key_material_format,
+                                const KeymasterKeyBlob& input_key_material,
+                                KeymasterKeyBlob* output_key_blob, AuthorizationSet* hw_enforced,
+                                AuthorizationSet* sw_enforced) override;
+
+    keymaster_error_t CreateEmptyKey(const AuthorizationSet& hw_enforced,
+                                     const AuthorizationSet& sw_enforced,
+                                     UniquePtr<AsymmetricKey>* key) override;
 };
 
 class RsaOperationFactory;
 
 class RsaKey : public AsymmetricKey {
-  private:
-    friend class RsaKeyFactory;
-    friend class RsaOperationFactory;
+  public:
+    RsaKey(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+           keymaster_error_t* error)
+        : AsymmetricKey(hw_enforced, sw_enforced, error) {}
 
-    RsaKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error);
-    RsaKey(RSA* rsa_key, const AuthorizationSet& auths) : AsymmetricKey(auths), rsa_key_(rsa_key) {}
-
-    int evp_key_type() override { return EVP_PKEY_RSA; }
     bool InternalToEvp(EVP_PKEY* pkey) const override;
     bool EvpToInternal(const EVP_PKEY* pkey) override;
 
@@ -54,9 +62,10 @@
         void operator()(RSA* p) { RSA_free(p); }
     };
 
-    RSA* key() const;
+    RSA* key() const { return rsa_key_.get(); }
 
-    mutable UniquePtr<RSA, RSA_Delete> rsa_key_;
+  private:
+    UniquePtr<RSA, RSA_Delete> rsa_key_;
 };
 
 }  // namespace keymaster
diff --git a/rsa_operation.h b/rsa_operation.h
index ea8d81d..586aaa1 100644
--- a/rsa_operation.h
+++ b/rsa_operation.h
@@ -22,8 +22,6 @@
 #include <openssl/evp.h>
 #include <openssl/rsa.h>
 
-#include <keymaster/key_blob.h>
-
 #include "operation.h"
 
 namespace keymaster {
diff --git a/soft_keymaster_context.cpp b/soft_keymaster_context.cpp
new file mode 100644
index 0000000..0745a5e
--- /dev/null
+++ b/soft_keymaster_context.cpp
@@ -0,0 +1,194 @@
+/*
+ * 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 <keymaster/soft_keymaster_context.h>
+
+#include <time.h>
+
+#include <openssl/aes.h>
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/logger.h>
+
+#include "aes_key.h"
+#include "auth_encrypted_key_blob.h"
+#include "ec_key.h"
+#include "hmac_key.h"
+#include "ocb_utils.h"
+#include "openssl_err.h"
+#include "rsa_key.h"
+
+namespace keymaster {
+
+namespace {
+static uint8_t master_key_bytes[AES_BLOCK_SIZE] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+const int NONCE_LENGTH = 12;
+const int TAG_LENGTH = 16;
+const KeymasterKeyBlob MASTER_KEY(master_key_bytes, array_length(master_key_bytes));
+}  // anonymous namespace
+
+class SoftKeymasterKeyRegistrations {
+  public:
+    SoftKeymasterKeyRegistrations(const KeymasterContext* context)
+        : rsa_(context), ec_(context), hmac_(context), aes_(context) {}
+
+    KeyFactoryRegistry::Registration<RsaKeyFactory> rsa_;
+    KeyFactoryRegistry::Registration<EcdsaKeyFactory> ec_;
+    KeyFactoryRegistry::Registration<HmacKeyFactory> hmac_;
+    KeyFactoryRegistry::Registration<AesKeyFactory> aes_;
+};
+
+SoftKeymasterContext::SoftKeymasterContext()
+    : registrations_(new SoftKeymasterKeyRegistrations(this)) {
+}
+
+static keymaster_error_t TranslateAuthorizationSetError(AuthorizationSet::Error err) {
+    switch (err) {
+    case AuthorizationSet::OK:
+        return KM_ERROR_OK;
+    case AuthorizationSet::ALLOCATION_FAILURE:
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    case AuthorizationSet::MALFORMED_DATA:
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+    return KM_ERROR_OK;
+}
+
+static keymaster_error_t BuildHiddenAuthorizations(const AuthorizationSet& input_set,
+                                                   AuthorizationSet* hidden) {
+    keymaster_blob_t entry;
+    if (input_set.GetTagValue(TAG_APPLICATION_ID, &entry))
+        hidden->push_back(TAG_APPLICATION_ID, entry.data, entry.data_length);
+    if (input_set.GetTagValue(TAG_APPLICATION_DATA, &entry))
+        hidden->push_back(TAG_APPLICATION_DATA, entry.data, entry.data_length);
+
+    keymaster_key_param_t root_of_trust;
+    root_of_trust.tag = KM_TAG_ROOT_OF_TRUST;
+    root_of_trust.blob.data = reinterpret_cast<const uint8_t*>("SW");
+    root_of_trust.blob.data_length = 2;
+    hidden->push_back(root_of_trust);
+
+    return TranslateAuthorizationSetError(hidden->is_valid());
+}
+
+static keymaster_error_t SetAuthorizations(const AuthorizationSet& key_description,
+                                           keymaster_key_origin_t origin,
+                                           AuthorizationSet* hw_enforced,
+                                           AuthorizationSet* sw_enforced) {
+    hw_enforced->Clear();
+    sw_enforced->Clear();
+    for (size_t i = 0; i < key_description.size(); ++i) {
+        switch (key_description[i].tag) {
+        // These cannot be specified by the client.
+        case KM_TAG_ROOT_OF_TRUST:
+        case KM_TAG_ORIGIN:
+            LOG_E("Root of trust and origin tags may not be specified", 0);
+            return KM_ERROR_INVALID_TAG;
+
+        // These don't work.
+        case KM_TAG_ROLLBACK_RESISTANT:
+            LOG_E("KM_TAG_ROLLBACK_RESISTANT not supported", 0);
+            return KM_ERROR_UNSUPPORTED_TAG;
+
+        // These are hidden.
+        case KM_TAG_APPLICATION_ID:
+        case KM_TAG_APPLICATION_DATA:
+            break;
+
+        // Everything else we just copy into sw_enforced.
+        default:
+            sw_enforced->push_back(key_description[i]);
+            break;
+        }
+    }
+
+    sw_enforced->push_back(TAG_CREATION_DATETIME, java_time(time(NULL)));
+    sw_enforced->push_back(TAG_ORIGIN, origin);
+    return TranslateAuthorizationSetError(sw_enforced->is_valid());
+}
+
+keymaster_error_t SoftKeymasterContext::CreateKeyBlob(const AuthorizationSet& key_description,
+                                                      const keymaster_key_origin_t origin,
+                                                      const KeymasterKeyBlob& key_material,
+                                                      KeymasterKeyBlob* blob,
+                                                      AuthorizationSet* hw_enforced,
+                                                      AuthorizationSet* sw_enforced) const {
+
+    keymaster_error_t error;
+
+    error = SetAuthorizations(key_description, origin, hw_enforced, sw_enforced);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    AuthorizationSet hidden;
+    error = BuildHiddenAuthorizations(key_description, &hidden);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    Buffer nonce, tag;
+    if (!nonce.reserve(OCB_NONCE_LENGTH) || !tag.reserve(OCB_TAG_LENGTH))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    GenerateRandom(nonce.peek_write(), OCB_NONCE_LENGTH);
+    nonce.advance_write(OCB_NONCE_LENGTH);
+
+    KeymasterKeyBlob encrypted_key;
+    error = OcbEncryptKey(*hw_enforced, *sw_enforced, hidden, MASTER_KEY, key_material, nonce,
+                          &encrypted_key, &tag);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    return SerializeAuthEncryptedBlob(encrypted_key, *hw_enforced, *sw_enforced, nonce, tag, blob);
+}
+
+keymaster_error_t SoftKeymasterContext::ParseKeyBlob(const KeymasterKeyBlob& blob,
+                                                     const AuthorizationSet& additional_params,
+                                                     KeymasterKeyBlob* key_material,
+                                                     AuthorizationSet* hw_enforced,
+                                                     AuthorizationSet* sw_enforced) const {
+    Buffer nonce, tag;
+    KeymasterKeyBlob encrypted_key_material;
+    keymaster_error_t error = DeserializeAuthEncryptedBlob(blob, &encrypted_key_material,
+                                                           hw_enforced, sw_enforced, &nonce, &tag);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    AuthorizationSet hidden;
+    error = BuildHiddenAuthorizations(additional_params, &hidden);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    if (nonce.available_read() != OCB_NONCE_LENGTH || tag.available_read() != OCB_TAG_LENGTH)
+        return KM_ERROR_INVALID_KEY_BLOB;
+
+    return OcbDecryptKey(*hw_enforced, *sw_enforced, hidden, MASTER_KEY, encrypted_key_material,
+                         nonce, tag, key_material);
+}
+
+keymaster_error_t SoftKeymasterContext::AddRngEntropy(const uint8_t* buf, size_t length) const {
+    RAND_add(buf, length, 0 /* Don't assume any entropy is added to the pool. */);
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t SoftKeymasterContext::GenerateRandom(uint8_t* buf, size_t length) const {
+    if (RAND_bytes(buf, length) != 1)
+        return KM_ERROR_UNKNOWN_ERROR;
+    return KM_ERROR_OK;
+}
+
+}  // namespace keymaster
diff --git a/soft_keymaster_device.cpp b/soft_keymaster_device.cpp
index 18ac3e6..3e92061 100644
--- a/soft_keymaster_device.cpp
+++ b/soft_keymaster_device.cpp
@@ -33,16 +33,13 @@
 #define LOG_TAG "SoftKeymasterDevice"
 #include <cutils/log.h>
 
-#include <keymaster/authorization_set.h>
+#include <keymaster/android_keymaster.h>
 #include <keymaster/android_keymaster_messages.h>
-#include <keymaster/key_blob.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/soft_keymaster_context.h>
 #include <keymaster/soft_keymaster_logger.h>
 
-#include "aes_key.h"
-#include "ec_key.h"
-#include "android_softkeymaster.h"
-#include "hmac_key.h"
-#include "rsa_key.h"
+#include "openssl_utils.h"
 
 struct keystore_module soft_keymaster_device_module = {
     .common =
@@ -61,12 +58,8 @@
 
 namespace keymaster {
 
-static KeyFactoryRegistry::Registration<AesKeyFactory> aes_registration;
-static KeyFactoryRegistry::Registration<EcdsaKeyFactory> ec_registration;
-static KeyFactoryRegistry::Registration<HmacKeyFactory> hmac_registration;
-static KeyFactoryRegistry::Registration<RsaKeyFactory> rsa_registration;
-
-SoftKeymasterDevice::SoftKeymasterDevice() : impl_(new AndroidSoftKeymaster(16)) {
+SoftKeymasterDevice::SoftKeymasterDevice()
+    : impl_(new AndroidKeymaster(new SoftKeymasterContext, 16)) {
 #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
     static_assert(std::is_standard_layout<SoftKeymasterDevice>::value,
                   "SoftKeymasterDevice must be standard layout");
@@ -265,14 +258,6 @@
     return KM_ERROR_OK;
 }
 
-struct EVP_PKEY_Delete {
-    void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
-};
-
-struct PKCS8_PRIV_KEY_INFO_Delete {
-    void operator()(PKCS8_PRIV_KEY_INFO* p) const { PKCS8_PRIV_KEY_INFO_free(p); }
-};
-
 /* static */
 keymaster_error_t SoftKeymasterDevice::GetPkcs8KeyAlgorithm(const uint8_t* key, size_t key_length,
                                                             keymaster_algorithm_t* algorithm) {
@@ -360,8 +345,8 @@
     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);
+    keymaster_error_t err = ExtractSigningParams(dev, params, key_blob, key_blob_length,
+                                                 &begin_request.additional_params);
     if (err != KM_ERROR_OK)
         return err;
 
@@ -413,12 +398,10 @@
     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;
-    }
+    keymaster_error_t err = ExtractSigningParams(dev, 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);
@@ -859,15 +842,28 @@
 }
 
 /* static */
-keymaster_error_t SoftKeymasterDevice::ExtractSigningParams(const void* signing_params,
+keymaster_error_t SoftKeymasterDevice::ExtractSigningParams(const keymaster1_device_t* dev,
+                                                            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();
+    const keymaster_blob_t client_id = {nullptr, 0};
+    const keymaster_blob_t app_data = {nullptr, 0};
+    const keymaster_key_blob_t blob = {key_blob, key_blob_length};
+    keymaster_key_characteristics_t* characteristics;
+    keymaster_error_t error =
+        get_key_characteristics(dev, &blob, &client_id, &app_data, &characteristics);
 
-    switch (blob.algorithm()) {
+    if (error != KM_ERROR_OK)
+        return error;
+
+    AuthorizationSet auths(characteristics->hw_enforced);
+    auths.push_back(AuthorizationSet(characteristics->sw_enforced));
+    keymaster_algorithm_t algorithm;
+    if (!auths.GetTagValue(TAG_ALGORITHM, &algorithm))
+        return KM_ERROR_INVALID_KEY_BLOB;
+
+    switch (algorithm) {
     case KM_ALGORITHM_RSA: {
         const keymaster_rsa_sign_params_t* rsa_params =
             reinterpret_cast<const keymaster_rsa_sign_params_t*>(signing_params);
diff --git a/symmetric_key.cpp b/symmetric_key.cpp
index e1ce39f..68fa6f1 100644
--- a/symmetric_key.cpp
+++ b/symmetric_key.cpp
@@ -22,53 +22,73 @@
 #include <openssl/rand.h>
 
 #include <keymaster/logger.h>
+#include <keymaster/keymaster_context.h>
 
 #include "aes_key.h"
 #include "hmac_key.h"
 #include "openssl_err.h"
-#include "unencrypted_key_blob.h"
 
 namespace keymaster {
 
-Key* SymmetricKeyFactory::GenerateKey(const AuthorizationSet& key_description,
-                                      keymaster_error_t* error) {
-    UniquePtr<SymmetricKey> key(CreateKeyAndValidateSize(key_description, error));
-    if (!key.get())
-        return NULL;
+keymaster_error_t SymmetricKeyFactory::GenerateKey(const AuthorizationSet& key_description,
+                                                   KeymasterKeyBlob* key_blob,
+                                                   AuthorizationSet* hw_enforced,
+                                                   AuthorizationSet* sw_enforced) {
+    if (!key_blob || !hw_enforced || !sw_enforced)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
-    if (RAND_bytes(key->key_data_.get(), key->key_data_size_) != 1) {
-        LOG_E("Error %ul generating %d bit AES key", ERR_get_error(), key->key_data_size_ * 8);
-        *error = TranslateLastOpenSslError();
-        return NULL;
+    uint32_t key_size_bits;
+    if (!key_description.GetTagValue(TAG_KEY_SIZE, &key_size_bits) ||
+        !key_size_supported(key_size_bits))
+        return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+
+    size_t key_data_size = key_size_bits / 8;
+    KeymasterKeyBlob key_material(key_data_size);
+    if (!key_material.key_material)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    keymaster_error_t error = context_->GenerateRandom(key_material.writable_data(), key_data_size);
+    if (error != KM_ERROR_OK) {
+        LOG_E("Error generating %d bit symmetric key", key_size_bits);
+        return error;
     }
 
-    if (*error != KM_ERROR_OK)
-        return NULL;
-    return key.release();
+    return context_->CreateKeyBlob(key_description, KM_ORIGIN_GENERATED, key_material, key_blob,
+                                   hw_enforced, sw_enforced);
 }
 
-Key* SymmetricKeyFactory::ImportKey(const AuthorizationSet& key_description,
-                                    keymaster_key_format_t format, const uint8_t* key_material,
-                                    size_t key_material_length, keymaster_error_t* error) {
-    UniquePtr<SymmetricKey> key(CreateKeyAndValidateSize(key_description, error));
-    if (!key.get())
-        return NULL;
+keymaster_error_t SymmetricKeyFactory::ImportKey(const AuthorizationSet& key_description,
+                                                 keymaster_key_format_t input_key_material_format,
+                                                 const KeymasterKeyBlob& input_key_material,
+                                                 KeymasterKeyBlob* output_key_blob,
+                                                 AuthorizationSet* hw_enforced,
+                                                 AuthorizationSet* sw_enforced) {
+    if (!output_key_blob || !hw_enforced || !sw_enforced)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
-    if (format != KM_KEY_FORMAT_RAW) {
-        *error = KM_ERROR_UNSUPPORTED_KEY_FORMAT;
-        return NULL;
+    AuthorizationSet authorizations(key_description);
+
+    uint32_t key_size_bits;
+    if (!authorizations.GetTagValue(TAG_KEY_SIZE, &key_size_bits)) {
+        // Default key size if not specified.
+        key_size_bits = input_key_material.key_material_size * 8;
+        authorizations.push_back(TAG_KEY_SIZE, key_size_bits);
     }
 
-    if (key->key_data_size_ != key_material_length) {
-        LOG_E("Expected %d byte key data but got %d bytes", key->key_data_size_,
-              key_material_length);
-        *error = KM_ERROR_INVALID_KEY_BLOB;
-        return NULL;
+    if (!key_size_supported(key_size_bits))
+        return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+
+    if (input_key_material_format != KM_KEY_FORMAT_RAW)
+        return KM_ERROR_UNSUPPORTED_KEY_FORMAT;
+
+    if (key_size_bits != input_key_material.key_material_size * 8) {
+        LOG_E("Expected %d-bit key data but got %d bits", key_size_bits,
+              input_key_material.key_material_size * 8);
+        return KM_ERROR_INVALID_KEY_BLOB;
     }
 
-    key->key_data_size_ = key_material_length;
-    memcpy(key->key_data_.get(), key_material, key_material_length);
-    return key.release();
+    return context_->CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material,
+                                   output_key_blob, hw_enforced, sw_enforced);
 }
 
 static const keymaster_key_format_t supported_import_formats[] = {KM_KEY_FORMAT_RAW};
@@ -77,40 +97,21 @@
     return supported_import_formats;
 }
 
-SymmetricKey* SymmetricKeyFactory::CreateKeyAndValidateSize(const AuthorizationSet& key_description,
-                                                            keymaster_error_t* error) {
-    if (!error)
-        return NULL;
-    *error = KM_ERROR_OK;
-
-    UniquePtr<SymmetricKey> key(CreateKey(key_description));
-
-    uint32_t key_size_bits;
-    if (!key_description.GetTagValue(TAG_KEY_SIZE, &key_size_bits) || key_size_bits % 8 != 0) {
-        *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
-        return NULL;
-    }
-
-    *error = key->set_size(key_size_bits / 8);
+SymmetricKey::SymmetricKey(const KeymasterKeyBlob& key_material,
+                           const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+                           keymaster_error_t* error)
+    : Key(hw_enforced, sw_enforced, error) {
     if (*error != KM_ERROR_OK)
-        return NULL;
-
-    return key.release();
-}
-
-SymmetricKey::SymmetricKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error)
-    : Key(blob), key_data_size_(blob.unencrypted_key_material_length()) {
-    key_data_.reset(new uint8_t[key_data_size_]);
-    if (!key_data_.get()) {
-        if (error)
-            *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
-        key_data_size_ = 0;
         return;
-    }
 
-    memcpy(key_data_.get(), blob.unencrypted_key_material(), key_data_size_);
-    if (error)
+    uint8_t* tmp = dup_buffer(key_material.key_material, key_material.key_material_size);
+    if (tmp) {
+        key_data_.reset(tmp);
+        key_data_size_ = key_material.key_material_size;
         *error = KM_ERROR_OK;
+    } else {
+        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 }
 
 SymmetricKey::~SymmetricKey() {
@@ -127,16 +128,4 @@
     return KM_ERROR_OK;
 }
 
-keymaster_error_t SymmetricKey::set_size(size_t key_size) {
-    if (!size_supported(key_size))
-        return KM_ERROR_UNSUPPORTED_KEY_SIZE;
-
-    key_data_.reset(new uint8_t[key_size]);
-    if (!key_data_.get())
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-    key_data_size_ = key_size;
-
-    return KM_ERROR_OK;
-}
-
 }  // namespace keymaster
diff --git a/symmetric_key.h b/symmetric_key.h
index 7662a4a..3e39364 100644
--- a/symmetric_key.h
+++ b/symmetric_key.h
@@ -24,9 +24,17 @@
 class SymmetricKey;
 
 class SymmetricKeyFactory : public KeyFactory {
-    Key* GenerateKey(const AuthorizationSet& key_description, keymaster_error_t* error) override;
-    Key* ImportKey(const AuthorizationSet&, keymaster_key_format_t, const uint8_t*, size_t,
-                   keymaster_error_t* error) override;
+  public:
+    SymmetricKeyFactory(const KeymasterContext* context) : KeyFactory(context) {}
+
+    keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+                                  KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
+                                  AuthorizationSet* sw_enforced) override;
+    keymaster_error_t ImportKey(const AuthorizationSet& key_description,
+                                keymaster_key_format_t input_key_material_format,
+                                const KeymasterKeyBlob& input_key_material,
+                                KeymasterKeyBlob* output_key_blob, AuthorizationSet* hw_enforced,
+                                AuthorizationSet* sw_enforced) override;
 
     virtual const keymaster_key_format_t* SupportedImportFormats(size_t* format_count);
     virtual const keymaster_key_format_t* SupportedExportFormats(size_t* format_count) {
@@ -34,10 +42,8 @@
     };
 
   private:
-    SymmetricKey* CreateKeyAndValidateSize(const AuthorizationSet& key_description,
-                                           keymaster_error_t* error);
+    virtual bool key_size_supported(size_t key_size_bits) const = 0;
 
-    virtual SymmetricKey* CreateKey(const AuthorizationSet& auths) = 0;
     const keymaster_key_format_t* NoFormats(size_t* format_count) {
         *format_count = 0;
         return NULL;
@@ -46,10 +52,6 @@
 
 class SymmetricKey : public Key {
   public:
-    static const int MAX_KEY_SIZE = 32;
-    static const int MAX_MAC_LENGTH = 32;
-    static const uint32_t MAX_CHUNK_LENGTH = 64 * 1024;
-
     ~SymmetricKey();
 
     virtual keymaster_error_t key_material(UniquePtr<uint8_t[]>* key_material, size_t* size) const;
@@ -62,16 +64,12 @@
     size_t key_data_size() const { return key_data_size_; }
 
   protected:
-    SymmetricKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error);
-    SymmetricKey(const AuthorizationSet& auths) : Key(auths) {}
+    SymmetricKey(const KeymasterKeyBlob& key_material, const AuthorizationSet& hw_enforced,
+                 const AuthorizationSet& sw_enforced, keymaster_error_t* error);
 
   private:
     friend SymmetricKeyFactory;
 
-    keymaster_error_t LoadKey(const UnencryptedKeyBlob& blob);
-    keymaster_error_t set_size(size_t key_size);
-    virtual bool size_supported(size_t key_size) const = 0;
-
     size_t key_data_size_;
     UniquePtr<uint8_t[]> key_data_;
 };
diff --git a/unencrypted_key_blob.cpp b/unencrypted_key_blob.cpp
deleted file mode 100644
index 43a7c25..0000000
--- a/unencrypted_key_blob.cpp
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright 2014 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 <assert.h>
-
-#include <openssl/aes.h>
-#include <openssl/sha.h>
-
-#include <keymaster/android_keymaster_utils.h>
-
-#include "ae.h"
-#include "unencrypted_key_blob.h"
-#include "ocb_utils.h"
-#include "openssl_err.h"
-
-namespace keymaster {
-
-UnencryptedKeyBlob::UnencryptedKeyBlob(const AuthorizationSet& enforced,
-                                       const AuthorizationSet& unenforced,
-                                       const AuthorizationSet& hidden,
-                                       const uint8_t* unencrypted_key,
-                                       size_t unencrypted_key_length, const uint8_t* master_key,
-                                       size_t master_key_length, const uint8_t nonce[NONCE_LENGTH])
-    : KeyBlob(enforced, unenforced), hidden_(hidden) {
-    // Check that KeyBlob ctor succeeded.
-    if (error_ != KM_ERROR_OK)
-        return;
-
-    if (hidden_.is_valid() == AuthorizationSet::ALLOCATION_FAILURE) {
-        error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
-        return;
-    }
-
-    if (hidden_.is_valid() != AuthorizationSet::OK) {
-        error_ = KM_ERROR_UNKNOWN_ERROR;
-        return;
-    }
-
-    unencrypted_key_material_.reset(new uint8_t[unencrypted_key_length]);
-    if (!unencrypted_key_material_.get()) {
-        error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
-        return;
-    }
-
-    unencrypted_key_material_length_ = unencrypted_key_length;
-    memcpy(unencrypted_key_material_.get(), unencrypted_key, unencrypted_key_length);
-    EncryptKey(master_key, master_key_length, nonce);
-}
-
-UnencryptedKeyBlob::UnencryptedKeyBlob(const keymaster_key_blob_t& key,
-                                       const AuthorizationSet& hidden, const uint8_t* master_key,
-                                       size_t master_key_length)
-    : KeyBlob(key), hidden_(hidden) {
-    // Check that KeyBlob ctor succeeded.
-    if (error_ != KM_ERROR_OK)
-        return;
-    DecryptKey(master_key, master_key_length);
-}
-
-void UnencryptedKeyBlob::EncryptKey(const uint8_t* master_key, size_t master_key_length,
-                                    const uint8_t* nonce) {
-    UniquePtr<AeCtx> ctx(InitializeKeyWrappingContext(master_key, master_key_length));
-    if (error_ != KM_ERROR_OK)
-        return;
-
-    UniquePtr<uint8_t[]> encrypted_key_material(new uint8_t[unencrypted_key_material_length()]);
-    UniquePtr<uint8_t[]> tag(new uint8_t[TAG_LENGTH]);
-    UniquePtr<uint8_t[]> nonce_copy(new uint8_t[NONCE_LENGTH]);
-    if (!encrypted_key_material.get() || !tag.get() || !nonce_copy.get()) {
-        error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
-        return;
-    }
-    memcpy(nonce_copy.get(), nonce, NONCE_LENGTH);
-
-    int ae_err =
-        ae_encrypt(ctx->get(), nonce, unencrypted_key_material(), unencrypted_key_material_length(),
-                   NULL /* additional data */, 0 /* additional data length */,
-                   encrypted_key_material.get(), tag.get(), 1 /* final */);
-    if (ae_err < 0) {
-        LOG_E("Error %d while encrypting key", ae_err);
-        error_ = KM_ERROR_UNKNOWN_ERROR;
-        return;
-    }
-    assert(ae_err == static_cast<int>(unencrypted_key_material_length()));
-
-    SetEncryptedKey(encrypted_key_material.release(), unencrypted_key_material_length(),
-                    nonce_copy.release(), tag.release());
-}
-
-void UnencryptedKeyBlob::DecryptKey(const uint8_t* master_key, size_t master_key_length) {
-    UniquePtr<AeCtx> ctx(InitializeKeyWrappingContext(master_key, master_key_length));
-    if (error_ != KM_ERROR_OK)
-        return;
-
-    unencrypted_key_material_length_ = key_material_length();
-    unencrypted_key_material_.reset(new uint8_t[unencrypted_key_material_length_]);
-    int ae_err = ae_decrypt(ctx->get(), nonce(), encrypted_key_material(), key_material_length(),
-                            NULL /* additional data */, 0 /* additional data length */,
-                            unencrypted_key_material_.get(), tag(), 1 /* final */);
-    if (ae_err == AE_INVALID) {
-        // Authentication failed!  Decryption probably succeeded(ish), but we don't want to return
-        // any data when the authentication fails, so clear it.
-        memset_s(unencrypted_key_material_.get(), 0, unencrypted_key_material_length());
-        LOG_E("Failed to validate authentication tag during key decryption", 0);
-        error_ = KM_ERROR_INVALID_KEY_BLOB;
-        return;
-    } else if (ae_err < 0) {
-        LOG_E("Failed to decrypt key, error: %d", ae_err);
-        error_ = KM_ERROR_UNKNOWN_ERROR;
-        return;
-    }
-    assert(ae_err == static_cast<int>(unencrypted_key_material_length()));
-    error_ = KM_ERROR_OK;
-}
-
-AeCtx* UnencryptedKeyBlob::InitializeKeyWrappingContext(const uint8_t* master_key,
-                                                        size_t master_key_length) {
-    size_t derivation_data_length;
-    UniquePtr<const uint8_t[]> derivation_data(BuildDerivationData(&derivation_data_length));
-    if (derivation_data.get() == NULL) {
-        error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
-        return NULL;
-    }
-
-    UniquePtr<AeCtx> ctx(new AeCtx);
-
-    SHA256_CTX sha256_ctx;
-    UniquePtr<uint8_t[]> hash_buf(new uint8_t[SHA256_DIGEST_LENGTH]);
-    Eraser hash_eraser(hash_buf.get(), SHA256_DIGEST_LENGTH);
-    UniquePtr<uint8_t[]> derived_key(new uint8_t[AES_BLOCK_SIZE]);
-    Eraser derived_key_eraser(derived_key.get(), AES_BLOCK_SIZE);
-
-    if (ctx.get() == NULL || hash_buf.get() == NULL || derived_key.get() == NULL) {
-        error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
-        return NULL;
-    }
-
-    Eraser sha256_ctx_eraser(sha256_ctx);
-
-    // Hash derivation data.
-    SHA256_Init(&sha256_ctx);
-    SHA256_Update(&sha256_ctx, derivation_data.get(), derivation_data_length);
-    SHA256_Final(hash_buf.get(), &sha256_ctx);
-
-    // Encrypt hash with master key to build derived key.
-    AES_KEY aes_key;
-    Eraser aes_key_eraser(AES_KEY);
-    if (AES_set_encrypt_key(master_key, master_key_length * 8, &aes_key) != 0) {
-        error_ = TranslateLastOpenSslError();
-        return NULL;
-    }
-    AES_encrypt(hash_buf.get(), derived_key.get(), &aes_key);
-
-    // Set up AES OCB context using derived key.
-    if (ae_init(ctx->get(), derived_key.get(), AES_BLOCK_SIZE /* key length */, NONCE_LENGTH,
-                TAG_LENGTH) == AE_SUCCESS)
-        return ctx.release();
-    else {
-        memset_s(ctx->get(), 0, ae_ctx_sizeof());
-        return NULL;
-    }
-}
-
-const uint8_t* UnencryptedKeyBlob::BuildDerivationData(size_t* derivation_data_length) const {
-    *derivation_data_length =
-        hidden_.SerializedSize() + enforced().SerializedSize() + unenforced().SerializedSize();
-    uint8_t* derivation_data = new uint8_t[*derivation_data_length];
-    if (derivation_data != NULL) {
-        uint8_t* buf = derivation_data;
-        uint8_t* end = derivation_data + *derivation_data_length;
-        buf = hidden_.Serialize(buf, end);
-        buf = enforced().Serialize(buf, end);
-        buf = unenforced().Serialize(buf, end);
-    }
-    return derivation_data;
-}
-
-}  // namespace keymaster
diff --git a/unencrypted_key_blob.h b/unencrypted_key_blob.h
deleted file mode 100644
index e559527..0000000
--- a/unencrypted_key_blob.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2014 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_UNENCRYPTED_KEY_BLOB_H_
-#define SYSTEM_KEYMASTER_UNENCRYPTED_KEY_BLOB_H_
-
-#include <keymaster/key_blob.h>
-
-namespace keymaster {
-
-class AeCtx;
-
-/**
- * Extends KeyBlob to provide access the the unencrypted key material as well as the encrypted form.
- */
-class UnencryptedKeyBlob : public KeyBlob {
-  public:
-    /**
-     * Create a UnencryptedKeyBlob containing the specified authorization data and key material.  \p
-     * key will be encrypted with a key derived from \p master_key, using OCB authenticated
-     * encryption with \p nonce.  It is critically important that nonces NEVER be reused.  The most
-     * convenient way to accomplish that is to choose them randomly.
-     *
-     * IMPORTANT: After constructing a UnencryptedKeyBlob, call error() to verify that the blob is
-     * usable.
-     */
-    UnencryptedKeyBlob(const AuthorizationSet& enforced, const AuthorizationSet& unenforced,
-                       const AuthorizationSet& hidden, const uint8_t* unencrypted_key,
-                       size_t unencrypted_key_length, const uint8_t* master_key,
-                       size_t master_key_length, const uint8_t nonce[NONCE_LENGTH]);
-
-    /**
-     * Create a UnencryptedKeyBlob, extracting the enforced and unenforced sets and decrypting the
-     * key.  The KeyBlob does *not* take ownership of key_blob.
-     *
-     * IMPORTANT: After constructing a UnencryptedKeyBlob, call error() to verify that the blob is
-     * usable.
-     */
-    UnencryptedKeyBlob(const keymaster_key_blob_t& key_blob, const AuthorizationSet& hidden,
-                       const uint8_t* master_key, size_t master_key_length);
-
-    inline const uint8_t* unencrypted_key_material() const {
-        return unencrypted_key_material_.get();
-    }
-    inline size_t unencrypted_key_material_length() const {
-        return unencrypted_key_material_length_;
-    }
-    inline const AuthorizationSet& hidden() const { return hidden_; }
-
-  private:
-    void DecryptKey(const uint8_t* master_key, size_t master_key_length);
-    void EncryptKey(const uint8_t* master_key, size_t master_key_length, const uint8_t* nonce);
-
-    /**
-     * Create an AES_OCB context initialized with a key derived using \p master_key and the
-     * authorizations.
-     */
-    AeCtx* InitializeKeyWrappingContext(const uint8_t* master_key, size_t master_key_length);
-
-    const uint8_t* BuildDerivationData(size_t* derivation_data_len) const;
-
-    UniquePtr<uint8_t[]> unencrypted_key_material_;
-    size_t unencrypted_key_material_length_;
-    AuthorizationSet hidden_;
-};
-
-}  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_UNENCRYPTED_KEY_BLOB_H_
diff --git a/valgrind.supp b/valgrind.supp
index 2ca244c..2b51c4b 100644
--- a/valgrind.supp
+++ b/valgrind.supp
@@ -22,4 +22,18 @@
    fun:RSA_sign_raw
    fun:RSA_private_encrypt
    ...
+}
+{
+   EcKeyErrorLeak1
+   Memcheck:Leak
+   fun:malloc
+   fun:err_add_error_vdata
+   fun:ERR_add_error_data
+   fun:ASN1_item_ex_d2i
+   fun:ASN1_item_d2i
+   fun:d2i_EC_PRIVATEKEY
+   fun:d2i_ECPrivateKey
+   fun:old_ec_priv_decode
+   fun:d2i_PrivateKey
+   ...
 }
\ No newline at end of file