Project import
diff --git a/keymaster/.clang-format b/keymaster/.clang-format
new file mode 100644
index 0000000..5747e19
--- /dev/null
+++ b/keymaster/.clang-format
@@ -0,0 +1,10 @@
+BasedOnStyle: LLVM
+IndentWidth: 4
+UseTab: Never
+BreakBeforeBraces: Attach
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: false
+IndentCaseLabels: false
+ColumnLimit: 100
+PointerBindsToType: true
+SpacesBeforeTrailingComments: 2
diff --git a/keymaster/Android.mk b/keymaster/Android.mk
new file mode 100644
index 0000000..233ed95
--- /dev/null
+++ b/keymaster/Android.mk
@@ -0,0 +1,180 @@
+# Copyright (C) 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.
+
+LOCAL_PATH := $(call my-dir)
+
+###
+# libkeymaster_messages contains just the code necessary to communicate with a
+# AndroidKeymaster implementation, e.g. one running in TrustZone.
+##
+include $(CLEAR_VARS)
+LOCAL_MODULE:= libkeymaster_messages
+LOCAL_SRC_FILES:= \
+		android_keymaster_messages.cpp \
+		android_keymaster_utils.cpp \
+		authorization_set.cpp \
+		keymaster_tags.cpp \
+		logger.cpp \
+		serializable.cpp
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/include
+LOCAL_CFLAGS = -Wall -Werror -Wunused -DKEYMASTER_NAME_TAGS
+LOCAL_CLANG := true
+# TODO(krasin): reenable coverage flags, when the new Clang toolchain is released.
+# Currently, if enabled, these flags will cause an internal error in Clang.
+LOCAL_CLANG_CFLAGS += -fno-sanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp
+LOCAL_MODULE_TAGS := optional
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_SHARED_LIBRARY)
+
+###
+# libkeymaster1 contains almost everything needed for a keymaster1
+# 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:= \
+		aes_key.cpp \
+		aes_operation.cpp \
+		android_keymaster.cpp \
+		android_keymaster_messages.cpp \
+		android_keymaster_utils.cpp \
+		asymmetric_key.cpp \
+		asymmetric_key_factory.cpp \
+		attestation_record.cpp \
+		auth_encrypted_key_blob.cpp \
+		ec_key.cpp \
+		ec_key_factory.cpp \
+		ecdsa_operation.cpp \
+		ecies_kem.cpp \
+		hkdf.cpp \
+		hmac.cpp \
+		hmac_key.cpp \
+		hmac_operation.cpp \
+		integrity_assured_key_blob.cpp \
+		iso18033kdf.cpp \
+		kdf.cpp \
+		key.cpp \
+		keymaster_enforcement.cpp \
+		nist_curve_key_exchange.cpp \
+		ocb.c \
+		ocb_utils.cpp \
+		openssl_err.cpp \
+		openssl_utils.cpp \
+		operation.cpp \
+		operation_table.cpp \
+		rsa_key.cpp \
+		rsa_key_factory.cpp \
+		rsa_operation.cpp \
+		symmetric_key.cpp
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := libcrypto libkeymaster_messages
+LOCAL_CFLAGS = -Wall -Werror -Wunused
+LOCAL_CLANG := true
+LOCAL_CLANG_CFLAGS += -Wno-error=unused-const-variable -Wno-error=unused-private-field
+# TODO(krasin): reenable coverage flags, when the new Clang toolchain is released.
+# Currently, if enabled, these flags will cause an internal error in Clang.
+LOCAL_CLANG_CFLAGS += -fno-sanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp
+# Ignore benigh warnings for now.
+LOCAL_CLANG_CFLAGS += -Wno-error=unused-private-field
+LOCAL_MODULE_TAGS := optional
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_SHARED_LIBRARY)
+
+
+###
+# libsoftkeymaster provides a software-based keymaster HAL implementation.
+# This is used by keystore as a fallback for when the hardware keymaster does
+# not support the request.
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := libsoftkeymasterdevice
+LOCAL_SRC_FILES := \
+	ec_keymaster0_key.cpp \
+	ec_keymaster1_key.cpp \
+	ecdsa_keymaster1_operation.cpp \
+	keymaster0_engine.cpp \
+	keymaster1_engine.cpp \
+	rsa_keymaster0_key.cpp \
+	rsa_keymaster1_key.cpp \
+	rsa_keymaster1_operation.cpp \
+	soft_keymaster_context.cpp \
+	soft_keymaster_device.cpp \
+	soft_keymaster_logger.cpp
+LOCAL_C_INCLUDES := \
+	system/security/keystore \
+	$(LOCAL_PATH)/include
+LOCAL_CFLAGS = -Wall -Werror -Wunused
+LOCAL_CLANG := true
+LOCAL_CLANG_CFLAGS += -Wno-error=unused-const-variable -Wno-error=unused-private-field
+# TODO(krasin): reenable coverage flags, when the new Clang toolchain is released.
+# Currently, if enabled, these flags will cause an internal error in Clang.
+LOCAL_CLANG_CFLAGS += -fno-sanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp
+LOCAL_SHARED_LIBRARIES := libkeymaster_messages libkeymaster1 liblog libcrypto
+LOCAL_MODULE_TAGS := optional
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+include $(BUILD_SHARED_LIBRARY)
+
+###
+# libkeymasterfiles is an empty library that exports all of the files in keymaster as includes.
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := libkeymasterfiles
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/include
+LOCAL_MODULE_TAGS := optional
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_LIBRARY)
+
+# Unit tests for libkeymaster
+include $(CLEAR_VARS)
+LOCAL_MODULE := keymaster_tests
+LOCAL_SRC_FILES := \
+	android_keymaster_messages_test.cpp \
+	android_keymaster_test.cpp \
+	android_keymaster_test_utils.cpp \
+	attestation_record_test.cpp \
+	authorization_set_test.cpp \
+	hkdf_test.cpp \
+	hmac_test.cpp \
+	kdf1_test.cpp \
+	kdf2_test.cpp \
+	kdf_test.cpp \
+	key_blob_test.cpp \
+	keymaster_enforcement_test.cpp
+
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/include
+LOCAL_CFLAGS = -Wall -Werror -Wunused -DKEYMASTER_NAME_TAGS
+LOCAL_CLANG := true
+LOCAL_CLANG_CFLAGS += -Wno-error=unused-const-variable -Wno-error=unused-private-field
+# TODO(krasin): reenable coverage flags, when the new Clang toolchain is released.
+# Currently, if enabled, these flags will cause an internal error in Clang.
+LOCAL_CLANG_CFLAGS += -fno-sanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp
+LOCAL_MODULE_TAGS := tests
+LOCAL_SHARED_LIBRARIES := \
+	libsoftkeymasterdevice \
+	libkeymaster_messages \
+	libkeymaster1 \
+	libcrypto \
+	libsoftkeymaster
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_NATIVE_TEST)
diff --git a/keymaster/List.h b/keymaster/List.h
new file mode 100644
index 0000000..403cd7f
--- /dev/null
+++ b/keymaster/List.h
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Templated list class.  Normally we'd use STL, but we don't have that.
+// This class mimics STL's interfaces.
+//
+// Objects are copied into the list with the '=' operator or with copy-
+// construction, so if the compiler's auto-generated versions won't work for
+// you, define your own.
+//
+// The only class you want to use from here is "List".
+//
+#ifndef _LIBS_UTILS_LIST_H
+#define _LIBS_UTILS_LIST_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace android {
+
+/*
+ * Doubly-linked list.  Instantiate with "List<MyClass> myList".
+ *
+ * Objects added to the list are copied using the assignment operator,
+ * so this must be defined.
+ */
+template<typename T> 
+class List 
+{
+protected:
+    /*
+     * One element in the list.
+     */
+    class _Node {
+    public:
+        explicit _Node(const T& val) : mVal(val) {}
+        ~_Node() {}
+        inline T& getRef() { return mVal; }
+        inline const T& getRef() const { return mVal; }
+        inline _Node* getPrev() const { return mpPrev; }
+        inline _Node* getNext() const { return mpNext; }
+        inline void setVal(const T& val) { mVal = val; }
+        inline void setPrev(_Node* ptr) { mpPrev = ptr; }
+        inline void setNext(_Node* ptr) { mpNext = ptr; }
+    private:
+        friend class List;
+        friend class _ListIterator;
+        T           mVal;
+        _Node*      mpPrev;
+        _Node*      mpNext;
+    };
+
+    /*
+     * Iterator for walking through the list.
+     */
+    
+    template <typename TYPE>
+    struct CONST_ITERATOR {
+        typedef _Node const * NodePtr;
+        typedef const TYPE Type;
+    };
+    
+    template <typename TYPE>
+    struct NON_CONST_ITERATOR {
+        typedef _Node* NodePtr;
+        typedef TYPE Type;
+    };
+    
+    template<
+        typename U,
+        template <class> class Constness
+    > 
+    class _ListIterator {
+        typedef _ListIterator<U, Constness>     _Iter;
+        typedef typename Constness<U>::NodePtr  _NodePtr;
+        typedef typename Constness<U>::Type     _Type;
+
+        explicit _ListIterator(_NodePtr ptr) : mpNode(ptr) {}
+
+    public:
+        _ListIterator() {}
+        _ListIterator(const _Iter& rhs) : mpNode(rhs.mpNode) {}
+        ~_ListIterator() {}
+        
+        // this will handle conversions from iterator to const_iterator
+        // (and also all convertible iterators)
+        // Here, in this implementation, the iterators can be converted
+        // if the nodes can be converted
+        template<typename V> explicit 
+        _ListIterator(const V& rhs) : mpNode(rhs.mpNode) {}
+        
+
+        /*
+         * Dereference operator.  Used to get at the juicy insides.
+         */
+        _Type& operator*() const { return mpNode->getRef(); }
+        _Type* operator->() const { return &(mpNode->getRef()); }
+
+        /*
+         * Iterator comparison.
+         */
+        inline bool operator==(const _Iter& right) const { 
+            return mpNode == right.mpNode; }
+        
+        inline bool operator!=(const _Iter& right) const { 
+            return mpNode != right.mpNode; }
+
+        /*
+         * handle comparisons between iterator and const_iterator
+         */
+        template<typename OTHER>
+        inline bool operator==(const OTHER& right) const { 
+            return mpNode == right.mpNode; }
+        
+        template<typename OTHER>
+        inline bool operator!=(const OTHER& right) const { 
+            return mpNode != right.mpNode; }
+
+        /*
+         * Incr/decr, used to move through the list.
+         */
+        inline _Iter& operator++() {     // pre-increment
+            mpNode = mpNode->getNext();
+            return *this;
+        }
+        const _Iter operator++(int) {    // post-increment
+            _Iter tmp(*this);
+            mpNode = mpNode->getNext();
+            return tmp;
+        }
+        inline _Iter& operator--() {     // pre-increment
+            mpNode = mpNode->getPrev();
+            return *this;
+        }
+        const _Iter operator--(int) {   // post-increment
+            _Iter tmp(*this);
+            mpNode = mpNode->getPrev();
+            return tmp;
+        }
+
+        inline _NodePtr getNode() const { return mpNode; }
+
+        _NodePtr mpNode;    /* should be private, but older gcc fails */
+    private:
+        friend class List;
+    };
+
+public:
+    List() {
+        prep();
+    }
+    List(const List<T>& src) {      // copy-constructor
+        prep();
+        insert(begin(), src.begin(), src.end());
+    }
+    virtual ~List() {
+        clear();
+        delete[] (unsigned char*) mpMiddle;
+    }
+
+    typedef _ListIterator<T, NON_CONST_ITERATOR> iterator;
+    typedef _ListIterator<T, CONST_ITERATOR> const_iterator;
+
+    List<T>& operator=(const List<T>& right);
+
+    /* returns true if the list is empty */
+    inline bool empty() const { return mpMiddle->getNext() == mpMiddle; }
+
+    /* return #of elements in list */
+    size_t size() const {
+        return size_t(distance(begin(), end()));
+    }
+
+    /*
+     * Return the first element or one past the last element.  The
+     * _Node* we're returning is converted to an "iterator" by a
+     * constructor in _ListIterator.
+     */
+    inline iterator begin() { 
+        return iterator(mpMiddle->getNext()); 
+    }
+    inline const_iterator begin() const { 
+        return const_iterator(const_cast<_Node const*>(mpMiddle->getNext())); 
+    }
+    inline iterator end() { 
+        return iterator(mpMiddle); 
+    }
+    inline const_iterator end() const { 
+        return const_iterator(const_cast<_Node const*>(mpMiddle)); 
+    }
+
+    /* add the object to the head or tail of the list */
+    void push_front(const T& val) { insert(begin(), val); }
+    void push_back(const T& val) { insert(end(), val); }
+
+    /* insert before the current node; returns iterator at new node */
+    iterator insert(iterator posn, const T& val) 
+    {
+        _Node* newNode = new _Node(val);        // alloc & copy-construct
+        newNode->setNext(posn.getNode());
+        newNode->setPrev(posn.getNode()->getPrev());
+        posn.getNode()->getPrev()->setNext(newNode);
+        posn.getNode()->setPrev(newNode);
+        return iterator(newNode);
+    }
+
+    /* insert a range of elements before the current node */
+    void insert(iterator posn, const_iterator first, const_iterator last) {
+        for ( ; first != last; ++first)
+            insert(posn, *first);
+    }
+
+    /* remove one entry; returns iterator at next node */
+    iterator erase(iterator posn) {
+        _Node* pNext = posn.getNode()->getNext();
+        _Node* pPrev = posn.getNode()->getPrev();
+        pPrev->setNext(pNext);
+        pNext->setPrev(pPrev);
+        delete posn.getNode();
+        return iterator(pNext);
+    }
+
+    /* remove a range of elements */
+    iterator erase(iterator first, iterator last) {
+        while (first != last)
+            erase(first++);     // don't erase than incr later!
+        return iterator(last);
+    }
+
+    /* remove all contents of the list */
+    void clear() {
+        _Node* pCurrent = mpMiddle->getNext();
+        _Node* pNext;
+
+        while (pCurrent != mpMiddle) {
+            pNext = pCurrent->getNext();
+            delete pCurrent;
+            pCurrent = pNext;
+        }
+        mpMiddle->setPrev(mpMiddle);
+        mpMiddle->setNext(mpMiddle);
+    }
+
+    /*
+     * Measure the distance between two iterators.  On exist, "first"
+     * will be equal to "last".  The iterators must refer to the same
+     * list.
+     *
+     * FIXME: This is actually a generic iterator function. It should be a 
+     * template function at the top-level with specializations for things like
+     * vector<>, which can just do pointer math). Here we limit it to
+     * _ListIterator of the same type but different constness.
+     */
+    template<
+        typename U,
+        template <class> class CL,
+        template <class> class CR
+    > 
+    ptrdiff_t distance(
+            _ListIterator<U, CL> first, _ListIterator<U, CR> last) const 
+    {
+        ptrdiff_t count = 0;
+        while (first != last) {
+            ++first;
+            ++count;
+        }
+        return count;
+    }
+
+private:
+    /*
+     * I want a _Node but don't need it to hold valid data.  More
+     * to the point, I don't want T's constructor to fire, since it
+     * might have side-effects or require arguments.  So, we do this
+     * slightly uncouth storage alloc.
+     */
+    void prep() {
+        mpMiddle = (_Node*) new unsigned char[sizeof(_Node)];
+        mpMiddle->setPrev(mpMiddle);
+        mpMiddle->setNext(mpMiddle);
+    }
+
+    /*
+     * This node plays the role of "pointer to head" and "pointer to tail".
+     * It sits in the middle of a circular list of nodes.  The iterator
+     * runs around the circle until it encounters this one.
+     */
+    _Node*      mpMiddle;
+};
+
+/*
+ * Assignment operator.
+ *
+ * The simplest way to do this would be to clear out the target list and
+ * fill it with the source.  However, we can speed things along by
+ * re-using existing elements.
+ */
+template<class T>
+List<T>& List<T>::operator=(const List<T>& right)
+{
+    if (this == &right)
+        return *this;       // self-assignment
+    iterator firstDst = begin();
+    iterator lastDst = end();
+    const_iterator firstSrc = right.begin();
+    const_iterator lastSrc = right.end();
+    while (firstSrc != lastSrc && firstDst != lastDst)
+        *firstDst++ = *firstSrc++;
+    if (firstSrc == lastSrc)        // ran out of elements in source?
+        erase(firstDst, lastDst);   // yes, erase any extras
+    else
+        insert(lastDst, firstSrc, lastSrc);     // copy remaining over
+    return *this;
+}
+
+}; // namespace android
+
+#endif // _LIBS_UTILS_LIST_H
diff --git a/keymaster/MODULE_LICENSE_APACHE2 b/keymaster/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/keymaster/MODULE_LICENSE_APACHE2
diff --git a/keymaster/Makefile b/keymaster/Makefile
new file mode 100644
index 0000000..fc8a540
--- /dev/null
+++ b/keymaster/Makefile
@@ -0,0 +1,381 @@
+#####
+# Local unit test Makefile
+#
+# This makefile builds and runs the keymaster unit tests locally on the development
+# machine, not on an Android device.  Android.mk builds the same tests into the
+# "keymaster_tests" binary for execution on-device, but this Makefile runs them locally,
+# for a very fast edit/build/test development cycle.
+#
+# To build and run these tests, one pre-requisite must be manually installed: BoringSSL.
+# This Makefile expects to find BoringSSL in a directory adjacent to $ANDROID_BUILD_TOP.
+# To get and build it, first install the Ninja build tool (e.g. apt-get install
+# ninja-build), then do:
+#
+# cd $ANDROID_BUILD_TOP/..
+# git clone https://boringssl.googlesource.com/boringssl
+# cd boringssl
+# mdkir build
+# cd build
+# cmake -GNinja ..
+# ninja
+#
+# Then return to $ANDROID_BUILD_TOP/system/keymaster and run "make".
+#####
+
+BASE=../..
+SUBS=system/core \
+	hardware/libhardware \
+	external/gtest \
+	system/security/softkeymaster \
+	system/security/keystore
+GTEST=$(BASE)/external/gtest
+
+INCLUDES=$(foreach dir,$(SUBS),-I $(BASE)/$(dir)/include) \
+	-I $(BASE)/libnativehelper/include/nativehelper \
+	-I $(GTEST) -Iinclude -I$(BASE)/../boringssl/include
+
+ifdef FORCE_32_BIT
+ARCH_FLAGS = -m32
+endif
+
+ifdef USE_CLANG
+CC=/usr/bin/clang
+CXX=/usr/bin/clang
+CXXFLAGS +=-std=c++11 -DKEYMASTER_CLANG_TEST_BUILD
+CFLAGS += -DKEYMASTER_CLANG_TEST_BUILD
+else
+CXXFLAGS +=-std=c++0x -fprofile-arcs -ftest-coverage
+CFLAGS += -fprofile-arcs -ftest-coverage
+endif
+
+LDFLAGS += $(ARCH_FLAGS)
+CPPFLAGS = $(INCLUDES) -g -O0 -MD -MP
+CXXFLAGS += -Wall -Werror -Wno-unused -Winit-self -Wpointer-arith -Wunused-parameter \
+	-Werror=sign-compare -Werror=return-type -fno-permissive \
+	-Wno-deprecated-declarations -fno-exceptions -DKEYMASTER_NAME_TAGS $(ARCH_FLAGS)
+CFLAGS += $(ARCH_FLAGS)
+
+# Uncomment to enable debug logging.
+# CXXFLAGS += -DDEBUG
+
+LDLIBS=-L$(BASE)/../boringssl/build/crypto -lcrypto -lpthread -lstdc++ -lgcov
+
+CPPSRCS=\
+	aes_key.cpp \
+	aes_operation.cpp \
+	android_keymaster.cpp \
+	android_keymaster_messages.cpp \
+	android_keymaster_messages_test.cpp \
+	android_keymaster_test.cpp \
+	android_keymaster_test_utils.cpp \
+	android_keymaster_utils.cpp \
+	asymmetric_key.cpp \
+	asymmetric_key_factory.cpp \
+	attestation_record.cpp \
+	attestation_record_test.cpp \
+	auth_encrypted_key_blob.cpp \
+	authorization_set.cpp \
+	authorization_set_test.cpp \
+	ec_key.cpp \
+	ec_key_factory.cpp \
+	ec_keymaster0_key.cpp \
+	ec_keymaster1_key.cpp \
+	ecdsa_keymaster1_operation.cpp \
+	ecdsa_operation.cpp \
+	ecies_kem.cpp \
+	ecies_kem_test.cpp \
+	gtest_main.cpp \
+	hkdf.cpp \
+	hkdf_test.cpp \
+	hmac.cpp \
+	hmac_key.cpp \
+	hmac_operation.cpp \
+	hmac_test.cpp \
+	integrity_assured_key_blob.cpp \
+	iso18033kdf.cpp \
+	kdf.cpp \
+	kdf_test.cpp \
+	kdf1_test.cpp \
+	kdf2_test.cpp \
+	key.cpp \
+	key_blob_test.cpp \
+	keymaster0_engine.cpp \
+	keymaster1_engine.cpp \
+	keymaster_enforcement.cpp \
+	keymaster_enforcement_test.cpp \
+	keymaster_tags.cpp \
+	logger.cpp \
+	nist_curve_key_exchange.cpp \
+	nist_curve_key_exchange_test.cpp \
+	ocb_utils.cpp \
+	openssl_err.cpp \
+	openssl_utils.cpp \
+	operation.cpp \
+	operation_table.cpp \
+	rsa_key.cpp \
+	rsa_key_factory.cpp \
+	rsa_keymaster0_key.cpp \
+	rsa_keymaster1_key.cpp \
+	rsa_keymaster1_operation.cpp \
+	rsa_operation.cpp \
+	serializable.cpp \
+	soft_keymaster_context.cpp \
+	soft_keymaster_device.cpp \
+	symmetric_key.cpp
+
+CCSRCS=$(GTEST)/src/gtest-all.cc
+CSRCS=ocb.c
+
+OBJS=$(CPPSRCS:.cpp=.o) $(CCSRCS:.cc=.o) $(CSRCS:.c=.o)
+DEPS=$(CPPSRCS:.cpp=.d) $(CCSRCS:.cc=.d) $(CSRCS:.c=.d)
+
+BINARIES = \
+	android_keymaster_messages_test \
+	android_keymaster_test \
+	attestation_record_test \
+	authorization_set_test \
+	ecies_kem_test \
+	hkdf_test \
+	hmac_test \
+	kdf_test \
+	kdf1_test \
+	kdf2_test \
+	key_blob_test \
+	keymaster_enforcement_test \
+	nist_curve_key_exchange_test
+
+.PHONY: coverage memcheck massif clean run
+
+%.run: %
+	./$<
+	touch $@
+
+run: $(BINARIES:=.run)
+
+coverage: coverage.info
+	genhtml coverage.info --output-directory coverage
+
+coverage.info: run
+	lcov --capture --directory=. --output-file coverage.info
+
+%.coverage : %
+	$(MAKE) clean && $(MAKE) $<
+	./$<
+	lcov --capture --directory=. --output-file coverage.info
+	genhtml coverage.info --output-directory coverage
+
+#UNINIT_OPTS=--track-origins=yes
+UNINIT_OPTS=--undef-value-errors=no
+
+MEMCHECK_OPTS=--leak-check=full \
+	--show-reachable=yes \
+	--vgdb=full \
+	$(UNINIT_OPTS) \
+	--error-exitcode=1 \
+	--suppressions=valgrind.supp \
+	--gen-suppressions=all
+
+MASSIF_OPTS=--tool=massif \
+	--stacks=yes
+
+%.memcheck : %
+	valgrind $(MEMCHECK_OPTS) ./$< && \
+	touch $@
+
+%.massif : %
+	valgrind $(MASSIF_OPTS) --massif-out-file=$@ ./$<
+
+memcheck: $(BINARIES:=.memcheck)
+
+massif: $(BINARIES:=.massif)
+
+GTEST_OBJS = $(GTEST)/src/gtest-all.o gtest_main.o
+
+hmac_test: hmac_test.o \
+	android_keymaster_test_utils.o \
+	android_keymaster_utils.o \
+	authorization_set.o \
+	hmac.o \
+	keymaster_tags.o \
+	logger.o \
+	serializable.o \
+	$(GTEST_OBJS)
+
+hkdf_test: hkdf_test.o \
+	android_keymaster_test_utils.o \
+	android_keymaster_utils.o \
+	authorization_set.o \
+	hkdf.o \
+	hmac.o \
+	kdf.o \
+	keymaster_tags.o \
+	logger.o \
+	serializable.o \
+	$(GTEST_OBJS)
+
+kdf_test: kdf_test.o \
+	android_keymaster_utils.o \
+	kdf.o \
+	logger.o \
+	serializable.o \
+	$(GTEST_OBJS)
+
+kdf1_test: kdf1_test.o \
+	android_keymaster_test_utils.o \
+	android_keymaster_utils.o \
+	authorization_set.o \
+	iso18033kdf.o \
+	kdf.o \
+	keymaster_tags.o \
+	logger.o \
+	serializable.o \
+	$(GTEST_OBJS)
+
+kdf2_test: kdf2_test.o \
+	android_keymaster_test_utils.o \
+	android_keymaster_utils.o \
+	authorization_set.o \
+	iso18033kdf.o \
+	kdf.o \
+	keymaster_tags.o \
+	logger.o \
+	serializable.o \
+	$(GTEST_OBJS)
+
+nist_curve_key_exchange_test: nist_curve_key_exchange_test.o \
+	android_keymaster_test_utils.o \
+	authorization_set.o \
+	keymaster_tags.o \
+	logger.o \
+	nist_curve_key_exchange.o \
+	openssl_err.o \
+	openssl_utils.o \
+	serializable.o \
+	$(GTEST_OBJS)
+
+ecies_kem_test: ecies_kem_test.o \
+	android_keymaster_utils.o \
+	android_keymaster_test_utils.o \
+	authorization_set.o \
+	ecies_kem.o \
+	hkdf.o \
+	hmac.o \
+	kdf.o \
+	keymaster_tags.o \
+	logger.o \
+	nist_curve_key_exchange.o \
+	openssl_err.o \
+	openssl_utils.o \
+	serializable.o \
+	$(GTEST_OBJS)
+
+authorization_set_test: authorization_set_test.o \
+	android_keymaster_test_utils.o \
+	authorization_set.o \
+	keymaster_tags.o \
+	logger.o \
+	serializable.o \
+	$(GTEST_OBJS)
+
+key_blob_test: key_blob_test.o \
+	android_keymaster_test_utils.o \
+	android_keymaster_utils.o \
+	auth_encrypted_key_blob.o \
+	authorization_set.o \
+	integrity_assured_key_blob.o \
+	keymaster_tags.o \
+	logger.o \
+	ocb.o \
+	ocb_utils.o \
+	openssl_err.o \
+	serializable.o \
+	$(GTEST_OBJS)
+
+android_keymaster_messages_test: android_keymaster_messages_test.o \
+	android_keymaster_messages.o \
+	android_keymaster_test_utils.o \
+	android_keymaster_utils.o \
+	authorization_set.o \
+	keymaster_tags.o \
+	logger.o \
+	serializable.o \
+	$(GTEST_OBJS)
+
+android_keymaster_test: android_keymaster_test.o \
+	aes_key.o \
+	aes_operation.o \
+	android_keymaster.o \
+	android_keymaster_messages.o \
+	android_keymaster_test_utils.o \
+	android_keymaster_utils.o \
+	asymmetric_key.o \
+	asymmetric_key_factory.o \
+	attestation_record.o \
+	auth_encrypted_key_blob.o \
+	authorization_set.o \
+	ec_key.o \
+	ec_key_factory.o \
+	ec_keymaster0_key.o \
+	ec_keymaster1_key.o \
+	ecdsa_keymaster1_operation.o \
+	ecdsa_operation.o \
+	hmac_key.o \
+	hmac_operation.o \
+	integrity_assured_key_blob.o \
+	key.o \
+	keymaster0_engine.o \
+	keymaster1_engine.o \
+	keymaster_enforcement.o \
+	keymaster_tags.o \
+	logger.o \
+	ocb.o \
+	ocb_utils.o \
+	openssl_err.o \
+	openssl_utils.o \
+	operation.o \
+	operation_table.o \
+	rsa_key.o \
+	rsa_key_factory.o \
+	rsa_keymaster0_key.o \
+	rsa_keymaster1_key.o \
+	rsa_keymaster1_operation.o \
+	rsa_operation.o \
+	serializable.o \
+	soft_keymaster_context.o \
+	soft_keymaster_device.o \
+	symmetric_key.o \
+	$(BASE)/system/security/softkeymaster/keymaster_openssl.o \
+	$(BASE)/system/security/keystore/keyblob_utils.o \
+	$(GTEST_OBJS)
+
+keymaster_enforcement_test: keymaster_enforcement_test.o \
+	android_keymaster_messages.o \
+	android_keymaster_test_utils.o \
+	android_keymaster_utils.o \
+	authorization_set.o \
+	keymaster_enforcement.o \
+	keymaster_tags.o \
+	logger.o \
+	serializable.o \
+	$(GTEST_OBJS)
+
+attestation_record_test: attestation_record_test.o \
+	android_keymaster_test_utils.o \
+	attestation_record.o \
+	authorization_set.o \
+	keymaster_tags.o \
+	logger.o \
+	openssl_err.o \
+	serializable.o \
+	$(GTEST_OBJS)
+
+$(GTEST)/src/gtest-all.o: CXXFLAGS:=$(subst -Wmissing-declarations,,$(CXXFLAGS))
+
+clean:
+	rm -f $(OBJS) $(DEPS) $(BINARIES) \
+		$(BINARIES:=.run) $(BINARIES:=.memcheck) $(BINARIES:=.massif) \
+		*gcov *gcno *gcda coverage.info
+	rm -rf coverage
+
+-include $(CPPSRCS:.cpp=.d)
+-include $(CCSRCS:.cc=.d)
diff --git a/keymaster/NOTICE b/keymaster/NOTICE
new file mode 100644
index 0000000..34bdaf1
--- /dev/null
+++ b/keymaster/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/keymaster/ae.h b/keymaster/ae.h
new file mode 100644
index 0000000..864d349
--- /dev/null
+++ b/keymaster/ae.h
@@ -0,0 +1,164 @@
+/* ---------------------------------------------------------------------------
+ *
+ * AEAD API 0.12 - 23-MAY-2012
+ *
+ * This file gives an interface appropriate for many authenticated
+ * encryption with associated data (AEAD) implementations. It does not try
+ * to accommodate all possible options or limitations that an implementation
+ * might have -- you should consult the documentation of your chosen
+ * implementation to find things like RFC 5116 constants, alignment
+ * requirements, whether the incremental interface is supported, etc.
+ *
+ * This file is in the public domain. It is provided "as is", without
+ * warranty of any kind. Use at your own risk.
+ *
+ * Comments are welcome: Ted Krovetz <ted@krovetz>.
+ *
+ * ------------------------------------------------------------------------ */
+
+#ifndef _AE_H_
+#define _AE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* --------------------------------------------------------------------------
+ *
+ * Constants
+ *
+ * ----------------------------------------------------------------------- */
+
+/* Return status codes: Negative return values indicate an error occurred.
+ * For full explanations of error values, consult the implementation's
+ * documentation.                                                          */
+#define AE_SUCCESS (0)        /* Indicates successful completion of call  */
+#define AE_INVALID (-1)       /* Indicates bad tag during decryption      */
+#define AE_NOT_SUPPORTED (-2) /* Indicates unsupported option requested   */
+
+/* Flags: When data can be processed "incrementally", these flags are used
+ * to indicate whether the submitted data is the last or not.               */
+#define AE_FINALIZE (1) /* This is the last of data                  */
+#define AE_PENDING (0)  /* More data of is coming                    */
+
+/* --------------------------------------------------------------------------
+ *
+ * AEAD opaque structure definition
+ *
+ * ----------------------------------------------------------------------- */
+
+typedef struct _ae_ctx ae_ctx;
+
+/* --------------------------------------------------------------------------
+ *
+ * Data Structure Routines
+ *
+ * ----------------------------------------------------------------------- */
+
+ae_ctx* ae_allocate(void* misc); /* Allocate ae_ctx, set optional ptr   */
+void ae_free(ae_ctx* ctx);       /* Deallocate ae_ctx struct            */
+int ae_clear(ae_ctx* ctx);       /* Undo initialization                 */
+int ae_ctx_sizeof(void);         /* Return sizeof(ae_ctx)               */
+/* ae_allocate() allocates an ae_ctx structure, but does not initialize it.
+ * ae_free() deallocates an ae_ctx structure, but does not zero it.
+ * ae_clear() zeroes sensitive values associated with an ae_ctx structure
+ * and deallocates any auxiliary structures allocated during ae_init().
+ * ae_ctx_sizeof() returns sizeof(ae_ctx), to aid in any static allocations.
+ */
+
+/* --------------------------------------------------------------------------
+ *
+ * AEAD Routines
+ *
+ * ----------------------------------------------------------------------- */
+
+int ae_init(ae_ctx* ctx, const void* key, int key_len, int nonce_len, int tag_len);
+/* --------------------------------------------------------------------------
+ *
+ * Initialize an ae_ctx context structure.
+ *
+ * Parameters:
+ *  ctx       - Pointer to an ae_ctx structure to be initialized
+ *  key       - Pointer to user-supplied key
+ *  key_len   - Length of key supplied, in bytes
+ *  nonce_len - Length of nonces to be used for this key, in bytes
+ *  tag_len   - Length of tags to be produced for this key, in bytes
+ *
+ * Returns:
+ *  AE_SUCCESS       - Success. Ctx ready for use.
+ *  AE_NOT_SUPPORTED - An unsupported length was supplied. Ctx is untouched.
+ *  Otherwise        - Error. Check implementation documentation for codes.
+ *
+ * ----------------------------------------------------------------------- */
+
+int ae_encrypt(ae_ctx* ctx, const void* nonce, const void* pt, int pt_len, const void* ad,
+               int ad_len, void* ct, void* tag, int final);
+/* --------------------------------------------------------------------------
+ *
+ * Encrypt plaintext; provide for authentication of ciphertext/associated data.
+ *
+ * Parameters:
+ *  ctx    - Pointer to an ae_ctx structure initialized by ae_init.
+ *  nonce  - Pointer to a nonce_len (defined in ae_init) byte nonce.
+ *  pt     - Pointer to plaintext bytes to be encrypted.
+ *  pt_len - number of bytes pointed to by pt.
+ *  ad     - Pointer to associated data.
+ *  ad_len - number of bytes pointed to by ad.
+ *  ct     - Pointer to buffer to receive ciphertext encryption.
+ *  tag    - Pointer to receive authentication tag; or NULL
+ *           if tag is to be bundled into the ciphertext.
+ *  final  - Non-zero if this call completes the plaintext being encrypted.
+ *
+ * If nonce!=NULL then a message is being initiated. If final!=0
+ * then a message is being finalized. If final==0 or nonce==NULL
+ * then the incremental interface is being used. If nonce!=NULL and
+ * ad_len<0, then use same ad as last message.
+ *
+ * Returns:
+ *  non-negative     - Number of bytes written to ct.
+ *  AE_NOT_SUPPORTED - Usage mode unsupported (eg, incremental and/or sticky).
+ *  Otherwise        - Error. Check implementation documentation for codes.
+ *
+ * ----------------------------------------------------------------------- */
+
+int ae_decrypt(ae_ctx* ctx, const void* nonce, const void* ct, int ct_len, const void* ad,
+               int ad_len, void* pt, const void* tag, int final);
+/* --------------------------------------------------------------------------
+ *
+ * Decrypt ciphertext; provide authenticity of plaintext and associated data.
+ *
+ * Parameters:
+ *  ctx    - Pointer to an ae_ctx structure initialized by ae_init.
+ *  nonce  - Pointer to a nonce_len (defined in ae_init) byte nonce.
+ *  ct     - Pointer to ciphertext bytes to be decrypted.
+ *  ct_len - number of bytes pointed to by ct.
+ *  ad     - Pointer to associated data.
+ *  ad_len - number of bytes pointed to by ad.
+ *  pt     - Pointer to buffer to receive plaintext decryption.
+ *  tag    - Pointer to tag_len (defined in ae_init) bytes; or NULL
+ *           if tag is bundled into the ciphertext. Non-NULL tag is only
+ *           read when final is non-zero.
+ *  final  - Non-zero if this call completes the ciphertext being decrypted.
+ *
+ * If nonce!=NULL then "ct" points to the start of a ciphertext. If final!=0
+ * then "in" points to the final piece of ciphertext. If final==0 or nonce==
+ * NULL then the incremental interface is being used. If nonce!=NULL and
+ * ad_len<0, then use same ad as last message.
+ *
+ * Returns:
+ *  non-negative     - Number of bytes written to pt.
+ *  AE_INVALID       - Authentication failure.
+ *  AE_NOT_SUPPORTED - Usage mode unsupported (eg, incremental and/or sticky).
+ *  Otherwise        - Error. Check implementation documentation for codes.
+ *
+ * NOTE !!! NOTE !!! -- The ciphertext should be assumed possibly inauthentic
+ *                      until it has been completely written and it is
+ *                      verified that this routine did not return AE_INVALID.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+} /* closing brace for extern "C" */
+#endif
+
+#endif /* _AE_H_ */
diff --git a/keymaster/aes_key.cpp b/keymaster/aes_key.cpp
new file mode 100644
index 0000000..6b784b7
--- /dev/null
+++ b/keymaster/aes_key.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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 "aes_key.h"
+
+#include <assert.h>
+
+#include <new>
+
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+#include "aes_operation.h"
+
+namespace keymaster {
+
+AesEncryptionOperationFactory encrypt_factory;
+AesDecryptionOperationFactory decrypt_factory;
+
+OperationFactory* AesKeyFactory::GetOperationFactory(keymaster_purpose_t purpose) const {
+    switch (purpose) {
+    case KM_PURPOSE_ENCRYPT:
+        return &encrypt_factory;
+    case KM_PURPOSE_DECRYPT:
+        return &decrypt_factory;
+    default:
+        return nullptr;
+    }
+}
+
+keymaster_error_t AesKeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+                                         const AuthorizationSet& /* additional_params */,
+                                         const AuthorizationSet& hw_enforced,
+                                         const AuthorizationSet& sw_enforced,
+                                         UniquePtr<Key>* key) const {
+    if (!key)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    uint32_t min_mac_length = 0;
+    if (hw_enforced.Contains(TAG_BLOCK_MODE, KM_MODE_GCM) ||
+        sw_enforced.Contains(TAG_BLOCK_MODE, KM_MODE_GCM)) {
+
+        if (!hw_enforced.GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length) &&
+            !sw_enforced.GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length)) {
+
+            LOG_E("AES-GCM key must have KM_TAG_MIN_MAC_LENGTH", 0);
+            return KM_ERROR_INVALID_KEY_BLOB;
+        }
+    }
+
+    keymaster_error_t error = KM_ERROR_OK;
+    key->reset(new (std::nothrow) AesKey(key_material, hw_enforced, sw_enforced, &error));
+    if (!key->get())
+        error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    return error;
+}
+
+keymaster_error_t AesKeyFactory::validate_algorithm_specific_new_key_params(
+    const AuthorizationSet& key_description) const {
+    if (key_description.Contains(TAG_BLOCK_MODE, KM_MODE_GCM)) {
+        uint32_t min_tag_length;
+        if (!key_description.GetTagValue(TAG_MIN_MAC_LENGTH, &min_tag_length))
+            return KM_ERROR_MISSING_MIN_MAC_LENGTH;
+
+        if (min_tag_length % 8 != 0)
+            return KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH;
+
+        if (min_tag_length < kMinGcmTagLength || min_tag_length > kMaxGcmTagLength)
+            return KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH;
+    } else {
+        // Not GCM
+        if (key_description.find(TAG_MIN_MAC_LENGTH) != -1) {
+            LOG_W("KM_TAG_MIN_MAC_LENGTH found for non AES-GCM key", 0);
+            return KM_ERROR_INVALID_TAG;
+        }
+    }
+
+    return KM_ERROR_OK;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/aes_key.h b/keymaster/aes_key.h
new file mode 100644
index 0000000..a4ab2f2
--- /dev/null
+++ b/keymaster/aes_key.h
@@ -0,0 +1,60 @@
+/*
+ * 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_AES_KEY_H_
+#define SYSTEM_KEYMASTER_AES_KEY_H_
+
+#include <openssl/aes.h>
+
+#include "symmetric_key.h"
+
+namespace keymaster {
+
+const size_t kMinGcmTagLength = 12 * 8;
+const size_t kMaxGcmTagLength = 16 * 8;
+
+class AesKeyFactory : public SymmetricKeyFactory {
+  public:
+    explicit AesKeyFactory(const KeymasterContext* context) : SymmetricKeyFactory(context) {}
+
+    keymaster_algorithm_t registry_key() const { return KM_ALGORITHM_AES; }
+
+    keymaster_error_t LoadKey(const KeymasterKeyBlob& key_material,
+                              const AuthorizationSet& additional_params,
+                              const AuthorizationSet& hw_enforced,
+                              const AuthorizationSet& sw_enforced,
+                              UniquePtr<Key>* key) const override;
+
+    OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const 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;
+    }
+    keymaster_error_t validate_algorithm_specific_new_key_params(
+        const AuthorizationSet& key_description) const override;
+};
+
+class AesKey : public SymmetricKey {
+  public:
+    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
+
+#endif  // SYSTEM_KEYMASTER_AES_KEY_H_
diff --git a/keymaster/aes_operation.cpp b/keymaster/aes_operation.cpp
new file mode 100644
index 0000000..4c5c88c
--- /dev/null
+++ b/keymaster/aes_operation.cpp
@@ -0,0 +1,651 @@
+/*
+ * 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 "aes_operation.h"
+
+#include <stdio.h>
+
+#include <new>
+
+#include <UniquePtr.h>
+
+#include <openssl/aes.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+#include <keymaster/logger.h>
+
+#include "aes_key.h"
+#include "openssl_err.h"
+
+namespace keymaster {
+
+static const size_t GCM_NONCE_SIZE = 12;
+
+inline bool allows_padding(keymaster_block_mode_t block_mode) {
+    switch (block_mode) {
+    case KM_MODE_CTR:
+    case KM_MODE_GCM:
+        return false;
+    case KM_MODE_ECB:
+    case KM_MODE_CBC:
+        return true;
+    }
+    assert(false /* Can't get here */);
+    return false;
+}
+
+static keymaster_error_t GetAndValidateGcmTagLength(const AuthorizationSet& begin_params,
+                                                    const AuthorizationSet& key_params,
+                                                    size_t* tag_length) {
+    uint32_t tag_length_bits;
+    if (!begin_params.GetTagValue(TAG_MAC_LENGTH, &tag_length_bits)) {
+        return KM_ERROR_MISSING_MAC_LENGTH;
+    }
+
+    uint32_t min_tag_length_bits;
+    if (!key_params.GetTagValue(TAG_MIN_MAC_LENGTH, &min_tag_length_bits)) {
+        LOG_E("AES GCM key must have KM_TAG_MIN_MAC_LENGTH", 0);
+        return KM_ERROR_INVALID_KEY_BLOB;
+    }
+
+    if (tag_length_bits % 8 != 0 || tag_length_bits > kMaxGcmTagLength ||
+        tag_length_bits < kMinGcmTagLength) {
+        return KM_ERROR_UNSUPPORTED_MAC_LENGTH;
+    }
+
+    if (tag_length_bits < min_tag_length_bits) {
+        return KM_ERROR_INVALID_MAC_LENGTH;
+    }
+
+    *tag_length = tag_length_bits / 8;
+    return KM_ERROR_OK;
+}
+
+Operation* AesOperationFactory::CreateOperation(const Key& key,
+                                                const AuthorizationSet& begin_params,
+                                                keymaster_error_t* error) {
+    *error = KM_ERROR_OK;
+    const SymmetricKey* symmetric_key = static_cast<const SymmetricKey*>(&key);
+
+    switch (symmetric_key->key_data_size()) {
+    case 16:
+    case 24:
+    case 32:
+        break;
+    default:
+        *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
+        return nullptr;
+    }
+
+    keymaster_block_mode_t block_mode;
+    if (!begin_params.GetTagValue(TAG_BLOCK_MODE, &block_mode)) {
+        LOG_E("%d block modes specified in begin params", begin_params.GetTagCount(TAG_BLOCK_MODE));
+        *error = KM_ERROR_UNSUPPORTED_BLOCK_MODE;
+        return nullptr;
+    } else if (!supported(block_mode)) {
+        LOG_E("Block mode %d not supported", block_mode);
+        *error = KM_ERROR_UNSUPPORTED_BLOCK_MODE;
+        return nullptr;
+    } else if (!key.authorizations().Contains(TAG_BLOCK_MODE, block_mode)) {
+        LOG_E("Block mode %d was specified, but not authorized by key", block_mode);
+        *error = KM_ERROR_INCOMPATIBLE_BLOCK_MODE;
+        return nullptr;
+    }
+
+    size_t tag_length = 0;
+    if (block_mode == KM_MODE_GCM) {
+        *error = GetAndValidateGcmTagLength(begin_params, key.authorizations(), &tag_length);
+        if (*error != KM_ERROR_OK) {
+            return nullptr;
+        }
+    }
+
+    keymaster_padding_t padding;
+    if (!GetAndValidatePadding(begin_params, key, &padding, error)) {
+        return nullptr;
+    }
+    if (!allows_padding(block_mode) && padding != KM_PAD_NONE) {
+        LOG_E("Mode does not support padding", 0);
+        *error = KM_ERROR_INCOMPATIBLE_PADDING_MODE;
+        return nullptr;
+    }
+
+    bool caller_nonce = key.authorizations().GetTagValue(TAG_CALLER_NONCE);
+
+    Operation* op = nullptr;
+    switch (purpose()) {
+    case KM_PURPOSE_ENCRYPT:
+        op = new (std::nothrow)
+            AesEvpEncryptOperation(block_mode, padding, caller_nonce, tag_length,
+                                   symmetric_key->key_data(), symmetric_key->key_data_size());
+        break;
+    case KM_PURPOSE_DECRYPT:
+        op = new (std::nothrow)
+            AesEvpDecryptOperation(block_mode, padding, tag_length, symmetric_key->key_data(),
+                                   symmetric_key->key_data_size());
+        break;
+    default:
+        *error = KM_ERROR_UNSUPPORTED_PURPOSE;
+        return nullptr;
+    }
+
+    if (!op)
+        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    return op;
+}
+
+static const keymaster_block_mode_t supported_block_modes[] = {KM_MODE_ECB, KM_MODE_CBC,
+                                                               KM_MODE_CTR, KM_MODE_GCM};
+
+const keymaster_block_mode_t*
+AesOperationFactory::SupportedBlockModes(size_t* block_mode_count) const {
+    *block_mode_count = array_length(supported_block_modes);
+    return supported_block_modes;
+}
+
+static const keymaster_padding_t supported_padding_modes[] = {KM_PAD_NONE, KM_PAD_PKCS7};
+const keymaster_padding_t*
+AesOperationFactory::SupportedPaddingModes(size_t* padding_mode_count) const {
+    *padding_mode_count = array_length(supported_padding_modes);
+    return supported_padding_modes;
+}
+
+AesEvpOperation::AesEvpOperation(keymaster_purpose_t purpose, keymaster_block_mode_t block_mode,
+                                 keymaster_padding_t padding, bool caller_iv, size_t tag_length,
+                                 const uint8_t* key, size_t key_size)
+    : Operation(purpose), block_mode_(block_mode), caller_iv_(caller_iv), tag_length_(tag_length),
+      data_started_(false), key_size_(key_size), padding_(padding) {
+    memcpy(key_, key, key_size_);
+    EVP_CIPHER_CTX_init(&ctx_);
+}
+
+AesEvpOperation::~AesEvpOperation() {
+    EVP_CIPHER_CTX_cleanup(&ctx_);
+    memset_s(aad_block_buf_.get(), AES_BLOCK_SIZE, 0);
+}
+
+keymaster_error_t AesEvpOperation::Begin(const AuthorizationSet& /* input_params */,
+                                         AuthorizationSet* /* output_params */) {
+    if (block_mode_ == KM_MODE_GCM) {
+        aad_block_buf_length_ = 0;
+        aad_block_buf_.reset(new (std::nothrow) uint8_t[AES_BLOCK_SIZE]);
+        if (!aad_block_buf_.get())
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    return InitializeCipher();
+}
+
+keymaster_error_t AesEvpOperation::Update(const AuthorizationSet& additional_params,
+                                          const Buffer& input,
+                                          AuthorizationSet* /* output_params */, Buffer* output,
+                                          size_t* input_consumed) {
+    keymaster_error_t error;
+    if (block_mode_ == KM_MODE_GCM)
+        if (!HandleAad(additional_params, input, &error))
+            return error;
+
+    if (!InternalUpdate(input.peek_read(), input.available_read(), output, &error))
+        return error;
+    *input_consumed = input.available_read();
+
+    return KM_ERROR_OK;
+}
+
+inline bool is_bad_decrypt(unsigned long error) {
+    return (ERR_GET_LIB(error) == ERR_LIB_CIPHER &&  //
+            ERR_GET_REASON(error) == CIPHER_R_BAD_DECRYPT);
+}
+
+keymaster_error_t AesEvpOperation::Finish(const AuthorizationSet& additional_params,
+                                          const Buffer& input, const Buffer& /* signature */,
+                                          AuthorizationSet* output_params, Buffer* output) {
+    keymaster_error_t error;
+    if (!UpdateForFinish(additional_params, input, output_params, output, &error))
+        return error;
+
+    if (!output->reserve(AES_BLOCK_SIZE))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    if (block_mode_ == KM_MODE_GCM && aad_block_buf_length_ > 0 && !ProcessBufferedAadBlock(&error))
+        return error;
+
+    int output_written = -1;
+    if (!EVP_CipherFinal_ex(&ctx_, output->peek_write(), &output_written)) {
+        if (tag_length_ > 0)
+            return KM_ERROR_VERIFICATION_FAILED;
+        LOG_E("Error encrypting final block: %s", ERR_error_string(ERR_peek_last_error(), NULL));
+        return TranslateLastOpenSslError();
+    }
+
+    assert(output_written <= AES_BLOCK_SIZE);
+    if (!output->advance_write(output_written))
+        return KM_ERROR_UNKNOWN_ERROR;
+    return KM_ERROR_OK;
+}
+
+bool AesEvpOperation::need_iv() const {
+    switch (block_mode_) {
+    case KM_MODE_CBC:
+    case KM_MODE_CTR:
+    case KM_MODE_GCM:
+        return true;
+    case KM_MODE_ECB:
+        return false;
+    default:
+        // Shouldn't get here.
+        assert(false);
+        return false;
+    }
+}
+
+keymaster_error_t AesEvpOperation::InitializeCipher() {
+    const EVP_CIPHER* cipher;
+    switch (block_mode_) {
+    case KM_MODE_ECB:
+        switch (key_size_) {
+        case 16:
+            cipher = EVP_aes_128_ecb();
+            break;
+        case 24:
+            cipher = EVP_aes_192_ecb();
+            break;
+        case 32:
+            cipher = EVP_aes_256_ecb();
+            break;
+        default:
+            return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+        }
+        break;
+    case KM_MODE_CBC:
+        switch (key_size_) {
+        case 16:
+            cipher = EVP_aes_128_cbc();
+            break;
+        case 24:
+            cipher = EVP_aes_192_cbc();
+            break;
+        case 32:
+            cipher = EVP_aes_256_cbc();
+            break;
+        default:
+            return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+        }
+        break;
+    case KM_MODE_CTR:
+        switch (key_size_) {
+        case 16:
+            cipher = EVP_aes_128_ctr();
+            break;
+        case 24:
+            cipher = EVP_aes_192_ctr();
+            break;
+        case 32:
+            cipher = EVP_aes_256_ctr();
+            break;
+        default:
+            return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+        }
+        break;
+    case KM_MODE_GCM:
+        switch (key_size_) {
+        case 16:
+            cipher = EVP_aes_128_gcm();
+            break;
+        case 24:
+            cipher = EVP_aes_192_gcm();
+            break;
+        case 32:
+            cipher = EVP_aes_256_gcm();
+            break;
+        default:
+            return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+        }
+        break;
+    default:
+        return KM_ERROR_UNSUPPORTED_BLOCK_MODE;
+    }
+
+    if (!EVP_CipherInit_ex(&ctx_, cipher, NULL /* engine */, key_, iv_.get(), evp_encrypt_mode()))
+        return TranslateLastOpenSslError();
+
+    switch (padding_) {
+    case KM_PAD_NONE:
+        EVP_CIPHER_CTX_set_padding(&ctx_, 0 /* disable padding */);
+        break;
+    case KM_PAD_PKCS7:
+        // This is the default for OpenSSL EVP cipher operations.
+        break;
+    default:
+        return KM_ERROR_UNSUPPORTED_PADDING_MODE;
+    }
+
+    if (block_mode_ == KM_MODE_GCM) {
+        aad_block_buf_length_ = 0;
+        aad_block_buf_.reset(new (std::nothrow) uint8_t[AES_BLOCK_SIZE]);
+        if (!aad_block_buf_.get())
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t AesEvpOperation::GetIv(const AuthorizationSet& input_params) {
+    keymaster_blob_t iv_blob;
+    if (!input_params.GetTagValue(TAG_NONCE, &iv_blob)) {
+        LOG_E("No IV provided", 0);
+        return KM_ERROR_INVALID_ARGUMENT;
+    }
+    if (block_mode_ != KM_MODE_GCM && iv_blob.data_length != AES_BLOCK_SIZE) {
+        LOG_E("Expected %d-byte IV for AES operation, but got %d bytes", AES_BLOCK_SIZE,
+              iv_blob.data_length);
+        return KM_ERROR_INVALID_NONCE;
+    }
+    if (block_mode_ == KM_MODE_GCM && iv_blob.data_length != GCM_NONCE_SIZE) {
+        LOG_E("Expected %d-byte nonce for AES-GCM operation, but got %d bytes", GCM_NONCE_SIZE,
+              iv_blob.data_length);
+        return KM_ERROR_INVALID_NONCE;
+    }
+    iv_.reset(dup_array(iv_blob.data, iv_blob.data_length));
+    if (!iv_.get())
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    iv_length_ = iv_blob.data_length;
+    return KM_ERROR_OK;
+}
+
+/*
+ * Process Incoming Associated Authentication Data.
+ *
+ * This method is more complex than might be expected, because the underlying library silently does
+ * the wrong thing when given partial AAD blocks, so we have to take care to process AAD in
+ * AES_BLOCK_SIZE increments, buffering (in aad_block_buf_) when given smaller amounts of data.
+ */
+bool AesEvpOperation::HandleAad(const AuthorizationSet& input_params, const Buffer& input,
+                                keymaster_error_t* error) {
+    assert(tag_length_ > 0);
+    assert(error);
+
+    keymaster_blob_t aad;
+    if (input_params.GetTagValue(TAG_ASSOCIATED_DATA, &aad)) {
+        if (data_started_) {
+            *error = KM_ERROR_INVALID_TAG;
+            return false;
+        }
+
+        if (aad_block_buf_length_ > 0) {
+            FillBufferedAadBlock(&aad);
+            if (aad_block_buf_length_ == AES_BLOCK_SIZE && !ProcessBufferedAadBlock(error))
+                return false;
+        }
+
+        size_t blocks_to_process = aad.data_length / AES_BLOCK_SIZE;
+        if (blocks_to_process && !ProcessAadBlocks(aad.data, blocks_to_process, error))
+            return false;
+        aad.data += blocks_to_process * AES_BLOCK_SIZE;
+        aad.data_length -= blocks_to_process * AES_BLOCK_SIZE;
+
+        FillBufferedAadBlock(&aad);
+        assert(aad.data_length == 0);
+    }
+
+    if (input.available_read()) {
+        data_started_ = true;
+        // Data has begun, no more AAD is allowed.  Process any buffered AAD.
+        if (aad_block_buf_length_ > 0 && !ProcessBufferedAadBlock(error))
+            return false;
+    }
+
+    return true;
+}
+
+bool AesEvpOperation::ProcessBufferedAadBlock(keymaster_error_t* error) {
+    int output_written;
+    if (EVP_CipherUpdate(&ctx_, nullptr /* out */, &output_written, aad_block_buf_.get(),
+                         aad_block_buf_length_)) {
+        aad_block_buf_length_ = 0;
+        return true;
+    }
+    *error = TranslateLastOpenSslError();
+    return false;
+}
+
+bool AesEvpOperation::ProcessAadBlocks(const uint8_t* data, size_t blocks,
+                                       keymaster_error_t* error) {
+    int output_written;
+    if (EVP_CipherUpdate(&ctx_, nullptr /* out */, &output_written, data, blocks * AES_BLOCK_SIZE))
+        return true;
+    *error = TranslateLastOpenSslError();
+    return false;
+}
+
+inline size_t min(size_t a, size_t b) {
+    return (a < b) ? a : b;
+}
+
+void AesEvpOperation::FillBufferedAadBlock(keymaster_blob_t* aad) {
+    size_t to_buffer = min(AES_BLOCK_SIZE - aad_block_buf_length_, aad->data_length);
+    memcpy(aad_block_buf_.get() + aad_block_buf_length_, aad->data, to_buffer);
+    aad->data += to_buffer;
+    aad->data_length -= to_buffer;
+    aad_block_buf_length_ += to_buffer;
+}
+
+bool AesEvpOperation::InternalUpdate(const uint8_t* input, size_t input_length, Buffer* output,
+                                     keymaster_error_t* error) {
+    assert(output);
+    assert(error);
+
+    if (!input_length)
+        return true;
+
+    if (!output->reserve(input_length + AES_BLOCK_SIZE)) {
+        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        return false;
+    }
+
+    int output_written = -1;
+    if (!EVP_CipherUpdate(&ctx_, output->peek_write(), &output_written, input, input_length)) {
+        *error = TranslateLastOpenSslError();
+        return false;
+    }
+    return output->advance_write(output_written);
+}
+
+bool AesEvpOperation::UpdateForFinish(const AuthorizationSet& additional_params,
+                                      const Buffer& input, AuthorizationSet* output_params,
+                                      Buffer* output, keymaster_error_t* error) {
+    if (input.available_read() || !additional_params.empty()) {
+        size_t input_consumed;
+        *error = Update(additional_params, input, output_params, output, &input_consumed);
+        if (*error != KM_ERROR_OK)
+            return false;
+        if (input_consumed != input.available_read()) {
+            *error = KM_ERROR_INVALID_INPUT_LENGTH;
+            return false;
+        }
+    }
+
+    return true;
+}
+
+keymaster_error_t AesEvpEncryptOperation::Begin(const AuthorizationSet& input_params,
+                                                AuthorizationSet* output_params) {
+    if (!output_params)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    if (need_iv()) {
+        keymaster_error_t error = KM_ERROR_OK;
+        if (input_params.find(TAG_NONCE) == -1)
+            error = GenerateIv();
+        else if (caller_iv_)
+            error = GetIv(input_params);
+        else
+            error = KM_ERROR_CALLER_NONCE_PROHIBITED;
+
+        if (error == KM_ERROR_OK)
+            output_params->push_back(TAG_NONCE, iv_.get(), iv_length_);
+        else
+            return error;
+    }
+
+    return AesEvpOperation::Begin(input_params, output_params);
+}
+
+keymaster_error_t AesEvpEncryptOperation::Finish(const AuthorizationSet& additional_params,
+                                                 const Buffer& input, const Buffer& signature,
+                                                 AuthorizationSet* output_params, Buffer* output) {
+    if (!output->reserve(input.available_read() + AES_BLOCK_SIZE + tag_length_))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    keymaster_error_t error =
+        AesEvpOperation::Finish(additional_params, input, signature, output_params, output);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    if (tag_length_ > 0) {
+        if (!output->reserve(tag_length_))
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+        if (!EVP_CIPHER_CTX_ctrl(&ctx_, EVP_CTRL_GCM_GET_TAG, tag_length_, output->peek_write()))
+            return TranslateLastOpenSslError();
+        if (!output->advance_write(tag_length_))
+            return KM_ERROR_UNKNOWN_ERROR;
+    }
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t AesEvpEncryptOperation::GenerateIv() {
+    iv_length_ = (block_mode_ == KM_MODE_GCM) ? GCM_NONCE_SIZE : AES_BLOCK_SIZE;
+    iv_.reset(new (std::nothrow) uint8_t[iv_length_]);
+    if (!iv_.get())
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (RAND_bytes(iv_.get(), iv_length_) != 1)
+        return TranslateLastOpenSslError();
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t AesEvpDecryptOperation::Begin(const AuthorizationSet& input_params,
+                                                AuthorizationSet* output_params) {
+    if (need_iv()) {
+        keymaster_error_t error = GetIv(input_params);
+        if (error != KM_ERROR_OK)
+            return error;
+    }
+
+    if (tag_length_ > 0) {
+        tag_buf_length_ = 0;
+        tag_buf_.reset(new (std::nothrow) uint8_t[tag_length_]);
+        if (!tag_buf_.get())
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    return AesEvpOperation::Begin(input_params, output_params);
+}
+
+keymaster_error_t AesEvpDecryptOperation::Update(const AuthorizationSet& additional_params,
+                                                 const Buffer& input,
+                                                 AuthorizationSet* /* output_params */,
+                                                 Buffer* output, size_t* input_consumed) {
+    if (!output || !input_consumed)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    // Barring error, we'll consume it all.
+    *input_consumed = input.available_read();
+
+    keymaster_error_t error;
+    if (block_mode_ == KM_MODE_GCM) {
+        if (!HandleAad(additional_params, input, &error))
+            return error;
+        return ProcessAllButTagLengthBytes(input, output);
+    }
+
+    if (!InternalUpdate(input.peek_read(), input.available_read(), output, &error))
+        return error;
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t AesEvpDecryptOperation::ProcessAllButTagLengthBytes(const Buffer& input,
+                                                                      Buffer* output) {
+    if (input.available_read() <= tag_buf_unused()) {
+        BufferCandidateTagData(input.peek_read(), input.available_read());
+        return KM_ERROR_OK;
+    }
+
+    const size_t data_available = tag_buf_length_ + input.available_read();
+
+    const size_t to_process = data_available - tag_length_;
+    const size_t to_process_from_tag_buf = min(to_process, tag_buf_length_);
+    const size_t to_process_from_input = to_process - to_process_from_tag_buf;
+
+    if (!output->reserve(to_process + AES_BLOCK_SIZE))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    keymaster_error_t error;
+    if (!ProcessTagBufContentsAsData(to_process_from_tag_buf, output, &error))
+        return error;
+
+    if (!InternalUpdate(input.peek_read(), to_process_from_input, output, &error))
+        return error;
+
+    BufferCandidateTagData(input.peek_read() + to_process_from_input,
+                           input.available_read() - to_process_from_input);
+    assert(tag_buf_unused() == 0);
+
+    return KM_ERROR_OK;
+}
+
+bool AesEvpDecryptOperation::ProcessTagBufContentsAsData(size_t to_process, Buffer* output,
+                                                         keymaster_error_t* error) {
+    assert(to_process <= tag_buf_length_);
+    if (!InternalUpdate(tag_buf_.get(), to_process, output, error))
+        return false;
+    if (to_process < tag_buf_length_)
+        memmove(tag_buf_.get(), tag_buf_.get() + to_process, tag_buf_length_ - to_process);
+    tag_buf_length_ -= to_process;
+    return true;
+}
+
+void AesEvpDecryptOperation::BufferCandidateTagData(const uint8_t* data, size_t data_length) {
+    assert(data_length <= tag_length_ - tag_buf_length_);
+    memcpy(tag_buf_.get() + tag_buf_length_, data, data_length);
+    tag_buf_length_ += data_length;
+}
+
+keymaster_error_t AesEvpDecryptOperation::Finish(const AuthorizationSet& additional_params,
+                                                 const Buffer& input, const Buffer& signature,
+                                                 AuthorizationSet* output_params, Buffer* output) {
+    keymaster_error_t error;
+    if (!UpdateForFinish(additional_params, input, output_params, output, &error))
+        return error;
+
+    if (tag_buf_length_ < tag_length_)
+        return KM_ERROR_INVALID_INPUT_LENGTH;
+    else if (tag_length_ > 0 &&
+             !EVP_CIPHER_CTX_ctrl(&ctx_, EVP_CTRL_GCM_SET_TAG, tag_length_, tag_buf_.get()))
+        return TranslateLastOpenSslError();
+
+    AuthorizationSet empty_params;
+    Buffer empty_input;
+    return AesEvpOperation::Finish(empty_params, empty_input, signature, output_params, output);
+}
+
+keymaster_error_t AesEvpOperation::Abort() {
+    return KM_ERROR_OK;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/aes_operation.h b/keymaster/aes_operation.h
new file mode 100644
index 0000000..1a296bb
--- /dev/null
+++ b/keymaster/aes_operation.h
@@ -0,0 +1,158 @@
+/*
+ * 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_AES_OPERATION_H_
+#define SYSTEM_KEYMASTER_AES_OPERATION_H_
+
+#include <openssl/evp.h>
+
+#include "ocb_utils.h"
+#include "operation.h"
+
+namespace keymaster {
+
+/**
+ * Abstract base for AES operation factories.  This class does all of the work to create
+ * AES operations.
+ */
+class AesOperationFactory : public OperationFactory {
+  public:
+    KeyType registry_key() const override { return KeyType(KM_ALGORITHM_AES, purpose()); }
+
+    Operation* CreateOperation(const Key& key, const AuthorizationSet& begin_params,
+                               keymaster_error_t* error) override;
+    const keymaster_block_mode_t* SupportedBlockModes(size_t* block_mode_count) const override;
+    const keymaster_padding_t* SupportedPaddingModes(size_t* padding_count) const override;
+
+    virtual keymaster_purpose_t purpose() const = 0;
+};
+
+/**
+ * Concrete factory for AES encryption operations.
+ */
+class AesEncryptionOperationFactory : public AesOperationFactory {
+    keymaster_purpose_t purpose() const override { return KM_PURPOSE_ENCRYPT; }
+};
+
+/**
+ * Concrete factory for AES decryption operations.
+ */
+class AesDecryptionOperationFactory : public AesOperationFactory {
+    keymaster_purpose_t purpose() const override { return KM_PURPOSE_DECRYPT; }
+};
+
+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,
+                    keymaster_padding_t padding, bool caller_iv, size_t tag_length,
+                    const uint8_t* key, size_t key_size);
+    ~AesEvpOperation();
+
+    keymaster_error_t Begin(const AuthorizationSet& input_params,
+                            AuthorizationSet* output_params) override;
+    keymaster_error_t Update(const AuthorizationSet& additional_params, const Buffer& input,
+                             AuthorizationSet* output_params, Buffer* output,
+                             size_t* input_consumed) override;
+    keymaster_error_t Finish(const AuthorizationSet& additional_params, const Buffer& input,
+                             const Buffer& signature, AuthorizationSet* output_params,
+                             Buffer* output) override;
+    keymaster_error_t Abort() override;
+
+    virtual int evp_encrypt_mode() = 0;
+
+  protected:
+    bool need_iv() const;
+    keymaster_error_t InitializeCipher();
+    keymaster_error_t GetIv(const AuthorizationSet& input_params);
+    bool HandleAad(const AuthorizationSet& input_params, const Buffer& input,
+                   keymaster_error_t* error);
+    bool ProcessAadBlocks(const uint8_t* data, size_t blocks, keymaster_error_t* error);
+    void FillBufferedAadBlock(keymaster_blob_t* aad);
+    bool ProcessBufferedAadBlock(keymaster_error_t* error);
+    bool InternalUpdate(const uint8_t* input, size_t input_length, Buffer* output,
+                        keymaster_error_t* error);
+    bool UpdateForFinish(const AuthorizationSet& additional_params, const Buffer& input,
+                         AuthorizationSet* output_params, Buffer* output, keymaster_error_t* error);
+
+    const keymaster_block_mode_t block_mode_;
+    EVP_CIPHER_CTX ctx_;
+    UniquePtr<uint8_t[]> iv_;
+    size_t iv_length_;
+    const bool caller_iv_;
+    size_t tag_length_;
+    UniquePtr<uint8_t[]> aad_block_buf_;
+    size_t aad_block_buf_length_;
+
+  private:
+    bool data_started_;
+    const size_t key_size_;
+    const keymaster_padding_t padding_;
+    uint8_t key_[MAX_EVP_KEY_SIZE];
+};
+
+class AesEvpEncryptOperation : public AesEvpOperation {
+  public:
+    AesEvpEncryptOperation(keymaster_block_mode_t block_mode, keymaster_padding_t padding,
+                           bool caller_iv, size_t tag_length, const uint8_t* key, size_t key_size)
+        : AesEvpOperation(KM_PURPOSE_ENCRYPT, block_mode, padding, caller_iv, tag_length, key,
+                          key_size) {}
+
+    keymaster_error_t Begin(const AuthorizationSet& input_params,
+                            AuthorizationSet* output_params) override;
+    keymaster_error_t Finish(const AuthorizationSet& additional_params, const Buffer& input,
+                             const Buffer& signature, AuthorizationSet* output_params,
+                             Buffer* output) override;
+
+    int evp_encrypt_mode() override { return 1; }
+
+  private:
+    keymaster_error_t GenerateIv();
+};
+
+class AesEvpDecryptOperation : public AesEvpOperation {
+  public:
+    AesEvpDecryptOperation(keymaster_block_mode_t block_mode, keymaster_padding_t padding,
+                           size_t tag_length, const uint8_t* key, size_t key_size)
+        : AesEvpOperation(KM_PURPOSE_DECRYPT, block_mode, padding,
+                          false /* caller_iv -- don't care */, tag_length, key, key_size) {}
+
+    keymaster_error_t Begin(const AuthorizationSet& input_params,
+                            AuthorizationSet* output_params) override;
+    keymaster_error_t Update(const AuthorizationSet& additional_params, const Buffer& input,
+                             AuthorizationSet* output_params, Buffer* output,
+                             size_t* input_consumed) override;
+    keymaster_error_t Finish(const AuthorizationSet& additional_params, const Buffer& input,
+                             const Buffer& signature, AuthorizationSet* output_params,
+                             Buffer* output) override;
+
+    int evp_encrypt_mode() override { return 0; }
+
+  private:
+    size_t tag_buf_unused() { return tag_length_ - tag_buf_length_; }
+
+    keymaster_error_t ProcessAllButTagLengthBytes(const Buffer& input, Buffer* output);
+    bool ProcessTagBufContentsAsData(size_t to_process, Buffer* output, keymaster_error_t* error);
+    void BufferCandidateTagData(const uint8_t* data, size_t data_length);
+
+    UniquePtr<uint8_t[]> tag_buf_;
+    size_t tag_buf_length_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_AES_OPERATION_H_
diff --git a/keymaster/android_keymaster.cpp b/keymaster/android_keymaster.cpp
new file mode 100644
index 0000000..3a53394
--- /dev/null
+++ b/keymaster/android_keymaster.cpp
@@ -0,0 +1,440 @@
+/*
+ * 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 <keymaster/android_keymaster.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <cstddef>
+
+#include <openssl/rand.h>
+#include <openssl/x509.h>
+
+#include <UniquePtr.h>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/key_factory.h>
+#include <keymaster/keymaster_context.h>
+
+#include "ae.h"
+#include "key.h"
+#include "openssl_err.h"
+#include "operation.h"
+#include "operation_table.h"
+
+namespace keymaster {
+
+const uint8_t MAJOR_VER = 1;
+const uint8_t MINOR_VER = 1;
+const uint8_t SUBMINOR_VER = 0;
+
+AndroidKeymaster::AndroidKeymaster(KeymasterContext* context, size_t operation_table_size)
+    : context_(context), operation_table_(new OperationTable(operation_table_size)) {}
+
+AndroidKeymaster::~AndroidKeymaster() {}
+
+struct AE_CTX_Delete {
+    void operator()(ae_ctx* ctx) const { ae_free(ctx); }
+};
+typedef UniquePtr<ae_ctx, AE_CTX_Delete> Unique_ae_ctx;
+
+// TODO(swillden): Unify support analysis.  Right now, we have per-keytype methods that determine if
+// specific modes, padding, etc. are supported for that key type, and AndroidKeymaster also has
+// methods that return the same information.  They'll get out of sync.  Best to put the knowledge in
+// the keytypes and provide some mechanism for AndroidKeymaster to query the keytypes for the
+// information.
+
+template <typename T>
+bool check_supported(const KeymasterContext& context, keymaster_algorithm_t algorithm,
+                     SupportedResponse<T>* response) {
+    if (context.GetKeyFactory(algorithm) == NULL) {
+        response->error = KM_ERROR_UNSUPPORTED_ALGORITHM;
+        return false;
+    }
+    return true;
+}
+
+void AndroidKeymaster::GetVersion(const GetVersionRequest&, GetVersionResponse* rsp) {
+    if (rsp == NULL)
+        return;
+
+    rsp->major_ver = MAJOR_VER;
+    rsp->minor_ver = MINOR_VER;
+    rsp->subminor_ver = SUBMINOR_VER;
+    rsp->error = KM_ERROR_OK;
+}
+
+void AndroidKeymaster::SupportedAlgorithms(const SupportedAlgorithmsRequest& /* request */,
+                                           SupportedAlgorithmsResponse* response) {
+    if (response == NULL)
+        return;
+
+    response->error = KM_ERROR_OK;
+
+    size_t algorithm_count = 0;
+    const keymaster_algorithm_t* algorithms = context_->GetSupportedAlgorithms(&algorithm_count);
+    if (algorithm_count == 0)
+        return;
+    response->results_length = algorithm_count;
+    response->results = dup_array(algorithms, algorithm_count);
+    if (!response->results)
+        response->error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+}
+
+template <typename T>
+void GetSupported(const KeymasterContext& context, keymaster_algorithm_t algorithm,
+                  keymaster_purpose_t purpose,
+                  const T* (OperationFactory::*get_supported_method)(size_t* count) const,
+                  SupportedResponse<T>* response) {
+    if (response == NULL || !check_supported(context, algorithm, response))
+        return;
+
+    const OperationFactory* factory = context.GetOperationFactory(algorithm, purpose);
+    if (!factory) {
+        response->error = KM_ERROR_UNSUPPORTED_PURPOSE;
+        return;
+    }
+
+    size_t count;
+    const T* supported = (factory->*get_supported_method)(&count);
+    response->SetResults(supported, count);
+}
+
+void AndroidKeymaster::SupportedBlockModes(const SupportedBlockModesRequest& request,
+                                           SupportedBlockModesResponse* response) {
+    GetSupported(*context_, request.algorithm, request.purpose,
+                 &OperationFactory::SupportedBlockModes, response);
+}
+
+void AndroidKeymaster::SupportedPaddingModes(const SupportedPaddingModesRequest& request,
+                                             SupportedPaddingModesResponse* response) {
+    GetSupported(*context_, request.algorithm, request.purpose,
+                 &OperationFactory::SupportedPaddingModes, response);
+}
+
+void AndroidKeymaster::SupportedDigests(const SupportedDigestsRequest& request,
+                                        SupportedDigestsResponse* response) {
+    GetSupported(*context_, request.algorithm, request.purpose, &OperationFactory::SupportedDigests,
+                 response);
+}
+
+void AndroidKeymaster::SupportedImportFormats(const SupportedImportFormatsRequest& request,
+                                              SupportedImportFormatsResponse* response) {
+    if (response == NULL || !check_supported(*context_, request.algorithm, response))
+        return;
+
+    size_t count;
+    const keymaster_key_format_t* formats =
+        context_->GetKeyFactory(request.algorithm)->SupportedImportFormats(&count);
+    response->SetResults(formats, count);
+}
+
+void AndroidKeymaster::SupportedExportFormats(const SupportedExportFormatsRequest& request,
+                                              SupportedExportFormatsResponse* response) {
+    if (response == NULL || !check_supported(*context_, request.algorithm, response))
+        return;
+
+    size_t count;
+    const keymaster_key_format_t* formats =
+        context_->GetKeyFactory(request.algorithm)->SupportedExportFormats(&count);
+    response->SetResults(formats, count);
+}
+
+void AndroidKeymaster::AddRngEntropy(const AddEntropyRequest& request,
+                                     AddEntropyResponse* response) {
+    response->error = context_->AddRngEntropy(request.random_data.peek_read(),
+                                              request.random_data.available_read());
+}
+
+void AndroidKeymaster::GenerateKey(const GenerateKeyRequest& request,
+                                   GenerateKeyResponse* response) {
+    if (response == NULL)
+        return;
+
+    keymaster_algorithm_t algorithm;
+    KeyFactory* factory = 0;
+    UniquePtr<Key> key;
+    if (!request.key_description.GetTagValue(TAG_ALGORITHM, &algorithm) ||
+        !(factory = context_->GetKeyFactory(algorithm)))
+        response->error = KM_ERROR_UNSUPPORTED_ALGORITHM;
+    else {
+        KeymasterKeyBlob key_blob;
+        response->enforced.Clear();
+        response->unenforced.Clear();
+        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,
+                                             GetKeyCharacteristicsResponse* response) {
+    if (response == NULL)
+        return;
+
+    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;
+}
+
+static KeyFactory* GetKeyFactory(const KeymasterContext& context,
+                                 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 = context.GetKeyFactory(*algorithm);
+    if (factory)
+        *error = KM_ERROR_OK;
+    return factory;
+}
+
+void AndroidKeymaster::BeginOperation(const BeginOperationRequest& request,
+                                      BeginOperationResponse* response) {
+    if (response == NULL)
+        return;
+    response->op_handle = 0;
+
+    AuthorizationSet hw_enforced;
+    AuthorizationSet sw_enforced;
+    const KeyFactory* key_factory;
+    UniquePtr<Key> key;
+    response->error = LoadKey(request.key_blob, request.additional_params, &hw_enforced,
+                              &sw_enforced, &key_factory, &key);
+    if (response->error != KM_ERROR_OK)
+        return;
+
+    response->error = KM_ERROR_UNKNOWN_ERROR;
+    keymaster_algorithm_t key_algorithm;
+    if (!key->authorizations().GetTagValue(TAG_ALGORITHM, &key_algorithm))
+        return;
+
+    response->error = KM_ERROR_UNSUPPORTED_PURPOSE;
+    OperationFactory* factory = key_factory->GetOperationFactory(request.purpose);
+    if (!factory)
+        return;
+
+    UniquePtr<Operation> operation(
+        factory->CreateOperation(*key, request.additional_params, &response->error));
+    if (operation.get() == NULL)
+        return;
+
+    if (context_->enforcement_policy()) {
+        km_id_t key_id;
+        response->error = KM_ERROR_UNKNOWN_ERROR;
+        if (!context_->enforcement_policy()->CreateKeyId(request.key_blob, &key_id))
+            return;
+        operation->set_key_id(key_id);
+        response->error = context_->enforcement_policy()->AuthorizeOperation(
+            request.purpose, key_id, key->authorizations(), request.additional_params,
+            0 /* op_handle */, true /* is_begin_operation */);
+        if (response->error != KM_ERROR_OK)
+            return;
+    }
+
+    response->output_params.Clear();
+    response->error = operation->Begin(request.additional_params, &response->output_params);
+    if (response->error != KM_ERROR_OK)
+        return;
+
+    operation->SetAuthorizations(key->authorizations());
+    response->error = operation_table_->Add(operation.release(), &response->op_handle);
+}
+
+void AndroidKeymaster::UpdateOperation(const UpdateOperationRequest& request,
+                                       UpdateOperationResponse* response) {
+    if (response == NULL)
+        return;
+
+    response->error = KM_ERROR_INVALID_OPERATION_HANDLE;
+    Operation* operation = operation_table_->Find(request.op_handle);
+    if (operation == NULL)
+        return;
+
+    if (context_->enforcement_policy()) {
+        response->error = context_->enforcement_policy()->AuthorizeOperation(
+            operation->purpose(), operation->key_id(), operation->authorizations(),
+            request.additional_params, request.op_handle, false /* is_begin_operation */);
+        if (response->error != KM_ERROR_OK) {
+            operation_table_->Delete(request.op_handle);
+            return;
+        }
+    }
+
+    response->error =
+        operation->Update(request.additional_params, request.input, &response->output_params,
+                          &response->output, &response->input_consumed);
+    if (response->error != KM_ERROR_OK) {
+        // Any error invalidates the operation.
+        operation_table_->Delete(request.op_handle);
+    }
+}
+
+void AndroidKeymaster::FinishOperation(const FinishOperationRequest& request,
+                                       FinishOperationResponse* response) {
+    if (response == NULL)
+        return;
+
+    response->error = KM_ERROR_INVALID_OPERATION_HANDLE;
+    Operation* operation = operation_table_->Find(request.op_handle);
+    if (operation == NULL)
+        return;
+
+    if (context_->enforcement_policy()) {
+        response->error = context_->enforcement_policy()->AuthorizeOperation(
+            operation->purpose(), operation->key_id(), operation->authorizations(),
+            request.additional_params, request.op_handle, false /* is_begin_operation */);
+        if (response->error != KM_ERROR_OK) {
+            operation_table_->Delete(request.op_handle);
+            return;
+        }
+    }
+
+    response->error = operation->Finish(request.additional_params, request.input, request.signature,
+                                        &response->output_params, &response->output);
+    operation_table_->Delete(request.op_handle);
+}
+
+void AndroidKeymaster::AbortOperation(const AbortOperationRequest& request,
+                                      AbortOperationResponse* response) {
+    if (!response)
+        return;
+
+    Operation* operation = operation_table_->Find(request.op_handle);
+    if (!operation) {
+        response->error = KM_ERROR_INVALID_OPERATION_HANDLE;
+        return;
+    }
+
+    response->error = operation->Abort();
+    operation_table_->Delete(request.op_handle);
+}
+
+void AndroidKeymaster::ExportKey(const ExportKeyRequest& request, ExportKeyResponse* response) {
+    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;
+    KeyFactory* key_factory =
+        GetKeyFactory(*context_, hw_enforced, sw_enforced, &algorithm, &response->error);
+    if (!key_factory)
+        return;
+
+    UniquePtr<Key> key;
+    response->error = key_factory->LoadKey(key_material, request.additional_params, hw_enforced,
+                                           sw_enforced, &key);
+    if (response->error != KM_ERROR_OK)
+        return;
+
+    UniquePtr<uint8_t[]> out_key;
+    size_t 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;
+    }
+}
+
+void AndroidKeymaster::AttestKey(const AttestKeyRequest& request, AttestKeyResponse* response) {
+    if (!response)
+        return;
+
+    AuthorizationSet tee_enforced;
+    AuthorizationSet sw_enforced;
+    const KeyFactory* key_factory;
+    UniquePtr<Key> key;
+    response->error = LoadKey(request.key_blob, request.attest_params, &tee_enforced, &sw_enforced,
+                              &key_factory, &key);
+    if (response->error != KM_ERROR_OK)
+        return;
+
+    response->error = key->GenerateAttestation(*context_, request.attest_params, tee_enforced,
+                                               sw_enforced, &response->certificate_chain);
+}
+
+void AndroidKeymaster::ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response) {
+    if (response == NULL)
+        return;
+
+    keymaster_algorithm_t algorithm;
+    KeyFactory* factory = 0;
+    UniquePtr<Key> key;
+    if (!request.key_description.GetTagValue(TAG_ALGORITHM, &algorithm) ||
+        !(factory = context_->GetKeyFactory(algorithm)))
+        response->error = KM_ERROR_UNSUPPORTED_ALGORITHM;
+    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();
+    }
+}
+
+void AndroidKeymaster::DeleteKey(const DeleteKeyRequest& request, DeleteKeyResponse* response) {
+    if (!response)
+        return;
+    response->error = context_->DeleteKey(KeymasterKeyBlob(request.key_blob));
+}
+
+void AndroidKeymaster::DeleteAllKeys(const DeleteAllKeysRequest&, DeleteAllKeysResponse* response) {
+    if (!response)
+        return;
+    response->error = context_->DeleteAllKeys();
+}
+
+bool AndroidKeymaster::has_operation(keymaster_operation_handle_t op_handle) const {
+    return operation_table_->Find(op_handle) != nullptr;
+}
+
+keymaster_error_t AndroidKeymaster::LoadKey(const keymaster_key_blob_t& key_blob,
+                                            const AuthorizationSet& additional_params,
+                                            AuthorizationSet* hw_enforced,
+                                            AuthorizationSet* sw_enforced,
+                                            const KeyFactory** factory, 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;
+
+    keymaster_algorithm_t algorithm;
+    *factory = GetKeyFactory(*context_, *hw_enforced, *sw_enforced, &algorithm, &error);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    return (*factory)->LoadKey(key_material, additional_params, *hw_enforced, *sw_enforced, key);
+}
+
+}  // namespace keymaster
diff --git a/keymaster/android_keymaster_messages.cpp b/keymaster/android_keymaster_messages.cpp
new file mode 100644
index 0000000..1b8f36e
--- /dev/null
+++ b/keymaster/android_keymaster_messages.cpp
@@ -0,0 +1,526 @@
+/*
+ * 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 <keymaster/android_keymaster_messages.h>
+#include <keymaster/android_keymaster_utils.h>
+
+namespace keymaster {
+
+/*
+ * Helper functions for working with key blobs.
+ */
+
+static void set_key_blob(keymaster_key_blob_t* key_blob, const void* key_material, size_t length) {
+    delete[] key_blob->key_material;
+    key_blob->key_material = dup_buffer(key_material, length);
+    key_blob->key_material_size = length;
+}
+
+static size_t key_blob_size(const keymaster_key_blob_t& key_blob) {
+    return sizeof(uint32_t) /* key size */ + key_blob.key_material_size;
+}
+
+static uint8_t* serialize_key_blob(const keymaster_key_blob_t& key_blob, uint8_t* buf,
+                                   const uint8_t* end) {
+    return append_size_and_data_to_buf(buf, end, key_blob.key_material, key_blob.key_material_size);
+}
+
+static bool deserialize_key_blob(keymaster_key_blob_t* key_blob, const uint8_t** buf_ptr,
+                                 const uint8_t* end) {
+    delete[] key_blob->key_material;
+    key_blob->key_material = 0;
+    UniquePtr<uint8_t[]> deserialized_key_material;
+    if (!copy_size_and_data_from_buf(buf_ptr, end, &key_blob->key_material_size,
+                                     &deserialized_key_material))
+        return false;
+    key_blob->key_material = deserialized_key_material.release();
+    return true;
+}
+
+size_t KeymasterResponse::SerializedSize() const {
+    if (error != KM_ERROR_OK)
+        return sizeof(int32_t);
+    else
+        return sizeof(int32_t) + NonErrorSerializedSize();
+}
+
+uint8_t* KeymasterResponse::Serialize(uint8_t* buf, const uint8_t* end) const {
+    buf = append_uint32_to_buf(buf, end, static_cast<uint32_t>(error));
+    if (error == KM_ERROR_OK)
+        buf = NonErrorSerialize(buf, end);
+    return buf;
+}
+
+bool KeymasterResponse::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    if (!copy_uint32_from_buf(buf_ptr, end, &error))
+        return false;
+    if (error != KM_ERROR_OK)
+        return true;
+    return NonErrorDeserialize(buf_ptr, end);
+}
+
+GenerateKeyResponse::~GenerateKeyResponse() {
+    delete[] key_blob.key_material;
+}
+
+size_t GenerateKeyResponse::NonErrorSerializedSize() const {
+    return key_blob_size(key_blob) + enforced.SerializedSize() + unenforced.SerializedSize();
+}
+
+uint8_t* GenerateKeyResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
+    buf = serialize_key_blob(key_blob, buf, end);
+    buf = enforced.Serialize(buf, end);
+    return unenforced.Serialize(buf, end);
+}
+
+bool GenerateKeyResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    return deserialize_key_blob(&key_blob, buf_ptr, end) && enforced.Deserialize(buf_ptr, end) &&
+           unenforced.Deserialize(buf_ptr, end);
+}
+
+GetKeyCharacteristicsRequest::~GetKeyCharacteristicsRequest() {
+    delete[] key_blob.key_material;
+}
+
+void GetKeyCharacteristicsRequest::SetKeyMaterial(const void* key_material, size_t length) {
+    set_key_blob(&key_blob, key_material, length);
+}
+
+size_t GetKeyCharacteristicsRequest::SerializedSize() const {
+    return key_blob_size(key_blob) + additional_params.SerializedSize();
+}
+
+uint8_t* GetKeyCharacteristicsRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
+    buf = serialize_key_blob(key_blob, buf, end);
+    return additional_params.Serialize(buf, end);
+}
+
+bool GetKeyCharacteristicsRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    return deserialize_key_blob(&key_blob, buf_ptr, end) &&
+           additional_params.Deserialize(buf_ptr, end);
+}
+
+size_t GetKeyCharacteristicsResponse::NonErrorSerializedSize() const {
+    return enforced.SerializedSize() + unenforced.SerializedSize();
+}
+
+uint8_t* GetKeyCharacteristicsResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
+    buf = enforced.Serialize(buf, end);
+    return unenforced.Serialize(buf, end);
+}
+
+bool GetKeyCharacteristicsResponse::NonErrorDeserialize(const uint8_t** buf_ptr,
+                                                        const uint8_t* end) {
+    return enforced.Deserialize(buf_ptr, end) && unenforced.Deserialize(buf_ptr, end);
+}
+
+void BeginOperationRequest::SetKeyMaterial(const void* key_material, size_t length) {
+    set_key_blob(&key_blob, key_material, length);
+}
+
+size_t BeginOperationRequest::SerializedSize() const {
+    return sizeof(uint32_t) /* purpose */ + key_blob_size(key_blob) +
+           additional_params.SerializedSize();
+}
+
+uint8_t* BeginOperationRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
+    buf = append_uint32_to_buf(buf, end, purpose);
+    buf = serialize_key_blob(key_blob, buf, end);
+    return additional_params.Serialize(buf, end);
+}
+
+bool BeginOperationRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    return copy_uint32_from_buf(buf_ptr, end, &purpose) &&
+           deserialize_key_blob(&key_blob, buf_ptr, end) &&
+           additional_params.Deserialize(buf_ptr, end);
+}
+
+size_t BeginOperationResponse::NonErrorSerializedSize() const {
+    if (message_version == 0)
+        return sizeof(op_handle);
+    else
+        return sizeof(op_handle) + output_params.SerializedSize();
+}
+
+uint8_t* BeginOperationResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
+    buf = append_uint64_to_buf(buf, end, op_handle);
+    if (message_version > 0)
+        buf = output_params.Serialize(buf, end);
+    return buf;
+}
+
+bool BeginOperationResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    bool retval = copy_uint64_from_buf(buf_ptr, end, &op_handle);
+    if (retval && message_version > 0)
+        retval = output_params.Deserialize(buf_ptr, end);
+    return retval;
+}
+
+size_t UpdateOperationRequest::SerializedSize() const {
+    if (message_version == 0)
+        return sizeof(op_handle) + input.SerializedSize();
+    else
+        return sizeof(op_handle) + input.SerializedSize() + additional_params.SerializedSize();
+}
+
+uint8_t* UpdateOperationRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
+    buf = append_uint64_to_buf(buf, end, op_handle);
+    buf = input.Serialize(buf, end);
+    if (message_version > 0)
+        buf = additional_params.Serialize(buf, end);
+    return buf;
+}
+
+bool UpdateOperationRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    bool retval = copy_uint64_from_buf(buf_ptr, end, &op_handle) && input.Deserialize(buf_ptr, end);
+    if (retval && message_version > 0)
+        retval = additional_params.Deserialize(buf_ptr, end);
+    return retval;
+}
+
+size_t UpdateOperationResponse::NonErrorSerializedSize() const {
+    size_t size = 0;
+    switch (message_version) {
+    case 3:
+    case 2:
+        size += output_params.SerializedSize();
+        ; /* falls through */
+    case 1:
+        size += sizeof(uint32_t);
+        ; /* falls through */
+    case 0:
+        size += output.SerializedSize();
+        break;
+
+    default:
+        assert(false);
+    }
+
+    return size;
+}
+
+uint8_t* UpdateOperationResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
+    buf = output.Serialize(buf, end);
+    if (message_version > 0)
+        buf = append_uint32_to_buf(buf, end, input_consumed);
+    if (message_version > 1)
+        buf = output_params.Serialize(buf, end);
+    return buf;
+}
+
+bool UpdateOperationResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    bool retval = output.Deserialize(buf_ptr, end);
+    if (retval && message_version > 0)
+        retval = copy_uint32_from_buf(buf_ptr, end, &input_consumed);
+    if (retval && message_version > 1)
+        retval = output_params.Deserialize(buf_ptr, end);
+    return retval;
+}
+
+size_t FinishOperationRequest::SerializedSize() const {
+    size_t size = 0;
+    switch (message_version) {
+    case 3:
+        size += input.SerializedSize();
+        ; /* falls through */
+    case 2:
+    case 1:
+        size += additional_params.SerializedSize();
+        ; /* falls through */
+    case 0:
+        size += sizeof(op_handle) + signature.SerializedSize();
+        break;
+
+    default:
+        assert(false);  // Should never get here.
+    }
+
+    return size;
+}
+
+uint8_t* FinishOperationRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
+    buf = append_uint64_to_buf(buf, end, op_handle);
+    buf = signature.Serialize(buf, end);
+    if (message_version > 0)
+        buf = additional_params.Serialize(buf, end);
+    if (message_version > 2)
+        buf = input.Serialize(buf, end);
+    return buf;
+}
+
+bool FinishOperationRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    bool retval =
+        copy_uint64_from_buf(buf_ptr, end, &op_handle) && signature.Deserialize(buf_ptr, end);
+    if (retval && message_version > 0)
+        retval = additional_params.Deserialize(buf_ptr, end);
+    if (retval && message_version > 2)
+        retval = input.Deserialize(buf_ptr, end);
+    return retval;
+}
+
+size_t FinishOperationResponse::NonErrorSerializedSize() const {
+    if (message_version < 2)
+        return output.SerializedSize();
+    else
+        return output.SerializedSize() + output_params.SerializedSize();
+}
+
+uint8_t* FinishOperationResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
+    buf = output.Serialize(buf, end);
+    if (message_version > 1)
+        buf = output_params.Serialize(buf, end);
+    return buf;
+}
+
+bool FinishOperationResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    bool retval = output.Deserialize(buf_ptr, end);
+    if (retval && message_version > 1)
+        retval = output_params.Deserialize(buf_ptr, end);
+    return retval;
+}
+
+size_t AddEntropyRequest::SerializedSize() const {
+    return random_data.SerializedSize();
+}
+
+uint8_t* AddEntropyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
+    return random_data.Serialize(buf, end);
+}
+
+bool AddEntropyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    return random_data.Deserialize(buf_ptr, end);
+}
+
+void ImportKeyRequest::SetKeyMaterial(const void* key_material, size_t length) {
+    delete[] key_data;
+    key_data = dup_buffer(key_material, length);
+    key_data_length = length;
+}
+
+size_t ImportKeyRequest::SerializedSize() const {
+    return key_description.SerializedSize() + sizeof(uint32_t) /* key_format */ +
+           sizeof(uint32_t) /* key_data_length */ + key_data_length;
+}
+
+uint8_t* ImportKeyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
+    buf = key_description.Serialize(buf, end);
+    buf = append_uint32_to_buf(buf, end, key_format);
+    return append_size_and_data_to_buf(buf, end, key_data, key_data_length);
+}
+
+bool ImportKeyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    delete[] key_data;
+    key_data = NULL;
+    UniquePtr<uint8_t[]> deserialized_key_material;
+    if (!key_description.Deserialize(buf_ptr, end) ||
+        !copy_uint32_from_buf(buf_ptr, end, &key_format) ||
+        !copy_size_and_data_from_buf(buf_ptr, end, &key_data_length, &deserialized_key_material))
+        return false;
+    key_data = deserialized_key_material.release();
+    return true;
+}
+
+void ImportKeyResponse::SetKeyMaterial(const void* key_material, size_t length) {
+    set_key_blob(&key_blob, key_material, length);
+}
+
+size_t ImportKeyResponse::NonErrorSerializedSize() const {
+    return key_blob_size(key_blob) + enforced.SerializedSize() + unenforced.SerializedSize();
+}
+
+uint8_t* ImportKeyResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
+    buf = serialize_key_blob(key_blob, buf, end);
+    buf = enforced.Serialize(buf, end);
+    return unenforced.Serialize(buf, end);
+}
+
+bool ImportKeyResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    return deserialize_key_blob(&key_blob, buf_ptr, end) && enforced.Deserialize(buf_ptr, end) &&
+           unenforced.Deserialize(buf_ptr, end);
+}
+
+void ExportKeyRequest::SetKeyMaterial(const void* key_material, size_t length) {
+    set_key_blob(&key_blob, key_material, length);
+}
+
+size_t ExportKeyRequest::SerializedSize() const {
+    return additional_params.SerializedSize() + sizeof(uint32_t) /* key_format */ +
+           key_blob_size(key_blob);
+}
+
+uint8_t* ExportKeyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
+    buf = additional_params.Serialize(buf, end);
+    buf = append_uint32_to_buf(buf, end, key_format);
+    return serialize_key_blob(key_blob, buf, end);
+}
+
+bool ExportKeyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    return additional_params.Deserialize(buf_ptr, end) &&
+           copy_uint32_from_buf(buf_ptr, end, &key_format) &&
+           deserialize_key_blob(&key_blob, buf_ptr, end);
+}
+
+void ExportKeyResponse::SetKeyMaterial(const void* key_material, size_t length) {
+    delete[] key_data;
+    key_data = dup_buffer(key_material, length);
+    key_data_length = length;
+}
+
+size_t ExportKeyResponse::NonErrorSerializedSize() const {
+    return sizeof(uint32_t) /* key_data_length */ + key_data_length;
+}
+
+uint8_t* ExportKeyResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
+    return append_size_and_data_to_buf(buf, end, key_data, key_data_length);
+}
+
+bool ExportKeyResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    delete[] key_data;
+    key_data = NULL;
+    UniquePtr<uint8_t[]> deserialized_key_material;
+    if (!copy_size_and_data_from_buf(buf_ptr, end, &key_data_length, &deserialized_key_material))
+        return false;
+    key_data = deserialized_key_material.release();
+    return true;
+}
+
+void DeleteKeyRequest::SetKeyMaterial(const void* key_material, size_t length) {
+    set_key_blob(&key_blob, key_material, length);
+}
+
+size_t DeleteKeyRequest::SerializedSize() const {
+    return key_blob_size(key_blob);
+}
+
+uint8_t* DeleteKeyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
+    return serialize_key_blob(key_blob, buf, end);
+}
+
+bool DeleteKeyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    return deserialize_key_blob(&key_blob, buf_ptr, end);
+}
+
+size_t GetVersionResponse::NonErrorSerializedSize() const {
+    return sizeof(major_ver) + sizeof(minor_ver) + sizeof(subminor_ver);
+}
+
+uint8_t* GetVersionResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
+    if (buf + NonErrorSerializedSize() <= end) {
+        *buf++ = major_ver;
+        *buf++ = minor_ver;
+        *buf++ = subminor_ver;
+    } else {
+        buf += NonErrorSerializedSize();
+    }
+    return buf;
+}
+
+bool GetVersionResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    if (*buf_ptr + NonErrorSerializedSize() > end)
+        return false;
+    const uint8_t* tmp = *buf_ptr;
+    major_ver = *tmp++;
+    minor_ver = *tmp++;
+    subminor_ver = *tmp++;
+    *buf_ptr = tmp;
+    return true;
+}
+
+AttestKeyRequest::~AttestKeyRequest() {
+    delete[] key_blob.key_material;
+}
+
+void AttestKeyRequest::SetKeyMaterial(const void* key_material, size_t length) {
+    set_key_blob(&key_blob, key_material, length);
+}
+
+size_t AttestKeyRequest::SerializedSize() const {
+    return key_blob_size(key_blob) + attest_params.SerializedSize();
+}
+
+uint8_t* AttestKeyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
+    buf = serialize_key_blob(key_blob, buf, end);
+    return attest_params.Serialize(buf, end);
+}
+
+bool AttestKeyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    return deserialize_key_blob(&key_blob, buf_ptr, end) && attest_params.Deserialize(buf_ptr, end);
+}
+
+AttestKeyResponse::~AttestKeyResponse() {
+    for (size_t i = 0; i < certificate_chain.entry_count; ++i)
+        delete[] certificate_chain.entries[i].data;
+    delete[] certificate_chain.entries;
+}
+
+const size_t kMaxChainEntryCount = 10;
+bool AttestKeyResponse::AllocateChain(size_t entry_count) {
+    if (entry_count > kMaxChainEntryCount)
+        return false;
+
+    if (certificate_chain.entries) {
+        for (size_t i = 0; i < certificate_chain.entry_count; ++i)
+            delete[] certificate_chain.entries[i].data;
+        delete[] certificate_chain.entries;
+    }
+
+    certificate_chain.entry_count = entry_count;
+    certificate_chain.entries = new keymaster_blob_t[entry_count];
+    if (!certificate_chain.entries) {
+        certificate_chain.entry_count = 0;
+        return false;
+    }
+
+    memset(certificate_chain.entries, 0, sizeof(certificate_chain.entries[0]) * entry_count);
+    return true;
+}
+
+size_t AttestKeyResponse::NonErrorSerializedSize() const {
+    size_t result = sizeof(uint32_t); /* certificate_chain.entry_count */
+    for (size_t i = 0; i < certificate_chain.entry_count; ++i) {
+        result += sizeof(uint32_t); /* certificate_chain.entries[i].data_length */
+        result += certificate_chain.entries[i].data_length;
+    }
+    return result;
+}
+
+uint8_t* AttestKeyResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
+    buf = append_uint32_to_buf(buf, end, certificate_chain.entry_count);
+    for (size_t i = 0; i < certificate_chain.entry_count; ++i) {
+        buf = append_size_and_data_to_buf(buf, end, certificate_chain.entries[i].data,
+                                          certificate_chain.entries[i].data_length);
+    }
+    return buf;
+}
+
+bool AttestKeyResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    size_t entry_count;
+    if (!copy_uint32_from_buf(buf_ptr, end, &entry_count) || !AllocateChain(entry_count))
+        return false;
+
+    for (size_t i = 0; i < certificate_chain.entry_count; ++i) {
+        UniquePtr<uint8_t[]> data;
+        size_t data_length;
+        if (!copy_size_and_data_from_buf(buf_ptr, end, &data_length, &data))
+            return false;
+        certificate_chain.entries[i].data = data.release();
+        certificate_chain.entries[i].data_length = data_length;
+    }
+
+    return true;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/android_keymaster_messages_test.cpp b/keymaster/android_keymaster_messages_test.cpp
new file mode 100644
index 0000000..1ec5894
--- /dev/null
+++ b/keymaster/android_keymaster_messages_test.cpp
@@ -0,0 +1,683 @@
+/*
+ * Copyright (C) 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 <UniquePtr.h>
+
+#include <gtest/gtest.h>
+
+#include <keymaster/android_keymaster.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/keymaster_tags.h>
+
+#include "android_keymaster_test_utils.h"
+
+namespace keymaster {
+namespace test {
+
+/**
+ * Serialize and deserialize a message.
+ */
+template <typename Message>
+Message* round_trip(int32_t ver, const Message& message, size_t expected_size) {
+    size_t size = message.SerializedSize();
+    EXPECT_EQ(expected_size, size);
+    if (size == 0)
+        return NULL;
+
+    UniquePtr<uint8_t[]> buf(new uint8_t[size]);
+    EXPECT_EQ(buf.get() + size, message.Serialize(buf.get(), buf.get() + size));
+
+    Message* deserialized = new Message(ver);
+    const uint8_t* p = buf.get();
+    EXPECT_TRUE(deserialized->Deserialize(&p, p + size));
+    EXPECT_EQ((ptrdiff_t)size, p - buf.get());
+    return deserialized;
+}
+
+struct EmptyKeymasterResponse : public KeymasterResponse {
+    explicit EmptyKeymasterResponse(int32_t ver) : KeymasterResponse(ver) {}
+    size_t NonErrorSerializedSize() const { return 1; }
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* /* end */) const {
+        *buf++ = 0;
+        return buf;
+    }
+    bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+        if (*buf_ptr >= end)
+            return false;
+        EXPECT_EQ(0, **buf_ptr);
+        (*buf_ptr)++;
+        return true;
+    }
+};
+
+TEST(RoundTrip, EmptyKeymasterResponse) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        EmptyKeymasterResponse msg(ver);
+        msg.error = KM_ERROR_OK;
+
+        UniquePtr<EmptyKeymasterResponse> deserialized(round_trip(ver, msg, 5));
+    }
+}
+
+TEST(RoundTrip, EmptyKeymasterResponseError) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        EmptyKeymasterResponse msg(ver);
+        msg.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+        UniquePtr<EmptyKeymasterResponse> deserialized(round_trip(ver, msg, 4));
+    }
+}
+
+TEST(RoundTrip, SupportedByAlgorithmRequest) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        SupportedByAlgorithmRequest req(ver);
+        req.algorithm = KM_ALGORITHM_EC;
+
+        UniquePtr<SupportedByAlgorithmRequest> deserialized(round_trip(ver, req, 4));
+        EXPECT_EQ(KM_ALGORITHM_EC, deserialized->algorithm);
+    }
+}
+
+TEST(RoundTrip, SupportedByAlgorithmAndPurposeRequest) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        SupportedByAlgorithmAndPurposeRequest req(ver);
+        req.algorithm = KM_ALGORITHM_EC;
+        req.purpose = KM_PURPOSE_DECRYPT;
+
+        UniquePtr<SupportedByAlgorithmAndPurposeRequest> deserialized(round_trip(ver, req, 8));
+        EXPECT_EQ(KM_ALGORITHM_EC, deserialized->algorithm);
+        EXPECT_EQ(KM_PURPOSE_DECRYPT, deserialized->purpose);
+    }
+}
+
+TEST(RoundTrip, SupportedResponse) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        SupportedResponse<keymaster_digest_t> rsp(ver);
+        keymaster_digest_t digests[] = {KM_DIGEST_NONE, KM_DIGEST_MD5, KM_DIGEST_SHA1};
+        rsp.error = KM_ERROR_OK;
+        rsp.SetResults(digests);
+
+        UniquePtr<SupportedResponse<keymaster_digest_t>> deserialized(round_trip(ver, rsp, 20));
+        EXPECT_EQ(array_length(digests), deserialized->results_length);
+        EXPECT_EQ(0, memcmp(deserialized->results, digests, array_size(digests)));
+    }
+}
+
+static keymaster_key_param_t params[] = {
+    Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+    Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+    Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
+    Authorization(TAG_USER_ID, 7),
+    Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD),
+    Authorization(TAG_APPLICATION_ID, "app_id", 6),
+    Authorization(TAG_AUTH_TIMEOUT, 300),
+};
+uint8_t TEST_DATA[] = "a key blob";
+
+TEST(RoundTrip, GenerateKeyRequest) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        GenerateKeyRequest req(ver);
+        req.key_description.Reinitialize(params, array_length(params));
+        UniquePtr<GenerateKeyRequest> deserialized(round_trip(ver, req, 78));
+        EXPECT_EQ(deserialized->key_description, req.key_description);
+    }
+}
+
+TEST(RoundTrip, GenerateKeyResponse) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        GenerateKeyResponse rsp(ver);
+        rsp.error = KM_ERROR_OK;
+        rsp.key_blob.key_material = dup_array(TEST_DATA);
+        rsp.key_blob.key_material_size = array_length(TEST_DATA);
+        rsp.enforced.Reinitialize(params, array_length(params));
+
+        UniquePtr<GenerateKeyResponse> deserialized(round_trip(ver, rsp, 109));
+        EXPECT_EQ(KM_ERROR_OK, deserialized->error);
+        EXPECT_EQ(deserialized->enforced, rsp.enforced);
+        EXPECT_EQ(deserialized->unenforced, rsp.unenforced);
+    }
+}
+
+TEST(RoundTrip, GenerateKeyResponseTestError) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        GenerateKeyResponse rsp(ver);
+        rsp.error = KM_ERROR_UNSUPPORTED_ALGORITHM;
+        rsp.key_blob.key_material = dup_array(TEST_DATA);
+        rsp.key_blob.key_material_size = array_length(TEST_DATA);
+        rsp.enforced.Reinitialize(params, array_length(params));
+
+        UniquePtr<GenerateKeyResponse> deserialized(round_trip(ver, rsp, 4));
+        EXPECT_EQ(KM_ERROR_UNSUPPORTED_ALGORITHM, deserialized->error);
+        EXPECT_EQ(0U, deserialized->enforced.size());
+        EXPECT_EQ(0U, deserialized->unenforced.size());
+        EXPECT_EQ(0U, deserialized->key_blob.key_material_size);
+    }
+}
+
+TEST(RoundTrip, GetKeyCharacteristicsRequest) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        GetKeyCharacteristicsRequest req(ver);
+        req.additional_params.Reinitialize(params, array_length(params));
+        req.SetKeyMaterial("foo", 3);
+
+        UniquePtr<GetKeyCharacteristicsRequest> deserialized(round_trip(ver, req, 85));
+        EXPECT_EQ(7U, deserialized->additional_params.size());
+        EXPECT_EQ(3U, deserialized->key_blob.key_material_size);
+        EXPECT_EQ(0, memcmp(deserialized->key_blob.key_material, "foo", 3));
+    }
+}
+
+TEST(RoundTrip, GetKeyCharacteristicsResponse) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        GetKeyCharacteristicsResponse msg(ver);
+        msg.error = KM_ERROR_OK;
+        msg.enforced.Reinitialize(params, array_length(params));
+        msg.unenforced.Reinitialize(params, array_length(params));
+
+        UniquePtr<GetKeyCharacteristicsResponse> deserialized(round_trip(ver, msg, 160));
+        EXPECT_EQ(msg.enforced, deserialized->enforced);
+        EXPECT_EQ(msg.unenforced, deserialized->unenforced);
+    }
+}
+
+TEST(RoundTrip, BeginOperationRequest) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        BeginOperationRequest msg(ver);
+        msg.purpose = KM_PURPOSE_SIGN;
+        msg.SetKeyMaterial("foo", 3);
+        msg.additional_params.Reinitialize(params, array_length(params));
+
+        UniquePtr<BeginOperationRequest> deserialized(round_trip(ver, msg, 89));
+        EXPECT_EQ(KM_PURPOSE_SIGN, deserialized->purpose);
+        EXPECT_EQ(3U, deserialized->key_blob.key_material_size);
+        EXPECT_EQ(0, memcmp(deserialized->key_blob.key_material, "foo", 3));
+        EXPECT_EQ(msg.additional_params, deserialized->additional_params);
+    }
+}
+
+TEST(RoundTrip, BeginOperationResponse) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        BeginOperationResponse msg(ver);
+        msg.error = KM_ERROR_OK;
+        msg.op_handle = 0xDEADBEEF;
+        msg.output_params.push_back(Authorization(TAG_NONCE, "foo", 3));
+
+        UniquePtr<BeginOperationResponse> deserialized;
+        switch (ver) {
+        case 0:
+            deserialized.reset(round_trip(ver, msg, 12));
+            break;
+        case 1:
+        case 2:
+        case 3:
+            deserialized.reset(round_trip(ver, msg, 39));
+            break;
+        default:
+            FAIL();
+        }
+
+        EXPECT_EQ(KM_ERROR_OK, deserialized->error);
+        EXPECT_EQ(0xDEADBEEF, deserialized->op_handle);
+
+        switch (ver) {
+        case 0:
+            EXPECT_EQ(0U, deserialized->output_params.size());
+            break;
+        case 1:
+        case 2:
+        case 3:
+            EXPECT_EQ(msg.output_params, deserialized->output_params);
+            break;
+        default:
+            FAIL();
+        }
+    }
+}
+
+TEST(RoundTrip, BeginOperationResponseError) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        BeginOperationResponse msg(ver);
+        msg.error = KM_ERROR_INVALID_OPERATION_HANDLE;
+        msg.op_handle = 0xDEADBEEF;
+
+        UniquePtr<BeginOperationResponse> deserialized(round_trip(ver, msg, 4));
+        EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, deserialized->error);
+    }
+}
+
+TEST(RoundTrip, UpdateOperationRequest) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        UpdateOperationRequest msg(ver);
+        msg.op_handle = 0xDEADBEEF;
+        msg.input.Reinitialize("foo", 3);
+
+        UniquePtr<UpdateOperationRequest> deserialized;
+        switch (ver) {
+        case 0:
+            deserialized.reset(round_trip(ver, msg, 15));
+            break;
+        case 1:
+        case 2:
+        case 3:
+            deserialized.reset(round_trip(ver, msg, 27));
+            break;
+        default:
+            FAIL();
+        }
+        EXPECT_EQ(3U, deserialized->input.available_read());
+        EXPECT_EQ(0, memcmp(deserialized->input.peek_read(), "foo", 3));
+    }
+}
+
+TEST(RoundTrip, UpdateOperationResponse) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        UpdateOperationResponse msg(ver);
+        msg.error = KM_ERROR_OK;
+        msg.output.Reinitialize("foo", 3);
+        msg.input_consumed = 99;
+        msg.output_params.push_back(TAG_APPLICATION_ID, "bar", 3);
+
+        UniquePtr<UpdateOperationResponse> deserialized;
+        switch (ver) {
+        case 0:
+            deserialized.reset(round_trip(ver, msg, 11));
+            break;
+        case 1:
+            deserialized.reset(round_trip(ver, msg, 15));
+            break;
+        case 2:
+        case 3:
+            deserialized.reset(round_trip(ver, msg, 42));
+            break;
+        default:
+            FAIL();
+        }
+        EXPECT_EQ(KM_ERROR_OK, deserialized->error);
+        EXPECT_EQ(3U, deserialized->output.available_read());
+        EXPECT_EQ(0, memcmp(deserialized->output.peek_read(), "foo", 3));
+
+        switch (ver) {
+        case 0:
+            EXPECT_EQ(0U, deserialized->input_consumed);
+            break;
+        case 1:
+            EXPECT_EQ(99U, deserialized->input_consumed);
+            break;
+        case 2:
+        case 3:
+            EXPECT_EQ(99U, deserialized->input_consumed);
+            EXPECT_EQ(1U, deserialized->output_params.size());
+            break;
+        default:
+            FAIL();
+        }
+    }
+}
+
+TEST(RoundTrip, FinishOperationRequest) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        FinishOperationRequest msg(ver);
+        msg.op_handle = 0xDEADBEEF;
+        msg.signature.Reinitialize("bar", 3);
+        msg.input.Reinitialize("baz", 3);
+
+        UniquePtr<FinishOperationRequest> deserialized;
+        switch (ver) {
+        case 0:
+            deserialized.reset(round_trip(ver, msg, 15));
+            break;
+        case 1:
+        case 2:
+            deserialized.reset(round_trip(ver, msg, 27));
+            break;
+        case 3:
+            deserialized.reset(round_trip(ver, msg, 34));
+            break;
+        default:
+            FAIL();
+        }
+        EXPECT_EQ(0xDEADBEEF, deserialized->op_handle);
+        EXPECT_EQ(3U, deserialized->signature.available_read());
+        EXPECT_EQ(0, memcmp(deserialized->signature.peek_read(), "bar", 3));
+    }
+}
+
+TEST(Round_Trip, FinishOperationResponse) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        FinishOperationResponse msg(ver);
+        msg.error = KM_ERROR_OK;
+        msg.output.Reinitialize("foo", 3);
+
+        UniquePtr<FinishOperationResponse> deserialized;
+        switch (ver) {
+        case 0:
+        case 1:
+            deserialized.reset(round_trip(ver, msg, 11));
+            break;
+        case 2:
+        case 3:
+            deserialized.reset(round_trip(ver, msg, 23));
+            break;
+        default:
+            FAIL();
+        }
+        EXPECT_EQ(msg.error, deserialized->error);
+        EXPECT_EQ(msg.output.available_read(), deserialized->output.available_read());
+        EXPECT_EQ(0, memcmp(msg.output.peek_read(), deserialized->output.peek_read(),
+                            msg.output.available_read()));
+    }
+}
+
+TEST(RoundTrip, ImportKeyRequest) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        ImportKeyRequest msg(ver);
+        msg.key_description.Reinitialize(params, array_length(params));
+        msg.key_format = KM_KEY_FORMAT_X509;
+        msg.SetKeyMaterial("foo", 3);
+
+        UniquePtr<ImportKeyRequest> deserialized(round_trip(ver, msg, 89));
+        EXPECT_EQ(msg.key_description, deserialized->key_description);
+        EXPECT_EQ(msg.key_format, deserialized->key_format);
+        EXPECT_EQ(msg.key_data_length, deserialized->key_data_length);
+        EXPECT_EQ(0, memcmp(msg.key_data, deserialized->key_data, msg.key_data_length));
+    }
+}
+
+TEST(RoundTrip, ImportKeyResponse) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        ImportKeyResponse msg(ver);
+        msg.error = KM_ERROR_OK;
+        msg.SetKeyMaterial("foo", 3);
+        msg.enforced.Reinitialize(params, array_length(params));
+        msg.unenforced.Reinitialize(params, array_length(params));
+
+        UniquePtr<ImportKeyResponse> deserialized(round_trip(ver, msg, 167));
+        EXPECT_EQ(msg.error, deserialized->error);
+        EXPECT_EQ(msg.key_blob.key_material_size, deserialized->key_blob.key_material_size);
+        EXPECT_EQ(0, memcmp(msg.key_blob.key_material, deserialized->key_blob.key_material,
+                            msg.key_blob.key_material_size));
+        EXPECT_EQ(msg.enforced, deserialized->enforced);
+        EXPECT_EQ(msg.unenforced, deserialized->unenforced);
+    }
+}
+
+TEST(RoundTrip, ExportKeyRequest) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        ExportKeyRequest msg(ver);
+        msg.additional_params.Reinitialize(params, array_length(params));
+        msg.key_format = KM_KEY_FORMAT_X509;
+        msg.SetKeyMaterial("foo", 3);
+
+        UniquePtr<ExportKeyRequest> deserialized(round_trip(ver, msg, 89));
+        EXPECT_EQ(msg.additional_params, deserialized->additional_params);
+        EXPECT_EQ(msg.key_format, deserialized->key_format);
+        EXPECT_EQ(3U, deserialized->key_blob.key_material_size);
+        EXPECT_EQ(0, memcmp("foo", deserialized->key_blob.key_material, 3));
+    }
+}
+
+TEST(RoundTrip, ExportKeyResponse) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        ExportKeyResponse msg(ver);
+        msg.error = KM_ERROR_OK;
+        msg.SetKeyMaterial("foo", 3);
+
+        UniquePtr<ExportKeyResponse> deserialized(round_trip(ver, msg, 11));
+        EXPECT_EQ(3U, deserialized->key_data_length);
+        EXPECT_EQ(0, memcmp("foo", deserialized->key_data, 3));
+    }
+}
+
+TEST(RoundTrip, DeleteKeyRequest) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        DeleteKeyRequest msg(ver);
+        msg.SetKeyMaterial("foo", 3);
+
+        UniquePtr<DeleteKeyRequest> deserialized(round_trip(ver, msg, 7));
+        EXPECT_EQ(3U, deserialized->key_blob.key_material_size);
+        EXPECT_EQ(0, memcmp("foo", deserialized->key_blob.key_material, 3));
+    }
+}
+
+TEST(RoundTrip, DeleteKeyResponse) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        DeleteKeyResponse msg(ver);
+        UniquePtr<DeleteKeyResponse> deserialized(round_trip(ver, msg, 4));
+    }
+}
+
+TEST(RoundTrip, DeleteAllKeysRequest) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        DeleteAllKeysRequest msg(ver);
+        UniquePtr<DeleteAllKeysRequest> deserialized(round_trip(ver, msg, 0));
+    }
+}
+
+TEST(RoundTrip, DeleteAllKeysResponse) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        DeleteAllKeysResponse msg(ver);
+        UniquePtr<DeleteAllKeysResponse> deserialized(round_trip(ver, msg, 4));
+    }
+}
+
+TEST(RoundTrip, GetVersionRequest) {
+    GetVersionRequest msg;
+
+    size_t size = msg.SerializedSize();
+    ASSERT_EQ(0U, size);
+
+    UniquePtr<uint8_t[]> buf(new uint8_t[size]);
+    EXPECT_EQ(buf.get() + size, msg.Serialize(buf.get(), buf.get() + size));
+
+    GetVersionRequest deserialized;
+    const uint8_t* p = buf.get();
+    EXPECT_TRUE(deserialized.Deserialize(&p, p + size));
+    EXPECT_EQ((ptrdiff_t)size, p - buf.get());
+}
+
+TEST(RoundTrip, GetVersionResponse) {
+    GetVersionResponse msg;
+    msg.error = KM_ERROR_OK;
+    msg.major_ver = 9;
+    msg.minor_ver = 98;
+    msg.subminor_ver = 38;
+
+    size_t size = msg.SerializedSize();
+    ASSERT_EQ(7U, size);
+
+    UniquePtr<uint8_t[]> buf(new uint8_t[size]);
+    EXPECT_EQ(buf.get() + size, msg.Serialize(buf.get(), buf.get() + size));
+
+    GetVersionResponse deserialized;
+    const uint8_t* p = buf.get();
+    EXPECT_TRUE(deserialized.Deserialize(&p, p + size));
+    EXPECT_EQ((ptrdiff_t)size, p - buf.get());
+    EXPECT_EQ(9U, msg.major_ver);
+    EXPECT_EQ(98U, msg.minor_ver);
+    EXPECT_EQ(38U, msg.subminor_ver);
+}
+
+TEST(RoundTrip, AddEntropyRequest) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        AddEntropyRequest msg(ver);
+        msg.random_data.Reinitialize("foo", 3);
+
+        UniquePtr<AddEntropyRequest> deserialized(round_trip(ver, msg, 7));
+        EXPECT_EQ(3U, deserialized->random_data.available_read());
+        EXPECT_EQ(0, memcmp("foo", deserialized->random_data.peek_read(), 3));
+    }
+}
+
+TEST(RoundTrip, AddEntropyResponse) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        AddEntropyResponse msg(ver);
+        UniquePtr<AddEntropyResponse> deserialized(round_trip(ver, msg, 4));
+    }
+}
+
+TEST(RoundTrip, AbortOperationRequest) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        AbortOperationRequest msg(ver);
+        UniquePtr<AbortOperationRequest> deserialized(round_trip(ver, msg, 8));
+    }
+}
+
+TEST(RoundTrip, AbortOperationResponse) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        AbortOperationResponse msg(ver);
+        UniquePtr<AbortOperationResponse> deserialized(round_trip(ver, msg, 4));
+    }
+}
+
+TEST(RoundTrip, AttestKeyRequest) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        AttestKeyRequest msg(ver);
+        msg.SetKeyMaterial("foo", 3);
+        msg.attest_params.Reinitialize(params, array_length(params));
+
+        UniquePtr<AttestKeyRequest> deserialized(round_trip(ver, msg, 85));
+        EXPECT_EQ(3U, deserialized->key_blob.key_material_size);
+        EXPECT_EQ(0, memcmp("foo", deserialized->key_blob.key_material, 3));
+        EXPECT_EQ(msg.attest_params, deserialized->attest_params);
+    }
+}
+
+TEST(RoundTrip, AttestKeyResponse) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        AttestKeyResponse msg(ver);
+        msg.error = KM_ERROR_OK;
+        EXPECT_TRUE(msg.AllocateChain(3));
+        msg.certificate_chain.entries[0] = {dup_buffer("foo", 3), 3};
+        msg.certificate_chain.entries[1] = {dup_buffer("bar", 3), 3};
+        msg.certificate_chain.entries[2] = {dup_buffer("baz", 3), 3};
+
+        UniquePtr<AttestKeyResponse> deserialized(round_trip(ver, msg, 29));
+        keymaster_cert_chain_t* chain = &deserialized->certificate_chain;
+
+        EXPECT_NE(nullptr, chain->entries);
+        EXPECT_EQ(3U, chain->entry_count);
+        EXPECT_EQ(3U, chain->entries[0].data_length);
+        EXPECT_EQ(0, memcmp("foo", chain->entries[0].data, 3));
+        EXPECT_EQ(3U, chain->entries[1].data_length);
+        EXPECT_EQ(0, memcmp("bar", chain->entries[1].data, 3));
+        EXPECT_EQ(3U, chain->entries[2].data_length);
+        EXPECT_EQ(0, memcmp("baz", chain->entries[2].data, 3));
+    }
+}
+
+uint8_t msgbuf[] = {
+    220, 88,  183, 255, 71,  1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   173, 0,   0,   0,   228, 174, 98,  187, 191, 135, 253, 200, 51,  230, 114, 247, 151, 109,
+    237, 79,  87,  32,  94,  5,   204, 46,  154, 30,  91,  6,   103, 148, 254, 129, 65,  171, 228,
+    167, 224, 163, 9,   15,  206, 90,  58,  11,  205, 55,  211, 33,  87,  178, 149, 91,  28,  236,
+    218, 112, 231, 34,  82,  82,  134, 103, 137, 115, 27,  156, 102, 159, 220, 226, 89,  42,  25,
+    37,  9,   84,  239, 76,  161, 198, 72,  167, 163, 39,  91,  148, 191, 17,  191, 87,  169, 179,
+    136, 10,  194, 154, 4,   40,  107, 109, 61,  161, 20,  176, 247, 13,  214, 106, 229, 45,  17,
+    5,   60,  189, 64,  39,  166, 208, 14,  57,  25,  140, 148, 25,  177, 246, 189, 43,  181, 88,
+    204, 29,  126, 224, 100, 143, 93,  60,  57,  249, 55,  0,   87,  83,  227, 224, 166, 59,  214,
+    81,  144, 129, 58,  6,   57,  46,  254, 232, 41,  220, 209, 230, 167, 138, 158, 94,  180, 125,
+    247, 26,  162, 116, 238, 202, 187, 100, 65,  13,  180, 44,  245, 159, 83,  161, 176, 58,  72,
+    236, 109, 105, 160, 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   11,  0,   0,   0,   98,  0,   0,   0,   1,   0,   0,   32,  2,   0,   0,   0,   1,   0,
+    0,   32,  3,   0,   0,   0,   2,   0,   0,   16,  1,   0,   0,   0,   3,   0,   0,   48,  0,
+    1,   0,   0,   200, 0,   0,   80,  3,   0,   0,   0,   0,   0,   0,   0,   244, 1,   0,   112,
+    1,   246, 1,   0,   112, 1,   189, 2,   0,   96,  144, 178, 236, 250, 255, 255, 255, 255, 145,
+    1,   0,   96,  144, 226, 33,  60,  222, 2,   0,   0,   189, 2,   0,   96,  0,   0,   0,   0,
+    0,   0,   0,   0,   190, 2,   0,   16,  1,   0,   0,   0,   12,  0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   110, 0,   0,   0,   0,   0,   0,   0,   11,  0,
+    0,   0,   98,  0,   0,   0,   1,   0,   0,   32,  2,   0,   0,   0,   1,   0,   0,   32,  3,
+    0,   0,   0,   2,   0,   0,   16,  1,   0,   0,   0,   3,   0,   0,   48,  0,   1,   0,   0,
+    200, 0,   0,   80,  3,   0,   0,   0,   0,   0,   0,   0,   244, 1,   0,   112, 1,   246, 1,
+    0,   112, 1,   189, 2,   0,   96,  144, 178, 236, 250, 255, 255, 255, 255, 145, 1,   0,   96,
+    144, 226, 33,  60,  222, 2,   0,   0,   189, 2,   0,   96,  0,   0,   0,   0,   0,   0,   0,
+    0,   190, 2,   0,   16,  1,   0,   0,   0,
+};
+
+/*
+ * These tests don't have any assertions or expectations. They just try to parse garbage, to see if
+ * the result will be a crash.  This is especially informative when run under Valgrind memcheck.
+ */
+
+template <typename Message> void parse_garbage() {
+    for (int32_t ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        Message msg(ver);
+        const uint8_t* end = msgbuf + array_length(msgbuf);
+        for (size_t i = 0; i < array_length(msgbuf); ++i) {
+            const uint8_t* begin = msgbuf + i;
+            const uint8_t* p = begin;
+            msg.Deserialize(&p, end);
+        }
+    }
+
+    time_t now = time(NULL);
+    std::cout << "Seeding rand() with " << now << " for fuzz test." << std::endl;
+    srand(now);
+
+    // Fill large buffer with random bytes.
+    const int kBufSize = 10000;
+    UniquePtr<uint8_t[]> buf(new uint8_t[kBufSize]);
+    for (size_t i = 0; i < kBufSize; ++i)
+        buf[i] = static_cast<uint8_t>(rand());
+
+    for (uint32_t ver = 0; ver < MAX_MESSAGE_VERSION; ++ver) {
+        Message msg(ver);
+        const uint8_t* end = buf.get() + kBufSize;
+        for (size_t i = 0; i < kBufSize; ++i) {
+            const uint8_t* begin = buf.get() + i;
+            const uint8_t* p = begin;
+            msg.Deserialize(&p, end);
+        }
+    }
+}
+
+#define GARBAGE_TEST(Message)                                                                      \
+    TEST(GarbageTest, Message) { parse_garbage<Message>(); }
+
+GARBAGE_TEST(AbortOperationRequest);
+GARBAGE_TEST(AbortOperationResponse);
+GARBAGE_TEST(AddEntropyRequest);
+GARBAGE_TEST(AddEntropyResponse);
+GARBAGE_TEST(BeginOperationRequest);
+GARBAGE_TEST(BeginOperationResponse);
+GARBAGE_TEST(DeleteAllKeysRequest);
+GARBAGE_TEST(DeleteAllKeysResponse);
+GARBAGE_TEST(DeleteKeyRequest);
+GARBAGE_TEST(DeleteKeyResponse);
+GARBAGE_TEST(ExportKeyRequest);
+GARBAGE_TEST(ExportKeyResponse);
+GARBAGE_TEST(FinishOperationRequest);
+GARBAGE_TEST(FinishOperationResponse);
+GARBAGE_TEST(GenerateKeyRequest);
+GARBAGE_TEST(GenerateKeyResponse);
+GARBAGE_TEST(GetKeyCharacteristicsRequest);
+GARBAGE_TEST(GetKeyCharacteristicsResponse);
+GARBAGE_TEST(ImportKeyRequest);
+GARBAGE_TEST(ImportKeyResponse);
+GARBAGE_TEST(SupportedByAlgorithmAndPurposeRequest)
+GARBAGE_TEST(SupportedByAlgorithmRequest)
+GARBAGE_TEST(UpdateOperationRequest);
+GARBAGE_TEST(UpdateOperationResponse);
+GARBAGE_TEST(AttestKeyRequest);
+GARBAGE_TEST(AttestKeyResponse);
+
+// The macro doesn't work on this one.
+TEST(GarbageTest, SupportedResponse) {
+    parse_garbage<SupportedResponse<keymaster_digest_t>>();
+}
+
+}  // namespace test
+
+}  // namespace keymaster
diff --git a/keymaster/android_keymaster_test.cpp b/keymaster/android_keymaster_test.cpp
new file mode 100644
index 0000000..ddc9783
--- /dev/null
+++ b/keymaster/android_keymaster_test.cpp
@@ -0,0 +1,3599 @@
+/*
+ * Copyright (C) 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 <fstream>
+#include <string>
+#include <vector>
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include <hardware/keymaster0.h>
+#include <keymaster/key_factory.h>
+#include <keymaster/soft_keymaster_context.h>
+#include <keymaster/soft_keymaster_device.h>
+#include <keymaster/softkeymaster.h>
+
+#include "android_keymaster_test_utils.h"
+#include "attestation_record.h"
+#include "keymaster0_engine.h"
+#include "openssl_utils.h"
+
+using std::ifstream;
+using std::istreambuf_iterator;
+using std::ofstream;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+extern "C" {
+int __android_log_print(int prio, const char* tag, const char* fmt);
+int __android_log_print(int prio, const char* tag, const char* fmt) {
+    (void)prio, (void)tag, (void)fmt;
+    return 0;
+}
+}  // extern "C"
+
+namespace keymaster {
+namespace test {
+
+StdoutLogger logger;
+
+template <typename T> vector<T> make_vector(const T* array, size_t len) {
+    return vector<T>(array, array + len);
+}
+
+/**
+ * KeymasterEnforcement class for use in testing.  It's permissive in the sense that it doesn't
+ * check cryptoperiods, but restrictive in the sense that the clock never advances (so rate-limited
+ * keys will only work once).
+ */
+class TestKeymasterEnforcement : public KeymasterEnforcement {
+  public:
+    TestKeymasterEnforcement() : KeymasterEnforcement(3, 3) {}
+
+    virtual bool activation_date_valid(uint64_t /* activation_date */) const { return true; }
+    virtual bool expiration_date_passed(uint64_t /* expiration_date */) const { return false; }
+    virtual bool auth_token_timed_out(const hw_auth_token_t& /* token */,
+                                      uint32_t /* timeout */) const {
+        return false;
+    }
+    virtual uint32_t get_current_time() const { return 0; }
+    virtual bool ValidateTokenSignature(const hw_auth_token_t& /* token */) const { return true; }
+};
+
+/**
+ * Variant of SoftKeymasterContext that provides a TestKeymasterEnforcement.
+ */
+class TestKeymasterContext : public SoftKeymasterContext {
+  public:
+    TestKeymasterContext() {}
+    explicit TestKeymasterContext(const string& root_of_trust) : SoftKeymasterContext(root_of_trust) {}
+
+    KeymasterEnforcement* enforcement_policy() override { return &test_policy_; }
+
+  private:
+    TestKeymasterEnforcement test_policy_;
+};
+
+/**
+ * Test instance creator that builds a pure software keymaster1 implementations.
+ */
+class SoftKeymasterTestInstanceCreator : public Keymaster2TestInstanceCreator {
+  public:
+    keymaster2_device_t* CreateDevice() const override {
+        std::cerr << "Creating software-only device" << std::endl;
+        SoftKeymasterDevice* device = new SoftKeymasterDevice(new TestKeymasterContext);
+        return device->keymaster2_device();
+    }
+
+    bool algorithm_in_km0_hardware(keymaster_algorithm_t) const override { return false; }
+    int keymaster0_calls() const override { return 0; }
+};
+
+/**
+ * Test instance creator that builds keymaster1 instances which wrap a faked hardware keymaster0
+ * instance, with or without EC support.
+ */
+class Keymaster0AdapterTestInstanceCreator : public Keymaster2TestInstanceCreator {
+  public:
+    explicit Keymaster0AdapterTestInstanceCreator(bool support_ec) : support_ec_(support_ec) {}
+
+    keymaster2_device_t* CreateDevice() const {
+        std::cerr << "Creating keymaster0-backed device (with ec: " << std::boolalpha << support_ec_
+                  << ")." << std::endl;
+        hw_device_t* softkeymaster_device;
+        EXPECT_EQ(0, openssl_open(&softkeymaster_module.common, KEYSTORE_KEYMASTER,
+                                  &softkeymaster_device));
+        // Make the software device pretend to be hardware
+        keymaster0_device_t* keymaster0_device =
+            reinterpret_cast<keymaster0_device_t*>(softkeymaster_device);
+        keymaster0_device->flags &= ~KEYMASTER_SOFTWARE_ONLY;
+
+        if (!support_ec_) {
+            // Make the software device pretend not to support EC
+            keymaster0_device->flags &= ~KEYMASTER_SUPPORTS_EC;
+        }
+
+        counting_keymaster0_device_ = new Keymaster0CountingWrapper(keymaster0_device);
+
+        SoftKeymasterDevice* keymaster = new SoftKeymasterDevice(new TestKeymasterContext);
+        keymaster->SetHardwareDevice(counting_keymaster0_device_);
+        return keymaster->keymaster2_device();
+    }
+
+    bool algorithm_in_km0_hardware(keymaster_algorithm_t algorithm) const override {
+        switch (algorithm) {
+        case KM_ALGORITHM_RSA:
+            return true;
+        case KM_ALGORITHM_EC:
+            return support_ec_;
+        default:
+            return false;
+        }
+    }
+    int keymaster0_calls() const override { return counting_keymaster0_device_->count(); }
+
+  private:
+    mutable Keymaster0CountingWrapper* counting_keymaster0_device_;
+    bool support_ec_;
+};
+
+/**
+ * Test instance creator that builds a SoftKeymasterDevice which wraps a fake hardware keymaster1
+ * instance, with minimal digest support.
+ */
+class Sha256OnlyKeymaster1TestInstanceCreator : public Keymaster2TestInstanceCreator {
+    keymaster2_device_t* CreateDevice() const {
+        std::cerr << "Creating keymaster1-backed device that supports only SHA256";
+
+        // fake_device doesn't leak because device (below) takes ownership of it.
+        keymaster1_device_t* fake_device = make_device_sha256_only(
+            (new SoftKeymasterDevice(new TestKeymasterContext("PseudoHW")))->keymaster_device());
+
+        // device doesn't leak; it's cleaned up by device->keymaster_device()->common.close().
+        SoftKeymasterDevice* device = new SoftKeymasterDevice(new TestKeymasterContext);
+        device->SetHardwareDevice(fake_device);
+
+        return device->keymaster2_device();
+    }
+
+    bool algorithm_in_km0_hardware(keymaster_algorithm_t) const override { return false; }
+    int keymaster0_calls() const override { return 0; }
+    int minimal_digest_set() const override { return true; }
+};
+
+static auto test_params = testing::Values(
+    InstanceCreatorPtr(new SoftKeymasterTestInstanceCreator),
+    InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(true /* support_ec */)),
+    InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(false /* support_ec */)),
+    InstanceCreatorPtr(new Sha256OnlyKeymaster1TestInstanceCreator));
+
+class NewKeyGeneration : public Keymaster2Test {
+  protected:
+    void CheckBaseParams() {
+        AuthorizationSet auths = sw_enforced();
+        EXPECT_GT(auths.SerializedSize(), 12U);
+
+        EXPECT_TRUE(contains(auths, TAG_PURPOSE, KM_PURPOSE_SIGN));
+        EXPECT_TRUE(contains(auths, TAG_PURPOSE, KM_PURPOSE_VERIFY));
+        EXPECT_TRUE(contains(auths, TAG_USER_ID, 7));
+        EXPECT_TRUE(contains(auths, TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
+        EXPECT_TRUE(contains(auths, TAG_AUTH_TIMEOUT, 300));
+
+        // Verify that App ID, App data and ROT are NOT included.
+        EXPECT_FALSE(contains(auths, TAG_ROOT_OF_TRUST));
+        EXPECT_FALSE(contains(auths, TAG_APPLICATION_ID));
+        EXPECT_FALSE(contains(auths, TAG_APPLICATION_DATA));
+
+        // Just for giggles, check that some unexpected tags/values are NOT present.
+        EXPECT_FALSE(contains(auths, TAG_PURPOSE, KM_PURPOSE_ENCRYPT));
+        EXPECT_FALSE(contains(auths, TAG_PURPOSE, KM_PURPOSE_DECRYPT));
+        EXPECT_FALSE(contains(auths, TAG_AUTH_TIMEOUT, 301));
+
+        // Now check that unspecified, defaulted tags are correct.
+        EXPECT_TRUE(contains(auths, KM_TAG_CREATION_DATETIME));
+    }
+};
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, NewKeyGeneration, test_params);
+
+TEST_P(NewKeyGeneration, Rsa) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(256, 3)
+                                           .Digest(KM_DIGEST_NONE)
+                                           .Padding(KM_PAD_NONE)));
+    CheckBaseParams();
+
+    // Check specified tags are all present, and in the right set.
+    AuthorizationSet crypto_params;
+    AuthorizationSet non_crypto_params;
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) {
+        EXPECT_NE(0U, hw_enforced().size());
+        EXPECT_NE(0U, sw_enforced().size());
+        crypto_params.push_back(hw_enforced());
+        non_crypto_params.push_back(sw_enforced());
+    } else {
+        EXPECT_EQ(0U, hw_enforced().size());
+        EXPECT_NE(0U, sw_enforced().size());
+        crypto_params.push_back(sw_enforced());
+    }
+
+    EXPECT_TRUE(contains(crypto_params, TAG_ALGORITHM, KM_ALGORITHM_RSA));
+    EXPECT_FALSE(contains(non_crypto_params, TAG_ALGORITHM, KM_ALGORITHM_RSA));
+    EXPECT_TRUE(contains(crypto_params, TAG_KEY_SIZE, 256));
+    EXPECT_FALSE(contains(non_crypto_params, TAG_KEY_SIZE, 256));
+    EXPECT_TRUE(contains(crypto_params, TAG_RSA_PUBLIC_EXPONENT, 3));
+    EXPECT_FALSE(contains(non_crypto_params, TAG_RSA_PUBLIC_EXPONENT, 3));
+
+    EXPECT_EQ(KM_ERROR_OK, DeleteKey());
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(NewKeyGeneration, RsaDefaultSize) {
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE,
+              GenerateKey(AuthorizationSetBuilder()
+                              .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                              .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3)
+                              .SigningKey()));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(NewKeyGeneration, Ecdsa) {
+    ASSERT_EQ(KM_ERROR_OK,
+              GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE)));
+    CheckBaseParams();
+
+    // Check specified tags are all present, and in the right set.
+    AuthorizationSet crypto_params;
+    AuthorizationSet non_crypto_params;
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) {
+        EXPECT_NE(0U, hw_enforced().size());
+        EXPECT_NE(0U, sw_enforced().size());
+        crypto_params.push_back(hw_enforced());
+        non_crypto_params.push_back(sw_enforced());
+    } else {
+        EXPECT_EQ(0U, hw_enforced().size());
+        EXPECT_NE(0U, sw_enforced().size());
+        crypto_params.push_back(sw_enforced());
+    }
+
+    EXPECT_TRUE(contains(crypto_params, TAG_ALGORITHM, KM_ALGORITHM_EC));
+    EXPECT_FALSE(contains(non_crypto_params, TAG_ALGORITHM, KM_ALGORITHM_EC));
+    EXPECT_TRUE(contains(crypto_params, TAG_KEY_SIZE, 224));
+    EXPECT_FALSE(contains(non_crypto_params, TAG_KEY_SIZE, 224));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_EQ(1, GetParam()->keymaster0_calls());
+}
+
+TEST_P(NewKeyGeneration, EcdsaDefaultSize) {
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE,
+              GenerateKey(AuthorizationSetBuilder()
+                              .Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC)
+                              .SigningKey()
+                              .Digest(KM_DIGEST_NONE)));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(NewKeyGeneration, EcdsaInvalidSize) {
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        ASSERT_EQ(
+            KM_ERROR_UNKNOWN_ERROR,
+            GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(190).Digest(KM_DIGEST_NONE)));
+    else
+        ASSERT_EQ(
+            KM_ERROR_UNSUPPORTED_KEY_SIZE,
+            GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(190).Digest(KM_DIGEST_NONE)));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_EQ(1, GetParam()->keymaster0_calls());
+}
+
+TEST_P(NewKeyGeneration, EcdsaAllValidSizes) {
+    size_t valid_sizes[] = {224, 256, 384, 521};
+    for (size_t size : valid_sizes) {
+        EXPECT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(size).Digest(
+                                   KM_DIGEST_NONE)))
+            << "Failed to generate size: " << size;
+    }
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(NewKeyGeneration, HmacSha256) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .HmacKey(128)
+                                           .Digest(KM_DIGEST_SHA_2_256)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 256)));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(NewKeyGeneration, HmacMultipleDigests) {
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST,
+              GenerateKey(AuthorizationSetBuilder()
+                              .HmacKey(128)
+                              .Digest(KM_DIGEST_SHA1)
+                              .Digest(KM_DIGEST_SHA_2_256)
+                              .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(NewKeyGeneration, HmacDigestNone) {
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST,
+              GenerateKey(AuthorizationSetBuilder()
+                              .HmacKey(128)
+                              .Digest(KM_DIGEST_NONE)
+                              .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(NewKeyGeneration, HmacSha256TooShortMacLength) {
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH,
+              GenerateKey(AuthorizationSetBuilder()
+                              .HmacKey(128)
+                              .Digest(KM_DIGEST_SHA_2_256)
+                              .Authorization(TAG_MIN_MAC_LENGTH, 48)));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(NewKeyGeneration, HmacSha256NonIntegralOctetMacLength) {
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH,
+              GenerateKey(AuthorizationSetBuilder()
+                              .HmacKey(128)
+                              .Digest(KM_DIGEST_SHA_2_256)
+                              .Authorization(TAG_MIN_MAC_LENGTH, 130)));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(NewKeyGeneration, HmacSha256TooLongMacLength) {
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH,
+              GenerateKey(AuthorizationSetBuilder()
+                              .HmacKey(128)
+                              .Digest(KM_DIGEST_SHA_2_256)
+                              .Authorization(TAG_MIN_MAC_LENGTH, 384)));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+typedef Keymaster2Test GetKeyCharacteristics;
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, GetKeyCharacteristics, test_params);
+
+TEST_P(GetKeyCharacteristics, SimpleRsa) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(256, 3)
+                                           .Digest(KM_DIGEST_NONE)
+                                           .Padding(KM_PAD_NONE)));
+    AuthorizationSet original(sw_enforced());
+
+    ASSERT_EQ(KM_ERROR_OK, GetCharacteristics());
+    EXPECT_EQ(original, sw_enforced());
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(1, GetParam()->keymaster0_calls());
+}
+
+typedef Keymaster2Test SigningOperationsTest;
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, SigningOperationsTest, test_params);
+
+TEST_P(SigningOperationsTest, RsaSuccess) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(256, 3)
+                                           .Digest(KM_DIGEST_NONE)
+                                           .Padding(KM_PAD_NONE)));
+    string message = "12345678901234567890123456789012";
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(3, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, RsaPssSha256Success) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(512, 3)
+                                           .Digest(KM_DIGEST_SHA_2_256)
+                                           .Padding(KM_PAD_RSA_PSS)));
+    // Use large message, which won't work without digesting.
+    string message(1024, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(3, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(512, 3)
+                                           .Digest(KM_DIGEST_NONE)
+                                           .Padding(KM_PAD_NONE)));
+    string message = "12345678901234567890123456789012";
+    string signature;
+
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
+    begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN);
+    EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PADDING_MODE, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, RsaPkcs1Sha256Success) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(512, 3)
+                                           .Digest(KM_DIGEST_SHA_2_256)
+                                           .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)));
+    string message(1024, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(3, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, RsaPkcs1NoDigestSuccess) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(512, 3)
+                                           .Digest(KM_DIGEST_NONE)
+                                           .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)));
+    string message(53, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_RSA_PKCS1_1_5_SIGN);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(3, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, RsaPkcs1NoDigestTooLarge) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(512, 3)
+                                           .Digest(KM_DIGEST_NONE)
+                                           .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)));
+    string message(54, 'a');
+
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
+    begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN);
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+    string signature;
+    EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(&signature));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, RsaPssSha256TooSmallKey) {
+    // Key must be at least 10 bytes larger than hash, to provide eight bytes of random salt, so
+    // verify that nine bytes larger than hash won't work.
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(256 + 9 * 8, 3)
+                                           .Digest(KM_DIGEST_SHA_2_256)
+                                           .Padding(KM_PAD_RSA_PSS)));
+    string message(1024, 'a');
+    string signature;
+
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+    begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PSS);
+    EXPECT_EQ(KM_ERROR_INCOMPATIBLE_DIGEST, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+}
+
+TEST_P(SigningOperationsTest, RsaNoPaddingHugeData) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(256, 3)
+                                           .Digest(KM_DIGEST_NONE)
+                                           .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)));
+    string message(64 * 1024, 'a');
+    string signature;
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
+    begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN);
+    ASSERT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, UpdateOperation(message, &result, &input_consumed));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, RsaAbort) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(256, 3)
+                                           .Digest(KM_DIGEST_NONE)
+                                           .Padding(KM_PAD_NONE)));
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    ASSERT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+    EXPECT_EQ(KM_ERROR_OK, AbortOperation());
+    // Another abort should fail
+    EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, AbortOperation());
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, RsaUnsupportedPadding) {
+    GenerateKey(AuthorizationSetBuilder()
+                    .RsaSigningKey(256, 3)
+                    .Digest(KM_DIGEST_SHA_2_256 /* supported digest */)
+                    .Padding(KM_PAD_PKCS7));
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, RsaNoDigest) {
+    // PSS requires a digest.
+    GenerateKey(AuthorizationSetBuilder()
+                    .RsaSigningKey(256, 3)
+                    .Digest(KM_DIGEST_NONE)
+                    .Padding(KM_PAD_RSA_PSS));
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
+    begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PSS);
+    ASSERT_EQ(KM_ERROR_INCOMPATIBLE_DIGEST, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, RsaNoPadding) {
+    // Padding must be specified
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaKey(256, 3).SigningKey().Digest(
+                               KM_DIGEST_NONE)));
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, RsaTooShortMessage) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(256, 3)
+                                           .Digest(KM_DIGEST_NONE)
+                                           .Padding(KM_PAD_NONE)));
+    string message = "1234567890123456789012345678901";
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(3, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, RsaSignWithEncryptionKey) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaEncryptionKey(256, 3)
+                                           .Digest(KM_DIGEST_NONE)
+                                           .Padding(KM_PAD_NONE)));
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
+    ASSERT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, RsaSignTooLargeMessage) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(256, 3)
+                                           .Digest(KM_DIGEST_NONE)
+                                           .Padding(KM_PAD_NONE)));
+    string message(256 / 8, static_cast<char>(0xff));
+    string signature;
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
+    ASSERT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+    string result;
+    size_t input_consumed;
+    ASSERT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+    ASSERT_EQ(message.size(), input_consumed);
+    string output;
+    ASSERT_EQ(KM_ERROR_INVALID_ARGUMENT, FinishOperation(&output));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(3, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, EcdsaSuccess) {
+    ASSERT_EQ(KM_ERROR_OK,
+              GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE)));
+    string message(224 / 8, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_NONE);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_EQ(3, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, EcdsaSha256Success) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(
+                               KM_DIGEST_SHA_2_256)));
+    string message(1024, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_SHA_2_256);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_EQ(3, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, EcdsaSha384Success) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(
+                               KM_DIGEST_SHA_2_384)));
+    string message(1024, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_SHA_2_384);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_EQ(3, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, EcdsaNoPaddingHugeData) {
+    ASSERT_EQ(KM_ERROR_OK,
+              GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE)));
+    string message(64 * 1024, 'a');
+    string signature;
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
+    ASSERT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, EcdsaAllSizesAndHashes) {
+    vector<int> key_sizes = {224, 256, 384, 521};
+    vector<keymaster_digest_t> digests = {
+        KM_DIGEST_SHA1,      KM_DIGEST_SHA_2_224, KM_DIGEST_SHA_2_256,
+        KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512,
+    };
+
+    for (int key_size : key_sizes) {
+        for (keymaster_digest_t digest : digests) {
+            ASSERT_EQ(
+                KM_ERROR_OK,
+                GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(key_size).Digest(digest)));
+
+            string message(1024, 'a');
+            string signature;
+            if (digest == KM_DIGEST_NONE)
+                message.resize(key_size / 8);
+            SignMessage(message, &signature, digest);
+        }
+    }
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_EQ(digests.size() * key_sizes.size() * 3,
+                  static_cast<size_t>(GetParam()->keymaster0_calls()));
+}
+
+TEST_P(SigningOperationsTest, AesEcbSign) {
+    ASSERT_EQ(KM_ERROR_OK,
+              GenerateKey(AuthorizationSetBuilder().AesEncryptionKey(128).Authorization(
+                  TAG_BLOCK_MODE, KM_MODE_ECB)));
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_SIGN));
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_VERIFY));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacSha1Success) {
+    if (GetParam()->minimal_digest_set())
+        // Can't emulate other digests for HMAC.
+        return;
+
+    GenerateKey(AuthorizationSetBuilder()
+                    .HmacKey(128)
+                    .Digest(KM_DIGEST_SHA1)
+                    .Authorization(TAG_MIN_MAC_LENGTH, 160));
+    string message = "12345678901234567890123456789012";
+    string signature;
+    MacMessage(message, &signature, 160);
+    ASSERT_EQ(20U, signature.size());
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacSha224Success) {
+    if (GetParam()->minimal_digest_set())
+        // Can't emulate other digests for HMAC.
+        return;
+
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .HmacKey(128)
+                                           .Digest(KM_DIGEST_SHA_2_224)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 160)));
+    string message = "12345678901234567890123456789012";
+    string signature;
+    MacMessage(message, &signature, 224);
+    ASSERT_EQ(28U, signature.size());
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacSha256Success) {
+    if (GetParam()->minimal_digest_set())
+        // Can't emulate other digests for HMAC.
+        return;
+
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .HmacKey(128)
+                                           .Digest(KM_DIGEST_SHA_2_256)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 256)));
+    string message = "12345678901234567890123456789012";
+    string signature;
+    MacMessage(message, &signature, 256);
+    ASSERT_EQ(32U, signature.size());
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacSha384Success) {
+    if (GetParam()->minimal_digest_set())
+        // Can't emulate other digests for HMAC.
+        return;
+
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .HmacKey(128)
+                                           .Digest(KM_DIGEST_SHA_2_384)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 384)));
+
+    string message = "12345678901234567890123456789012";
+    string signature;
+    MacMessage(message, &signature, 384);
+    ASSERT_EQ(48U, signature.size());
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacSha512Success) {
+    if (GetParam()->minimal_digest_set())
+        // Can't emulate other digests for HMAC.
+        return;
+
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .HmacKey(128)
+                                           .Digest(KM_DIGEST_SHA_2_512)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 384)));
+    string message = "12345678901234567890123456789012";
+    string signature;
+    MacMessage(message, &signature, 512);
+    ASSERT_EQ(64U, signature.size());
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacLengthInKey) {
+    // TODO(swillden): unified API should generate an error on key generation.
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .HmacKey(128)
+                                           .Digest(KM_DIGEST_SHA_2_256)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    string message = "12345678901234567890123456789012";
+    string signature;
+    MacMessage(message, &signature, 160);
+    ASSERT_EQ(20U, signature.size());
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase1) {
+    uint8_t key_data[] = {
+        0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+        0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+    };
+    string message = "Hi There";
+    uint8_t sha_224_expected[] = {
+        0x89, 0x6f, 0xb1, 0x12, 0x8a, 0xbb, 0xdf, 0x19, 0x68, 0x32, 0x10, 0x7c, 0xd4, 0x9d,
+        0xf3, 0x3f, 0x47, 0xb4, 0xb1, 0x16, 0x99, 0x12, 0xba, 0x4f, 0x53, 0x68, 0x4b, 0x22,
+    };
+    uint8_t sha_256_expected[] = {
+        0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf,
+        0xce, 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83,
+        0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7,
+    };
+    uint8_t sha_384_expected[] = {
+        0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62, 0x6b, 0x08, 0x25, 0xf4,
+        0xab, 0x46, 0x90, 0x7f, 0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6,
+        0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c, 0xfa, 0xea, 0x9e, 0xa9,
+        0x07, 0x6e, 0xde, 0x7f, 0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6,
+    };
+    uint8_t sha_512_expected[] = {
+        0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d, 0x4f, 0xf0, 0xb4, 0x24, 0x1a,
+        0x1d, 0x6c, 0xb0, 0x23, 0x79, 0xf4, 0xe2, 0xce, 0x4e, 0xc2, 0x78, 0x7a, 0xd0,
+        0xb3, 0x05, 0x45, 0xe1, 0x7c, 0xde, 0xda, 0xa8, 0x33, 0xb7, 0xd6, 0xb8, 0xa7,
+        0x02, 0x03, 0x8b, 0x27, 0x4e, 0xae, 0xa3, 0xf4, 0xe4, 0xbe, 0x9d, 0x91, 0x4e,
+        0xeb, 0x61, 0xf1, 0x70, 0x2e, 0x69, 0x6c, 0x20, 0x3a, 0x12, 0x68, 0x54,
+    };
+
+    string key = make_string(key_data);
+
+    CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
+    if (!GetParam()->minimal_digest_set()) {
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected));
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected));
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected));
+    }
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase2) {
+    string key = "Jefe";
+    string message = "what do ya want for nothing?";
+    uint8_t sha_224_expected[] = {
+        0xa3, 0x0e, 0x01, 0x09, 0x8b, 0xc6, 0xdb, 0xbf, 0x45, 0x69, 0x0f, 0x3a, 0x7e, 0x9e,
+        0x6d, 0x0f, 0x8b, 0xbe, 0xa2, 0xa3, 0x9e, 0x61, 0x48, 0x00, 0x8f, 0xd0, 0x5e, 0x44,
+    };
+    uint8_t sha_256_expected[] = {
+        0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24,
+        0x26, 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27,
+        0x39, 0x83, 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43,
+    };
+    uint8_t sha_384_expected[] = {
+        0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31, 0x61, 0x7f, 0x78, 0xd2,
+        0xb5, 0x8a, 0x6b, 0x1b, 0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47,
+        0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e, 0x8e, 0x22, 0x40, 0xca,
+        0x5e, 0x69, 0xe2, 0xc7, 0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49,
+    };
+    uint8_t sha_512_expected[] = {
+        0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2, 0xe3, 0x95, 0xfb, 0xe7, 0x3b,
+        0x56, 0xe0, 0xa3, 0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6, 0x10, 0x27,
+        0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54, 0x97, 0x58, 0xbf, 0x75, 0xc0, 0x5a, 0x99,
+        0x4a, 0x6d, 0x03, 0x4f, 0x65, 0xf8, 0xf0, 0xe6, 0xfd, 0xca, 0xea, 0xb1, 0xa3,
+        0x4d, 0x4a, 0x6b, 0x4b, 0x63, 0x6e, 0x07, 0x0a, 0x38, 0xbc, 0xe7, 0x37,
+    };
+
+    CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
+    if (!GetParam()->minimal_digest_set()) {
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected));
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected));
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected));
+    }
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase3) {
+    string key(20, 0xaa);
+    string message(50, 0xdd);
+    uint8_t sha_224_expected[] = {
+        0x7f, 0xb3, 0xcb, 0x35, 0x88, 0xc6, 0xc1, 0xf6, 0xff, 0xa9, 0x69, 0x4d, 0x7d, 0x6a,
+        0xd2, 0x64, 0x93, 0x65, 0xb0, 0xc1, 0xf6, 0x5d, 0x69, 0xd1, 0xec, 0x83, 0x33, 0xea,
+    };
+    uint8_t sha_256_expected[] = {
+        0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8,
+        0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8,
+        0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe,
+    };
+    uint8_t sha_384_expected[] = {
+        0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a, 0x0a, 0xa2, 0xac, 0xe0,
+        0x14, 0xc8, 0xa8, 0x6f, 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb,
+        0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b, 0x2a, 0x5a, 0xb3, 0x9d,
+        0xc1, 0x38, 0x14, 0xb9, 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27,
+    };
+    uint8_t sha_512_expected[] = {
+        0xfa, 0x73, 0xb0, 0x08, 0x9d, 0x56, 0xa2, 0x84, 0xef, 0xb0, 0xf0, 0x75, 0x6c,
+        0x89, 0x0b, 0xe9, 0xb1, 0xb5, 0xdb, 0xdd, 0x8e, 0xe8, 0x1a, 0x36, 0x55, 0xf8,
+        0x3e, 0x33, 0xb2, 0x27, 0x9d, 0x39, 0xbf, 0x3e, 0x84, 0x82, 0x79, 0xa7, 0x22,
+        0xc8, 0x06, 0xb4, 0x85, 0xa4, 0x7e, 0x67, 0xc8, 0x07, 0xb9, 0x46, 0xa3, 0x37,
+        0xbe, 0xe8, 0x94, 0x26, 0x74, 0x27, 0x88, 0x59, 0xe1, 0x32, 0x92, 0xfb,
+    };
+
+    CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
+    if (!GetParam()->minimal_digest_set()) {
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected));
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected));
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected));
+    }
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase4) {
+    uint8_t key_data[25] = {
+        0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+        0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+    };
+    string key = make_string(key_data);
+    string message(50, 0xcd);
+    uint8_t sha_224_expected[] = {
+        0x6c, 0x11, 0x50, 0x68, 0x74, 0x01, 0x3c, 0xac, 0x6a, 0x2a, 0xbc, 0x1b, 0xb3, 0x82,
+        0x62, 0x7c, 0xec, 0x6a, 0x90, 0xd8, 0x6e, 0xfc, 0x01, 0x2d, 0xe7, 0xaf, 0xec, 0x5a,
+    };
+    uint8_t sha_256_expected[] = {
+        0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81,
+        0x98, 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78,
+        0xf8, 0x07, 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b,
+    };
+    uint8_t sha_384_expected[] = {
+        0x3e, 0x8a, 0x69, 0xb7, 0x78, 0x3c, 0x25, 0x85, 0x19, 0x33, 0xab, 0x62,
+        0x90, 0xaf, 0x6c, 0xa7, 0x7a, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9c,
+        0xc5, 0x57, 0x7c, 0x6e, 0x1f, 0x57, 0x3b, 0x4e, 0x68, 0x01, 0xdd, 0x23,
+        0xc4, 0xa7, 0xd6, 0x79, 0xcc, 0xf8, 0xa3, 0x86, 0xc6, 0x74, 0xcf, 0xfb,
+    };
+    uint8_t sha_512_expected[] = {
+        0xb0, 0xba, 0x46, 0x56, 0x37, 0x45, 0x8c, 0x69, 0x90, 0xe5, 0xa8, 0xc5, 0xf6,
+        0x1d, 0x4a, 0xf7, 0xe5, 0x76, 0xd9, 0x7f, 0xf9, 0x4b, 0x87, 0x2d, 0xe7, 0x6f,
+        0x80, 0x50, 0x36, 0x1e, 0xe3, 0xdb, 0xa9, 0x1c, 0xa5, 0xc1, 0x1a, 0xa2, 0x5e,
+        0xb4, 0xd6, 0x79, 0x27, 0x5c, 0xc5, 0x78, 0x80, 0x63, 0xa5, 0xf1, 0x97, 0x41,
+        0x12, 0x0c, 0x4f, 0x2d, 0xe2, 0xad, 0xeb, 0xeb, 0x10, 0xa2, 0x98, 0xdd,
+    };
+
+    CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
+    if (!GetParam()->minimal_digest_set()) {
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected));
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected));
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected));
+    }
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase5) {
+    string key(20, 0x0c);
+    string message = "Test With Truncation";
+
+    uint8_t sha_224_expected[] = {
+        0x0e, 0x2a, 0xea, 0x68, 0xa9, 0x0c, 0x8d, 0x37,
+        0xc9, 0x88, 0xbc, 0xdb, 0x9f, 0xca, 0x6f, 0xa8,
+    };
+    uint8_t sha_256_expected[] = {
+        0xa3, 0xb6, 0x16, 0x74, 0x73, 0x10, 0x0e, 0xe0,
+        0x6e, 0x0c, 0x79, 0x6c, 0x29, 0x55, 0x55, 0x2b,
+    };
+    uint8_t sha_384_expected[] = {
+        0x3a, 0xbf, 0x34, 0xc3, 0x50, 0x3b, 0x2a, 0x23,
+        0xa4, 0x6e, 0xfc, 0x61, 0x9b, 0xae, 0xf8, 0x97,
+    };
+    uint8_t sha_512_expected[] = {
+        0x41, 0x5f, 0xad, 0x62, 0x71, 0x58, 0x0a, 0x53,
+        0x1d, 0x41, 0x79, 0xbc, 0x89, 0x1d, 0x87, 0xa6,
+    };
+
+    CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
+    if (!GetParam()->minimal_digest_set()) {
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected));
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected));
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected));
+    }
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase6) {
+    string key(131, 0xaa);
+    string message = "Test Using Larger Than Block-Size Key - Hash Key First";
+
+    uint8_t sha_224_expected[] = {
+        0x95, 0xe9, 0xa0, 0xdb, 0x96, 0x20, 0x95, 0xad, 0xae, 0xbe, 0x9b, 0x2d, 0x6f, 0x0d,
+        0xbc, 0xe2, 0xd4, 0x99, 0xf1, 0x12, 0xf2, 0xd2, 0xb7, 0x27, 0x3f, 0xa6, 0x87, 0x0e,
+    };
+    uint8_t sha_256_expected[] = {
+        0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26,
+        0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28,
+        0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54,
+    };
+    uint8_t sha_384_expected[] = {
+        0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90, 0x88, 0xd2, 0xc6, 0x3a,
+        0x04, 0x1b, 0xc5, 0xb4, 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f,
+        0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6, 0x0c, 0x2e, 0xf6, 0xab,
+        0x40, 0x30, 0xfe, 0x82, 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52,
+    };
+    uint8_t sha_512_expected[] = {
+        0x80, 0xb2, 0x42, 0x63, 0xc7, 0xc1, 0xa3, 0xeb, 0xb7, 0x14, 0x93, 0xc1, 0xdd,
+        0x7b, 0xe8, 0xb4, 0x9b, 0x46, 0xd1, 0xf4, 0x1b, 0x4a, 0xee, 0xc1, 0x12, 0x1b,
+        0x01, 0x37, 0x83, 0xf8, 0xf3, 0x52, 0x6b, 0x56, 0xd0, 0x37, 0xe0, 0x5f, 0x25,
+        0x98, 0xbd, 0x0f, 0xd2, 0x21, 0x5d, 0x6a, 0x1e, 0x52, 0x95, 0xe6, 0x4f, 0x73,
+        0xf6, 0x3f, 0x0a, 0xec, 0x8b, 0x91, 0x5a, 0x98, 0x5d, 0x78, 0x65, 0x98,
+    };
+
+    CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
+    if (!GetParam()->minimal_digest_set()) {
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected));
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected));
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected));
+    }
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase7) {
+    string key(131, 0xaa);
+    string message = "This is a test using a larger than block-size key and a larger than "
+                     "block-size data. The key needs to be hashed before being used by the HMAC "
+                     "algorithm.";
+
+    uint8_t sha_224_expected[] = {
+        0x3a, 0x85, 0x41, 0x66, 0xac, 0x5d, 0x9f, 0x02, 0x3f, 0x54, 0xd5, 0x17, 0xd0, 0xb3,
+        0x9d, 0xbd, 0x94, 0x67, 0x70, 0xdb, 0x9c, 0x2b, 0x95, 0xc9, 0xf6, 0xf5, 0x65, 0xd1,
+    };
+    uint8_t sha_256_expected[] = {
+        0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f,
+        0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07,
+        0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2,
+    };
+    uint8_t sha_384_expected[] = {
+        0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d, 0x35, 0x1e, 0x2f, 0x25,
+        0x4e, 0x8f, 0xd3, 0x2c, 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a,
+        0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5, 0xa6, 0x78, 0xcc, 0x31,
+        0xe7, 0x99, 0x17, 0x6d, 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e,
+    };
+    uint8_t sha_512_expected[] = {
+        0xe3, 0x7b, 0x6a, 0x77, 0x5d, 0xc8, 0x7d, 0xba, 0xa4, 0xdf, 0xa9, 0xf9, 0x6e,
+        0x5e, 0x3f, 0xfd, 0xde, 0xbd, 0x71, 0xf8, 0x86, 0x72, 0x89, 0x86, 0x5d, 0xf5,
+        0xa3, 0x2d, 0x20, 0xcd, 0xc9, 0x44, 0xb6, 0x02, 0x2c, 0xac, 0x3c, 0x49, 0x82,
+        0xb1, 0x0d, 0x5e, 0xeb, 0x55, 0xc3, 0xe4, 0xde, 0x15, 0x13, 0x46, 0x76, 0xfb,
+        0x6d, 0xe0, 0x44, 0x60, 0x65, 0xc9, 0x74, 0x40, 0xfa, 0x8c, 0x6a, 0x58,
+    };
+
+    CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
+    if (!GetParam()->minimal_digest_set()) {
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected));
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected));
+        CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected));
+    }
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacSha256TooLargeMacLength) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .HmacKey(128)
+                                           .Digest(KM_DIGEST_SHA_2_256)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 256)));
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_MAC_LENGTH, 264);
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_MAC_LENGTH,
+              BeginOperation(KM_PURPOSE_SIGN, begin_params, nullptr /* output_params */));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacSha256TooSmallMacLength) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .HmacKey(128)
+                                           .Digest(KM_DIGEST_SHA_2_256)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_MAC_LENGTH, 120);
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+    ASSERT_EQ(KM_ERROR_INVALID_MAC_LENGTH,
+              BeginOperation(KM_PURPOSE_SIGN, begin_params, nullptr /* output_params */));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+// TODO(swillden): Add more verification failure tests.
+
+typedef Keymaster2Test VerificationOperationsTest;
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, VerificationOperationsTest, test_params);
+
+TEST_P(VerificationOperationsTest, RsaSuccess) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(256, 3)
+                                           .Digest(KM_DIGEST_NONE)
+                                           .Padding(KM_PAD_NONE)));
+    string message = "12345678901234567890123456789012";
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
+    VerifyMessage(message, signature, KM_DIGEST_NONE, KM_PAD_NONE);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, RsaPssSha256Success) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(512, 3)
+                                           .Digest(KM_DIGEST_SHA_2_256)
+                                           .Padding(KM_PAD_RSA_PSS)));
+    // Use large message, which won't work without digesting.
+    string message(1024, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS);
+    VerifyMessage(message, signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, RsaPssSha224Success) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(512, 3)
+                                           .Digest(KM_DIGEST_SHA_2_224)
+                                           .Padding(KM_PAD_RSA_PSS)));
+    // Use large message, which won't work without digesting.
+    string message(1024, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_SHA_2_224, KM_PAD_RSA_PSS);
+    VerifyMessage(message, signature, KM_DIGEST_SHA_2_224, KM_PAD_RSA_PSS);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+
+    // Verify with OpenSSL.
+    string pubkey;
+    EXPECT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &pubkey));
+
+    const uint8_t* p = reinterpret_cast<const uint8_t*>(pubkey.data());
+    unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
+        d2i_PUBKEY(nullptr /* alloc new */, &p, pubkey.size()));
+    ASSERT_TRUE(pkey.get());
+
+    EVP_MD_CTX digest_ctx;
+    EVP_MD_CTX_init(&digest_ctx);
+    EVP_PKEY_CTX* pkey_ctx;
+    EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, EVP_sha224(), nullptr /* engine */,
+                                      pkey.get()));
+    EXPECT_EQ(1, EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING));
+    EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(), message.size()));
+    EXPECT_EQ(1,
+              EVP_DigestVerifyFinal(&digest_ctx, reinterpret_cast<const uint8_t*>(signature.data()),
+                                    signature.size()));
+    EVP_MD_CTX_cleanup(&digest_ctx);
+}
+
+TEST_P(VerificationOperationsTest, RsaPssSha256CorruptSignature) {
+    GenerateKey(AuthorizationSetBuilder()
+                    .RsaSigningKey(512, 3)
+                    .Digest(KM_DIGEST_SHA_2_256)
+                    .Padding(KM_PAD_RSA_PSS));
+    string message(1024, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS);
+    ++signature[signature.size() / 2];
+
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+    begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PSS);
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
+
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, RsaPssSha256CorruptInput) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(512, 3)
+                                           .Digest(KM_DIGEST_SHA_2_256)
+                                           .Padding(KM_PAD_RSA_PSS)));
+    // Use large message, which won't work without digesting.
+    string message(1024, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS);
+    ++message[message.size() / 2];
+
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+    begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PSS);
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
+
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, RsaPkcs1Sha256Success) {
+    GenerateKey(AuthorizationSetBuilder()
+                    .RsaSigningKey(512, 3)
+                    .Digest(KM_DIGEST_SHA_2_256)
+                    .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN));
+    string message(1024, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN);
+    VerifyMessage(message, signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, RsaPks1Sha224Success) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(512, 3)
+                                           .Digest(KM_DIGEST_SHA_2_224)
+                                           .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)));
+    // Use large message, which won't work without digesting.
+    string message(1024, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_SHA_2_224, KM_PAD_RSA_PKCS1_1_5_SIGN);
+    VerifyMessage(message, signature, KM_DIGEST_SHA_2_224, KM_PAD_RSA_PKCS1_1_5_SIGN);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+
+    // Verify with OpenSSL.
+    string pubkey;
+    EXPECT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &pubkey));
+
+    const uint8_t* p = reinterpret_cast<const uint8_t*>(pubkey.data());
+    unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
+        d2i_PUBKEY(nullptr /* alloc new */, &p, pubkey.size()));
+    ASSERT_TRUE(pkey.get());
+
+    EVP_MD_CTX digest_ctx;
+    EVP_MD_CTX_init(&digest_ctx);
+    EVP_PKEY_CTX* pkey_ctx;
+    EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, EVP_sha224(), nullptr /* engine */,
+                                      pkey.get()));
+    EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(), message.size()));
+    EXPECT_EQ(1,
+              EVP_DigestVerifyFinal(&digest_ctx, reinterpret_cast<const uint8_t*>(signature.data()),
+                                    signature.size()));
+    EVP_MD_CTX_cleanup(&digest_ctx);
+}
+
+TEST_P(VerificationOperationsTest, RsaPkcs1Sha256CorruptSignature) {
+    GenerateKey(AuthorizationSetBuilder()
+                    .RsaSigningKey(512, 3)
+                    .Digest(KM_DIGEST_SHA_2_256)
+                    .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN));
+    string message(1024, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN);
+    ++signature[signature.size() / 2];
+
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+    begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN);
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
+
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, RsaPkcs1Sha256CorruptInput) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(512, 3)
+                                           .Digest(KM_DIGEST_SHA_2_256)
+                                           .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)));
+    // Use large message, which won't work without digesting.
+    string message(1024, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN);
+    ++message[message.size() / 2];
+
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+    begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN);
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
+
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, RsaAllDigestAndPadCombinations) {
+    vector<keymaster_digest_t> digests = {
+        KM_DIGEST_NONE,      KM_DIGEST_MD5,       KM_DIGEST_SHA1,      KM_DIGEST_SHA_2_224,
+        KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512,
+    };
+
+    vector<keymaster_padding_t> padding_modes{
+        KM_PAD_NONE, KM_PAD_RSA_PKCS1_1_5_SIGN, KM_PAD_RSA_PSS,
+    };
+
+    int trial_count = 0;
+    for (keymaster_padding_t padding_mode : padding_modes) {
+        for (keymaster_digest_t digest : digests) {
+            if (digest != KM_DIGEST_NONE && padding_mode == KM_PAD_NONE)
+                // Digesting requires padding
+                continue;
+
+            // Compute key & message size that will work.
+            size_t key_bits = 0;
+            size_t message_len = 1000;
+
+            if (digest == KM_DIGEST_NONE) {
+                key_bits = 256;
+                switch (padding_mode) {
+                case KM_PAD_NONE:
+                    // Match key size.
+                    message_len = key_bits / 8;
+                    break;
+                case KM_PAD_RSA_PKCS1_1_5_SIGN:
+                    message_len = key_bits / 8 - 11;
+                    break;
+                case KM_PAD_RSA_PSS:
+                    // PSS requires a digest.
+                    continue;
+                default:
+                    FAIL() << "Missing padding";
+                    break;
+                }
+            } else {
+                size_t digest_bits;
+                switch (digest) {
+                case KM_DIGEST_MD5:
+                    digest_bits = 128;
+                    break;
+                case KM_DIGEST_SHA1:
+                    digest_bits = 160;
+                    break;
+                case KM_DIGEST_SHA_2_224:
+                    digest_bits = 224;
+                    break;
+                case KM_DIGEST_SHA_2_256:
+                    digest_bits = 256;
+                    break;
+                case KM_DIGEST_SHA_2_384:
+                    digest_bits = 384;
+                    break;
+                case KM_DIGEST_SHA_2_512:
+                    digest_bits = 512;
+                    break;
+                default:
+                    FAIL() << "Missing digest";
+                }
+
+                switch (padding_mode) {
+                case KM_PAD_RSA_PKCS1_1_5_SIGN:
+                    key_bits = digest_bits + 8 * (11 + 19);
+                    break;
+                case KM_PAD_RSA_PSS:
+                    key_bits = digest_bits + 22 * 8;
+                    break;
+                default:
+                    FAIL() << "Missing padding";
+                    break;
+                }
+            }
+
+            GenerateKey(AuthorizationSetBuilder()
+                            .RsaSigningKey(key_bits, 3)
+                            .Digest(digest)
+                            .Padding(padding_mode));
+            string message(message_len, 'a');
+            string signature;
+            SignMessage(message, &signature, digest, padding_mode);
+            VerifyMessage(message, signature, digest, padding_mode);
+            ++trial_count;
+        }
+    }
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(trial_count * 4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, EcdsaSuccess) {
+    ASSERT_EQ(KM_ERROR_OK,
+              GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(KM_DIGEST_NONE)));
+    string message = "12345678901234567890123456789012";
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_NONE);
+    VerifyMessage(message, signature, KM_DIGEST_NONE);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, EcdsaTooShort) {
+    ASSERT_EQ(KM_ERROR_OK,
+              GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(KM_DIGEST_NONE)));
+    string message = "12345678901234567890";
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_NONE);
+    VerifyMessage(message, signature, KM_DIGEST_NONE);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, EcdsaSlightlyTooLong) {
+    ASSERT_EQ(KM_ERROR_OK,
+              GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(521).Digest(KM_DIGEST_NONE)));
+
+    string message(66, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_NONE);
+    VerifyMessage(message, signature, KM_DIGEST_NONE);
+
+    // Modifying low-order bits doesn't matter, because they didn't get signed.  Ugh.
+    message[65] ^= 7;
+    VerifyMessage(message, signature, KM_DIGEST_NONE);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_EQ(5, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, EcdsaSha256Success) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .EcdsaSigningKey(256)
+                                           .Digest(KM_DIGEST_SHA_2_256)
+                                           .Digest(KM_DIGEST_NONE)));
+    string message = "12345678901234567890123456789012";
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_SHA_2_256);
+    VerifyMessage(message, signature, KM_DIGEST_SHA_2_256);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+
+    // Just for giggles, try verifying with the wrong digest.
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
+
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
+}
+
+TEST_P(VerificationOperationsTest, EcdsaSha224Success) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(
+                               KM_DIGEST_SHA_2_224)));
+
+    string message = "12345678901234567890123456789012";
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_SHA_2_224);
+    VerifyMessage(message, signature, KM_DIGEST_SHA_2_224);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+
+    // Just for giggles, try verifying with the wrong digest.
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
+
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
+}
+
+TEST_P(VerificationOperationsTest, EcdsaAllDigestsAndKeySizes) {
+    keymaster_digest_t digests[] = {
+        KM_DIGEST_SHA1,      KM_DIGEST_SHA_2_224, KM_DIGEST_SHA_2_256,
+        KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512,
+    };
+    size_t key_sizes[] = {224, 256, 384, 521};
+
+    string message = "1234567890";
+    string signature;
+
+    for (auto key_size : key_sizes) {
+        AuthorizationSetBuilder builder;
+        builder.EcdsaSigningKey(key_size);
+        for (auto digest : digests)
+            builder.Digest(digest);
+        ASSERT_EQ(KM_ERROR_OK, GenerateKey(builder));
+
+        for (auto digest : digests) {
+            SignMessage(message, &signature, digest);
+            VerifyMessage(message, signature, digest);
+        }
+    }
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_EQ(static_cast<int>(array_length(key_sizes) * (1 + 3 * array_length(digests))),
+                  GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, HmacSha1Success) {
+    if (GetParam()->minimal_digest_set())
+        // Can't emulate missing digests for HMAC.
+        return;
+
+    GenerateKey(AuthorizationSetBuilder()
+                    .HmacKey(128)
+                    .Digest(KM_DIGEST_SHA1)
+                    .Authorization(TAG_MIN_MAC_LENGTH, 128));
+    string message = "123456789012345678901234567890123456789012345678";
+    string signature;
+    MacMessage(message, &signature, 160);
+    VerifyMac(message, signature);
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, HmacSha224Success) {
+    if (GetParam()->minimal_digest_set())
+        // Can't emulate missing digests for HMAC.
+        return;
+
+    GenerateKey(AuthorizationSetBuilder()
+                    .HmacKey(128)
+                    .Digest(KM_DIGEST_SHA_2_224)
+                    .Authorization(TAG_MIN_MAC_LENGTH, 128));
+    string message = "123456789012345678901234567890123456789012345678";
+    string signature;
+    MacMessage(message, &signature, 224);
+    VerifyMac(message, signature);
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, HmacSha256Success) {
+    GenerateKey(AuthorizationSetBuilder()
+                    .HmacKey(128)
+                    .Digest(KM_DIGEST_SHA_2_256)
+                    .Authorization(TAG_MIN_MAC_LENGTH, 128));
+    string message = "123456789012345678901234567890123456789012345678";
+    string signature;
+    MacMessage(message, &signature, 256);
+    VerifyMac(message, signature);
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, HmacSha256TooShortMac) {
+    GenerateKey(AuthorizationSetBuilder()
+                    .HmacKey(128)
+                    .Digest(KM_DIGEST_SHA_2_256)
+                    .Authorization(TAG_MIN_MAC_LENGTH, 128));
+    string message = "123456789012345678901234567890123456789012345678";
+    string signature;
+    MacMessage(message, &signature, 256);
+
+    // Shorten to 128 bits, should still work.
+    signature.resize(128 / 8);
+    VerifyMac(message, signature);
+
+    // Drop one more byte.
+    signature.resize(signature.length() - 1);
+
+    AuthorizationSet begin_params(client_params());
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+    EXPECT_EQ(KM_ERROR_INVALID_MAC_LENGTH, FinishOperation(signature, &result));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, HmacSha384Success) {
+    if (GetParam()->minimal_digest_set())
+        // Can't emulate missing digests for HMAC.
+        return;
+
+    GenerateKey(AuthorizationSetBuilder()
+                    .HmacKey(128)
+                    .Digest(KM_DIGEST_SHA_2_384)
+                    .Authorization(TAG_MIN_MAC_LENGTH, 128));
+    string message = "123456789012345678901234567890123456789012345678";
+    string signature;
+    MacMessage(message, &signature, 384);
+    VerifyMac(message, signature);
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, HmacSha512Success) {
+    if (GetParam()->minimal_digest_set())
+        // Can't emulate missing digests for HMAC.
+        return;
+
+    GenerateKey(AuthorizationSetBuilder()
+                    .HmacKey(128)
+                    .Digest(KM_DIGEST_SHA_2_512)
+                    .Authorization(TAG_MIN_MAC_LENGTH, 128));
+    string message = "123456789012345678901234567890123456789012345678";
+    string signature;
+    MacMessage(message, &signature, 512);
+    VerifyMac(message, signature);
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+typedef Keymaster2Test ExportKeyTest;
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, ExportKeyTest, test_params);
+
+TEST_P(ExportKeyTest, RsaSuccess) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(256, 3)
+                                           .Digest(KM_DIGEST_NONE)
+                                           .Padding(KM_PAD_NONE)));
+    string export_data;
+    ASSERT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &export_data));
+    EXPECT_GT(export_data.length(), 0U);
+
+    // TODO(swillden): Verify that the exported key is actually usable to verify signatures.
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(ExportKeyTest, EcdsaSuccess) {
+    ASSERT_EQ(KM_ERROR_OK,
+              GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE)));
+    string export_data;
+    ASSERT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &export_data));
+    EXPECT_GT(export_data.length(), 0U);
+
+    // TODO(swillden): Verify that the exported key is actually usable to verify signatures.
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(ExportKeyTest, RsaUnsupportedKeyFormat) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(256, 3)
+                                           .Digest(KM_DIGEST_NONE)
+                                           .Padding(KM_PAD_NONE)));
+    string export_data;
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT, ExportKey(KM_KEY_FORMAT_PKCS8, &export_data));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(ExportKeyTest, RsaCorruptedKeyBlob) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(256, 3)
+                                           .Digest(KM_DIGEST_NONE)
+                                           .Padding(KM_PAD_NONE)));
+    corrupt_key_blob();
+    string export_data;
+    ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, ExportKey(KM_KEY_FORMAT_X509, &export_data));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(ExportKeyTest, AesKeyExportFails) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().AesEncryptionKey(128)));
+    string export_data;
+
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT, ExportKey(KM_KEY_FORMAT_X509, &export_data));
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT, ExportKey(KM_KEY_FORMAT_PKCS8, &export_data));
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT, ExportKey(KM_KEY_FORMAT_RAW, &export_data));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+static string read_file(const string& file_name) {
+    ifstream file_stream(file_name, std::ios::binary);
+    istreambuf_iterator<char> file_begin(file_stream);
+    istreambuf_iterator<char> file_end;
+    return string(file_begin, file_end);
+}
+
+typedef Keymaster2Test ImportKeyTest;
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, ImportKeyTest, test_params);
+
+TEST_P(ImportKeyTest, RsaSuccess) {
+    string pk8_key = read_file("rsa_privkey_pk8.der");
+    ASSERT_EQ(633U, pk8_key.size());
+
+    ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder()
+                                         .RsaSigningKey(1024, 65537)
+                                         .Digest(KM_DIGEST_NONE)
+                                         .Padding(KM_PAD_NONE),
+                                     KM_KEY_FORMAT_PKCS8, pk8_key));
+
+    // Check values derived from the key.
+    EXPECT_TRUE(contains(GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA) ? hw_enforced()
+                                                                                 : sw_enforced(),
+                         TAG_ALGORITHM, KM_ALGORITHM_RSA));
+    EXPECT_TRUE(contains(GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA) ? hw_enforced()
+                                                                                 : sw_enforced(),
+                         TAG_KEY_SIZE, 1024));
+    EXPECT_TRUE(contains(GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA) ? hw_enforced()
+                                                                                 : sw_enforced(),
+                         TAG_RSA_PUBLIC_EXPONENT, 65537U));
+
+    // And values provided by AndroidKeymaster
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_TRUE(contains(hw_enforced(), TAG_ORIGIN, KM_ORIGIN_UNKNOWN));
+    else
+        EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED));
+    EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME));
+
+    string message(1024 / 8, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
+    VerifyMessage(message, signature, KM_DIGEST_NONE, KM_PAD_NONE);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(ImportKeyTest, RsaKeySizeMismatch) {
+    string pk8_key = read_file("rsa_privkey_pk8.der");
+    ASSERT_EQ(633U, pk8_key.size());
+    ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH,
+              ImportKey(AuthorizationSetBuilder()
+                            .RsaSigningKey(2048 /* Doesn't match key */, 3)
+                            .Digest(KM_DIGEST_NONE)
+                            .Padding(KM_PAD_NONE),
+                        KM_KEY_FORMAT_PKCS8, pk8_key));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(ImportKeyTest, RsaPublicExponenMismatch) {
+    string pk8_key = read_file("rsa_privkey_pk8.der");
+    ASSERT_EQ(633U, pk8_key.size());
+    ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH,
+              ImportKey(AuthorizationSetBuilder()
+                            .RsaSigningKey(256, 3 /* Doesnt' match key */)
+                            .Digest(KM_DIGEST_NONE)
+                            .Padding(KM_PAD_NONE),
+                        KM_KEY_FORMAT_PKCS8, pk8_key));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(ImportKeyTest, EcdsaSuccess) {
+    string pk8_key = read_file("ec_privkey_pk8.der");
+    ASSERT_EQ(138U, pk8_key.size());
+
+    ASSERT_EQ(KM_ERROR_OK,
+              ImportKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(KM_DIGEST_NONE),
+                        KM_KEY_FORMAT_PKCS8, pk8_key));
+
+    // Check values derived from the key.
+    EXPECT_TRUE(contains(GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC) ? hw_enforced()
+                                                                                : sw_enforced(),
+                         TAG_ALGORITHM, KM_ALGORITHM_EC));
+    EXPECT_TRUE(contains(GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC) ? hw_enforced()
+                                                                                : sw_enforced(),
+                         TAG_KEY_SIZE, 256));
+
+    // And values provided by AndroidKeymaster
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_TRUE(contains(hw_enforced(), TAG_ORIGIN, KM_ORIGIN_UNKNOWN));
+    else
+        EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED));
+    EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME));
+
+    string message(32, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_NONE);
+    VerifyMessage(message, signature, KM_DIGEST_NONE);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(ImportKeyTest, EcdsaSizeSpecified) {
+    string pk8_key = read_file("ec_privkey_pk8.der");
+    ASSERT_EQ(138U, pk8_key.size());
+
+    ASSERT_EQ(KM_ERROR_OK,
+              ImportKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(KM_DIGEST_NONE),
+                        KM_KEY_FORMAT_PKCS8, pk8_key));
+
+    // Check values derived from the key.
+    EXPECT_TRUE(contains(GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC) ? hw_enforced()
+                                                                                : sw_enforced(),
+                         TAG_ALGORITHM, KM_ALGORITHM_EC));
+    EXPECT_TRUE(contains(GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC) ? hw_enforced()
+                                                                                : sw_enforced(),
+                         TAG_KEY_SIZE, 256));
+
+    // And values provided by AndroidKeymaster
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_TRUE(contains(hw_enforced(), TAG_ORIGIN, KM_ORIGIN_UNKNOWN));
+    else
+        EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED));
+    EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME));
+
+    string message(32, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_NONE);
+    VerifyMessage(message, signature, KM_DIGEST_NONE);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(ImportKeyTest, EcdsaSizeMismatch) {
+    string pk8_key = read_file("ec_privkey_pk8.der");
+    ASSERT_EQ(138U, pk8_key.size());
+    ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH,
+              ImportKey(AuthorizationSetBuilder()
+                            .EcdsaSigningKey(224 /* Doesn't match key */)
+                            .Digest(KM_DIGEST_NONE),
+                        KM_KEY_FORMAT_PKCS8, pk8_key));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(ImportKeyTest, AesKeySuccess) {
+    char key_data[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    string key(key_data, sizeof(key_data));
+    ASSERT_EQ(KM_ERROR_OK,
+              ImportKey(AuthorizationSetBuilder().AesEncryptionKey(128).EcbMode().Authorization(
+                            TAG_PADDING, KM_PAD_PKCS7),
+                        KM_KEY_FORMAT_RAW, key));
+
+    EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED));
+    EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME));
+
+    string message = "Hello World!";
+    string ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_PKCS7);
+    string plaintext = DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_PKCS7);
+    EXPECT_EQ(message, plaintext);
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(ImportKeyTest, HmacSha256KeySuccess) {
+    char key_data[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    string key(key_data, sizeof(key_data));
+    ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder()
+                                         .HmacKey(sizeof(key_data) * 8)
+                                         .Digest(KM_DIGEST_SHA_2_256)
+                                         .Authorization(TAG_MIN_MAC_LENGTH, 256),
+                                     KM_KEY_FORMAT_RAW, key));
+
+    EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED));
+    EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME));
+
+    string message = "Hello World!";
+    string signature;
+    MacMessage(message, &signature, 256);
+    VerifyMac(message, signature);
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+typedef Keymaster2Test EncryptionOperationsTest;
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, EncryptionOperationsTest, test_params);
+
+TEST_P(EncryptionOperationsTest, RsaNoPaddingSuccess) {
+    ASSERT_EQ(KM_ERROR_OK,
+              GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(256, 3).Padding(KM_PAD_NONE)));
+
+    string message = "12345678901234567890123456789012";
+    string ciphertext1 = EncryptMessage(string(message), KM_PAD_NONE);
+    EXPECT_EQ(256U / 8, ciphertext1.size());
+
+    string ciphertext2 = EncryptMessage(string(message), KM_PAD_NONE);
+    EXPECT_EQ(256U / 8, ciphertext2.size());
+
+    // Unpadded RSA is deterministic
+    EXPECT_EQ(ciphertext1, ciphertext2);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(3, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaNoPaddingTooShort) {
+    ASSERT_EQ(KM_ERROR_OK,
+              GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(256, 3).Padding(KM_PAD_NONE)));
+
+    string message = "1";
+
+    string ciphertext = EncryptMessage(message, KM_PAD_NONE);
+    EXPECT_EQ(256U / 8, ciphertext.size());
+
+    string expected_plaintext = string(256 / 8 - 1, 0) + message;
+    string plaintext = DecryptMessage(ciphertext, KM_PAD_NONE);
+
+    EXPECT_EQ(expected_plaintext, plaintext);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaNoPaddingTooLong) {
+    ASSERT_EQ(KM_ERROR_OK,
+              GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(256, 3).Padding(KM_PAD_NONE)));
+
+    string message = "123456789012345678901234567890123";
+
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, UpdateOperation(message, &result, &input_consumed));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaNoPaddingLargerThanModulus) {
+    ASSERT_EQ(KM_ERROR_OK,
+              GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(256, 3).Padding(KM_PAD_NONE)));
+
+    string exported;
+    ASSERT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &exported));
+
+    const uint8_t* p = reinterpret_cast<const uint8_t*>(exported.data());
+    unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
+        d2i_PUBKEY(nullptr /* alloc new */, &p, exported.size()));
+    unique_ptr<RSA, RSA_Delete> rsa(EVP_PKEY_get1_RSA(pkey.get()));
+
+    size_t modulus_len = BN_num_bytes(rsa->n);
+    ASSERT_EQ(256U / 8, modulus_len);
+    unique_ptr<uint8_t[]> modulus_buf(new uint8_t[modulus_len]);
+    BN_bn2bin(rsa->n, modulus_buf.get());
+
+    // The modulus is too big to encrypt.
+    string message(reinterpret_cast<const char*>(modulus_buf.get()), modulus_len);
+
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+    EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, FinishOperation(&result));
+
+    // One smaller than the modulus is okay.
+    BN_sub(rsa->n, rsa->n, BN_value_one());
+    modulus_len = BN_num_bytes(rsa->n);
+    ASSERT_EQ(256U / 8, modulus_len);
+    BN_bn2bin(rsa->n, modulus_buf.get());
+    message = string(reinterpret_cast<const char*>(modulus_buf.get()), modulus_len);
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(&result));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaOaepSuccess) {
+    size_t key_size = 768;
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaEncryptionKey(key_size, 3)
+                                           .Padding(KM_PAD_RSA_OAEP)
+                                           .Digest(KM_DIGEST_SHA_2_256)));
+
+    string message = "Hello";
+    string ciphertext1 = EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP);
+    EXPECT_EQ(key_size / 8, ciphertext1.size());
+
+    string ciphertext2 = EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP);
+    EXPECT_EQ(key_size / 8, ciphertext2.size());
+
+    // OAEP randomizes padding so every result should be different.
+    EXPECT_NE(ciphertext1, ciphertext2);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(3, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaOaepSha224Success) {
+    size_t key_size = 768;
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaEncryptionKey(key_size, 3)
+                                           .Padding(KM_PAD_RSA_OAEP)
+                                           .Digest(KM_DIGEST_SHA_2_224)));
+
+    string message = "Hello";
+    string ciphertext1 = EncryptMessage(string(message), KM_DIGEST_SHA_2_224, KM_PAD_RSA_OAEP);
+    EXPECT_EQ(key_size / 8, ciphertext1.size());
+
+    string ciphertext2 = EncryptMessage(string(message), KM_DIGEST_SHA_2_224, KM_PAD_RSA_OAEP);
+    EXPECT_EQ(key_size / 8, ciphertext2.size());
+
+    // OAEP randomizes padding so every result should be different.
+    EXPECT_NE(ciphertext1, ciphertext2);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(3, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaOaepRoundTrip) {
+    size_t key_size = 768;
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaEncryptionKey(key_size, 3)
+                                           .Padding(KM_PAD_RSA_OAEP)
+                                           .Digest(KM_DIGEST_SHA_2_256)));
+    string message = "Hello World!";
+    string ciphertext = EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP);
+    EXPECT_EQ(key_size / 8, ciphertext.size());
+
+    string plaintext = DecryptMessage(ciphertext, KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP);
+    EXPECT_EQ(message, plaintext);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaOaepSha224RoundTrip) {
+    size_t key_size = 768;
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaEncryptionKey(key_size, 3)
+                                           .Padding(KM_PAD_RSA_OAEP)
+                                           .Digest(KM_DIGEST_SHA_2_224)));
+    string message = "Hello World!";
+    string ciphertext = EncryptMessage(string(message), KM_DIGEST_SHA_2_224, KM_PAD_RSA_OAEP);
+    EXPECT_EQ(key_size / 8, ciphertext.size());
+
+    string plaintext = DecryptMessage(ciphertext, KM_DIGEST_SHA_2_224, KM_PAD_RSA_OAEP);
+    EXPECT_EQ(message, plaintext);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaOaepInvalidDigest) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaEncryptionKey(512, 3)
+                                           .Padding(KM_PAD_RSA_OAEP)
+                                           .Digest(KM_DIGEST_NONE)));
+    string message = "Hello World!";
+
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, KM_PAD_RSA_OAEP);
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
+    EXPECT_EQ(KM_ERROR_INCOMPATIBLE_DIGEST, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaOaepUnauthorizedDigest) {
+    if (GetParam()->minimal_digest_set())
+        // We don't have two supported digests, so we can't try authorizing one and using another.
+        return;
+
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaEncryptionKey(512, 3)
+                                           .Padding(KM_PAD_RSA_OAEP)
+                                           .Digest(KM_DIGEST_SHA_2_256)));
+    string message = "Hello World!";
+    // Works because encryption is a public key operation.
+    EncryptMessage(string(message), KM_DIGEST_SHA1, KM_PAD_RSA_OAEP);
+
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, KM_PAD_RSA_OAEP);
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA1);
+    EXPECT_EQ(KM_ERROR_INCOMPATIBLE_DIGEST, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(3, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) {
+    if (GetParam()->minimal_digest_set())
+        // We don't have two supported digests, so we can't try encrypting with one and decrypting
+        // with another.
+        return;
+
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaEncryptionKey(768, 3)
+                                           .Padding(KM_PAD_RSA_OAEP)
+                                           .Digest(KM_DIGEST_SHA_2_256)
+                                           .Digest(KM_DIGEST_SHA_2_384)));
+    string message = "Hello World!";
+    string ciphertext = EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP);
+
+    string result;
+    size_t input_consumed;
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, KM_PAD_RSA_OAEP);
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_384);
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext, &result, &input_consumed));
+    EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, FinishOperation(&result));
+    EXPECT_EQ(0U, result.size());
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaOaepTooLarge) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaEncryptionKey(512, 3)
+                                           .Padding(KM_PAD_RSA_OAEP)
+                                           .Digest(KM_DIGEST_SHA1)));
+    string message = "12345678901234567890123";
+    string result;
+    size_t input_consumed;
+
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, KM_PAD_RSA_OAEP);
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA1);
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+    EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(&result));
+    EXPECT_EQ(0U, result.size());
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaOaepCorruptedDecrypt) {
+    size_t key_size = 768;
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaEncryptionKey(768, 3)
+                                           .Padding(KM_PAD_RSA_OAEP)
+                                           .Digest(KM_DIGEST_SHA_2_256)));
+    string message = "Hello World!";
+    string ciphertext = EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP);
+    EXPECT_EQ(key_size / 8, ciphertext.size());
+
+    // Corrupt the ciphertext
+    ciphertext[key_size / 8 / 2]++;
+
+    string result;
+    size_t input_consumed;
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, KM_PAD_RSA_OAEP);
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext, &result, &input_consumed));
+    EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, FinishOperation(&result));
+    EXPECT_EQ(0U, result.size());
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaPkcs1Success) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(512, 3).Padding(
+                               KM_PAD_RSA_PKCS1_1_5_ENCRYPT)));
+    string message = "Hello World!";
+    string ciphertext1 = EncryptMessage(message, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+    EXPECT_EQ(512U / 8, ciphertext1.size());
+
+    string ciphertext2 = EncryptMessage(message, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+    EXPECT_EQ(512U / 8, ciphertext2.size());
+
+    // PKCS1 v1.5 randomizes padding so every result should be different.
+    EXPECT_NE(ciphertext1, ciphertext2);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(3, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaPkcs1RoundTrip) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(512, 3).Padding(
+                               KM_PAD_RSA_PKCS1_1_5_ENCRYPT)));
+    string message = "Hello World!";
+    string ciphertext = EncryptMessage(message, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+    EXPECT_EQ(512U / 8, ciphertext.size());
+
+    string plaintext = DecryptMessage(ciphertext, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+    EXPECT_EQ(message, plaintext);
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaRoundTripAllCombinations) {
+    size_t key_size = 2048;
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaEncryptionKey(key_size, 3)
+                                           .Padding(KM_PAD_RSA_PKCS1_1_5_ENCRYPT)
+                                           .Padding(KM_PAD_RSA_OAEP)
+                                           .Digest(KM_DIGEST_NONE)
+                                           .Digest(KM_DIGEST_MD5)
+                                           .Digest(KM_DIGEST_SHA1)
+                                           .Digest(KM_DIGEST_SHA_2_224)
+                                           .Digest(KM_DIGEST_SHA_2_256)
+                                           .Digest(KM_DIGEST_SHA_2_384)
+                                           .Digest(KM_DIGEST_SHA_2_512)));
+
+    string message = "Hello World!";
+
+    keymaster_padding_t padding_modes[] = {KM_PAD_RSA_OAEP, KM_PAD_RSA_PKCS1_1_5_ENCRYPT};
+    keymaster_digest_t digests[] = {
+        KM_DIGEST_NONE,      KM_DIGEST_MD5,       KM_DIGEST_SHA1,      KM_DIGEST_SHA_2_224,
+        KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512,
+    };
+
+    for (auto padding : padding_modes)
+        for (auto digest : digests) {
+            if (padding == KM_PAD_RSA_OAEP && digest == KM_DIGEST_NONE)
+                // OAEP requires a digest.
+                continue;
+
+            string ciphertext = EncryptMessage(message, digest, padding);
+            EXPECT_EQ(key_size / 8, ciphertext.size());
+
+            string plaintext = DecryptMessage(ciphertext, digest, padding);
+            EXPECT_EQ(message, plaintext);
+        }
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(40, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaPkcs1TooLarge) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(512, 3).Padding(
+                               KM_PAD_RSA_PKCS1_1_5_ENCRYPT)));
+    string message = "123456789012345678901234567890123456789012345678901234";
+    string result;
+    size_t input_consumed;
+
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+    EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(&result));
+    EXPECT_EQ(0U, result.size());
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaPkcs1CorruptedDecrypt) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(512, 3).Padding(
+                               KM_PAD_RSA_PKCS1_1_5_ENCRYPT)));
+    string message = "Hello World!";
+    string ciphertext = EncryptMessage(string(message), KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+    EXPECT_EQ(512U / 8, ciphertext.size());
+
+    // Corrupt the ciphertext
+    ciphertext[512 / 8 / 2]++;
+
+    string result;
+    size_t input_consumed;
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext, &result, &input_consumed));
+    EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, FinishOperation(&result));
+    EXPECT_EQ(0U, result.size());
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaEncryptWithSigningKey) {
+    ASSERT_EQ(KM_ERROR_OK,
+              GenerateKey(AuthorizationSetBuilder().RsaSigningKey(256, 3).Padding(KM_PAD_NONE)));
+
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    ASSERT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, EcdsaEncrypt) {
+    ASSERT_EQ(KM_ERROR_OK,
+              GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE)));
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_ENCRYPT));
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_DECRYPT));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_EQ(3, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, HmacEncrypt) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .HmacKey(128)
+                                           .Digest(KM_DIGEST_SHA_2_256)
+                                           .Padding(KM_PAD_NONE)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_ENCRYPT));
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_DECRYPT));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesEcbRoundTripSuccess) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB)
+                                           .Padding(KM_PAD_NONE)));
+    // Two-block message.
+    string message = "12345678901234567890123456789012";
+    string ciphertext1 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+
+    string ciphertext2 = EncryptMessage(string(message), KM_MODE_ECB, KM_PAD_NONE);
+    EXPECT_EQ(message.size(), ciphertext2.size());
+
+    // ECB is deterministic.
+    EXPECT_EQ(ciphertext1, ciphertext2);
+
+    string plaintext = DecryptMessage(ciphertext1, KM_MODE_ECB, KM_PAD_NONE);
+    EXPECT_EQ(message, plaintext);
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesEcbNotAuthorized) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC)
+                                           .Padding(KM_PAD_NONE)));
+    // Two-block message.
+    string message = "12345678901234567890123456789012";
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    EXPECT_EQ(KM_ERROR_INCOMPATIBLE_BLOCK_MODE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesEcbNoPaddingWrongInputSize) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB)
+                                           .Padding(KM_PAD_NONE)));
+    // Message is slightly shorter than two blocks.
+    string message = "1234567890123456789012345678901";
+
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+    string ciphertext;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &ciphertext, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(&ciphertext));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesEcbPkcs7Padding) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB)
+                                           .Authorization(TAG_PADDING, KM_PAD_PKCS7)));
+
+    // Try various message lengths; all should work.
+    for (size_t i = 0; i < 32; ++i) {
+        string message(i, 'a');
+        string ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_PKCS7);
+        EXPECT_EQ(i + 16 - (i % 16), ciphertext.size());
+        string plaintext = DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_PKCS7);
+        EXPECT_EQ(message, plaintext);
+    }
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesEcbNoPaddingKeyWithPkcs7Padding) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB)
+                                           .Authorization(TAG_PADDING, KM_PAD_NONE)));
+
+    // Try various message lengths; all should fail.
+    for (size_t i = 0; i < 32; ++i) {
+        AuthorizationSet begin_params(client_params());
+        begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
+        begin_params.push_back(TAG_PADDING, KM_PAD_PKCS7);
+        EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PADDING_MODE,
+                  BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+    }
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB)
+                                           .Authorization(TAG_PADDING, KM_PAD_PKCS7)));
+
+    string message = "a";
+    string ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_PKCS7);
+    EXPECT_EQ(16U, ciphertext.size());
+    EXPECT_NE(ciphertext, message);
+    ++ciphertext[ciphertext.size() / 2];
+
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
+    begin_params.push_back(TAG_PADDING, KM_PAD_PKCS7);
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+    string plaintext;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext, &plaintext, &input_consumed));
+    EXPECT_EQ(ciphertext.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, FinishOperation(&plaintext));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesCtrRoundTripSuccess) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR)
+                                           .Padding(KM_PAD_NONE)));
+    string message = "123";
+    string iv1;
+    string ciphertext1 = EncryptMessage(message, KM_MODE_CTR, KM_PAD_NONE, &iv1);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+    EXPECT_EQ(16U, iv1.size());
+
+    string iv2;
+    string ciphertext2 = EncryptMessage(message, KM_MODE_CTR, KM_PAD_NONE, &iv2);
+    EXPECT_EQ(message.size(), ciphertext2.size());
+    EXPECT_EQ(16U, iv2.size());
+
+    // IVs should be random, so ciphertexts should differ.
+    EXPECT_NE(iv1, iv2);
+    EXPECT_NE(ciphertext1, ciphertext2);
+
+    string plaintext = DecryptMessage(ciphertext1, KM_MODE_CTR, KM_PAD_NONE, iv1);
+    EXPECT_EQ(message, plaintext);
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesCtrIncremental) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR)
+                                           .Padding(KM_PAD_NONE)));
+
+    int increment = 15;
+    string message(239, 'a');
+    AuthorizationSet input_params(client_params());
+    input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR);
+    input_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    AuthorizationSet output_params;
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, input_params, &output_params));
+
+    string ciphertext;
+    size_t input_consumed;
+    for (size_t i = 0; i < message.size(); i += increment)
+        EXPECT_EQ(KM_ERROR_OK,
+                  UpdateOperation(message.substr(i, increment), &ciphertext, &input_consumed));
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+    EXPECT_EQ(message.size(), ciphertext.size());
+
+    // Move TAG_NONCE into input_params
+    input_params.Reinitialize(output_params);
+    input_params.push_back(client_params());
+    input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR);
+    input_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    output_params.Clear();
+
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, input_params, &output_params));
+    string plaintext;
+    for (size_t i = 0; i < ciphertext.size(); i += increment)
+        EXPECT_EQ(KM_ERROR_OK,
+                  UpdateOperation(ciphertext.substr(i, increment), &plaintext, &input_consumed));
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
+    EXPECT_EQ(ciphertext.size(), plaintext.size());
+    EXPECT_EQ(message, plaintext);
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+struct AesCtrSp80038aTestVector {
+    const char* key;
+    const char* nonce;
+    const char* plaintext;
+    const char* ciphertext;
+};
+
+// These test vectors are taken from
+// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, section F.5.
+static const AesCtrSp80038aTestVector kAesCtrSp80038aTestVectors[] = {
+    // AES-128
+    {
+        "2b7e151628aed2a6abf7158809cf4f3c", "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+        "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+        "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff"
+        "5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee",
+    },
+    // AES-192
+    {
+        "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+        "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+        "1abc932417521ca24f2b0459fe7e6e0b090339ec0aa6faefd5ccc2c6f4ce8e94"
+        "1e36b26bd1ebc670d1bd1d665620abf74f78a7f6d29809585a97daec58c6b050",
+    },
+    // AES-256
+    {
+        "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
+        "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+        "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+        "601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c5"
+        "2b0930daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6",
+    },
+};
+
+TEST_P(EncryptionOperationsTest, AesCtrSp80038aTestVector) {
+    for (size_t i = 0; i < 3; i++) {
+        const AesCtrSp80038aTestVector& test(kAesCtrSp80038aTestVectors[i]);
+        const string key = hex2str(test.key);
+        const string nonce = hex2str(test.nonce);
+        const string plaintext = hex2str(test.plaintext);
+        const string ciphertext = hex2str(test.ciphertext);
+        CheckAesCtrTestVector(key, nonce, plaintext, ciphertext);
+    }
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesCtrInvalidPaddingMode) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR)
+                                           .Authorization(TAG_PADDING, KM_PAD_PKCS7)));
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR);
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PADDING_MODE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesCtrInvalidCallerNonce) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR)
+                                           .Authorization(TAG_CALLER_NONCE)
+                                           .Padding(KM_PAD_NONE)));
+
+    AuthorizationSet input_params(client_params());
+    input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR);
+    input_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    input_params.push_back(TAG_NONCE, "123", 3);
+    EXPECT_EQ(KM_ERROR_INVALID_NONCE, BeginOperation(KM_PURPOSE_ENCRYPT, input_params));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesCbcRoundTripSuccess) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC)
+                                           .Padding(KM_PAD_NONE)));
+    // Two-block message.
+    string message = "12345678901234567890123456789012";
+    string iv1;
+    string ciphertext1 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv1);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+
+    string iv2;
+    string ciphertext2 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv2);
+    EXPECT_EQ(message.size(), ciphertext2.size());
+
+    // IVs should be random, so ciphertexts should differ.
+    EXPECT_NE(iv1, iv2);
+    EXPECT_NE(ciphertext1, ciphertext2);
+
+    string plaintext = DecryptMessage(ciphertext1, KM_MODE_CBC, KM_PAD_NONE, iv1);
+    EXPECT_EQ(message, plaintext);
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesCallerNonce) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC)
+                                           .Authorization(TAG_CALLER_NONCE)
+                                           .Padding(KM_PAD_NONE)));
+    string message = "12345678901234567890123456789012";
+    string iv1;
+    // Don't specify nonce, should get a random one.
+    string ciphertext1 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv1);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+    EXPECT_EQ(16U, iv1.size());
+
+    string plaintext = DecryptMessage(ciphertext1, KM_MODE_CBC, KM_PAD_NONE, iv1);
+    EXPECT_EQ(message, plaintext);
+
+    // Now specify a nonce, should also work.
+    AuthorizationSet input_params(client_params());
+    AuthorizationSet update_params;
+    AuthorizationSet output_params;
+    input_params.push_back(TAG_NONCE, "abcdefghijklmnop", 16);
+    input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC);
+    input_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    string ciphertext2 =
+        ProcessMessage(KM_PURPOSE_ENCRYPT, message, input_params, update_params, &output_params);
+
+    // Decrypt with correct nonce.
+    plaintext = ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext2, input_params, update_params,
+                               &output_params);
+    EXPECT_EQ(message, plaintext);
+
+    // Now try with wrong nonce.
+    input_params.Reinitialize(client_params());
+    input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC);
+    input_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    input_params.push_back(TAG_NONCE, "aaaaaaaaaaaaaaaa", 16);
+    plaintext = ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext2, input_params, update_params,
+                               &output_params);
+    EXPECT_NE(message, plaintext);
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesCallerNonceProhibited) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC)
+                                           .Padding(KM_PAD_NONE)));
+
+    string message = "12345678901234567890123456789012";
+    string iv1;
+    // Don't specify nonce, should get a random one.
+    string ciphertext1 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv1);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+    EXPECT_EQ(16U, iv1.size());
+
+    string plaintext = DecryptMessage(ciphertext1, KM_MODE_CBC, KM_PAD_NONE, iv1);
+    EXPECT_EQ(message, plaintext);
+
+    // Now specify a nonce, should fail.
+    AuthorizationSet input_params(client_params());
+    AuthorizationSet update_params;
+    AuthorizationSet output_params;
+    input_params.push_back(TAG_NONCE, "abcdefghijklmnop", 16);
+    input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC);
+    input_params.push_back(TAG_PADDING, KM_PAD_NONE);
+
+    EXPECT_EQ(KM_ERROR_CALLER_NONCE_PROHIBITED,
+              BeginOperation(KM_PURPOSE_ENCRYPT, input_params, &output_params));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesCbcIncrementalNoPadding) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC)
+                                           .Padding(KM_PAD_NONE)));
+
+    int increment = 15;
+    string message(240, 'a');
+    AuthorizationSet input_params(client_params());
+    input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC);
+    input_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    AuthorizationSet output_params;
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, input_params, &output_params));
+
+    string ciphertext;
+    size_t input_consumed;
+    for (size_t i = 0; i < message.size(); i += increment)
+        EXPECT_EQ(KM_ERROR_OK,
+                  UpdateOperation(message.substr(i, increment), &ciphertext, &input_consumed));
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+    EXPECT_EQ(message.size(), ciphertext.size());
+
+    // Move TAG_NONCE into input_params
+    input_params.Reinitialize(output_params);
+    input_params.push_back(client_params());
+    input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC);
+    input_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    output_params.Clear();
+
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, input_params, &output_params));
+    string plaintext;
+    for (size_t i = 0; i < ciphertext.size(); i += increment)
+        EXPECT_EQ(KM_ERROR_OK,
+                  UpdateOperation(ciphertext.substr(i, increment), &plaintext, &input_consumed));
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
+    EXPECT_EQ(ciphertext.size(), plaintext.size());
+    EXPECT_EQ(message, plaintext);
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesCbcPkcs7Padding) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC)
+                                           .Authorization(TAG_PADDING, KM_PAD_PKCS7)));
+
+    // Try various message lengths; all should work.
+    for (size_t i = 0; i < 32; ++i) {
+        string message(i, 'a');
+        string iv;
+        string ciphertext = EncryptMessage(message, KM_MODE_CBC, KM_PAD_PKCS7, &iv);
+        EXPECT_EQ(i + 16 - (i % 16), ciphertext.size());
+        string plaintext = DecryptMessage(ciphertext, KM_MODE_CBC, KM_PAD_PKCS7, iv);
+        EXPECT_EQ(message, plaintext);
+    }
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesGcmRoundTripSuccess) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+                                           .Authorization(TAG_PADDING, KM_PAD_NONE)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    string aad = "foobar";
+    string message = "123456789012345678901234567890123456";
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    begin_params.push_back(TAG_MAC_LENGTH, 128);
+
+    AuthorizationSet update_params;
+    update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
+    string ciphertext;
+    size_t input_consumed;
+    AuthorizationSet update_out_params;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext,
+                                           &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+
+    // Grab nonce
+    EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
+    begin_params.push_back(begin_out_params);
+
+    // Decrypt.
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+    string plaintext;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params,
+                                           &plaintext, &input_consumed));
+    EXPECT_EQ(ciphertext.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
+
+    EXPECT_EQ(message, plaintext);
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesGcmTooShortTag) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+                                           .Authorization(TAG_PADDING, KM_PAD_NONE)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    string aad = "foobar";
+    string message = "123456789012345678901234567890123456";
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    begin_params.push_back(TAG_MAC_LENGTH, 96);
+
+    AuthorizationSet update_params;
+    update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(KM_ERROR_INVALID_MAC_LENGTH,
+              BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+                                           .Authorization(TAG_PADDING, KM_PAD_NONE)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    string aad = "foobar";
+    string message = "123456789012345678901234567890123456";
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    begin_params.push_back(TAG_MAC_LENGTH, 128);
+
+    AuthorizationSet update_params;
+    update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
+    string ciphertext;
+    size_t input_consumed;
+    AuthorizationSet update_out_params;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext,
+                                           &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+
+    // Grab nonce
+    EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
+    begin_params.Reinitialize(client_params());
+    begin_params.push_back(begin_out_params);
+    begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    begin_params.push_back(TAG_MAC_LENGTH, 96);
+
+    // Decrypt.
+    EXPECT_EQ(KM_ERROR_INVALID_MAC_LENGTH, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesGcmCorruptKey) {
+    uint8_t nonce[] = {
+        0xb7, 0x94, 0x37, 0xae, 0x08, 0xff, 0x35, 0x5d, 0x7d, 0x8a, 0x4d, 0x0f,
+    };
+    uint8_t ciphertext[] = {
+        0xb3, 0xf6, 0x79, 0x9e, 0x8f, 0x93, 0x26, 0xf2, 0xdf, 0x1e, 0x80, 0xfc, 0xd2, 0xcb, 0x16,
+        0xd7, 0x8c, 0x9d, 0xc7, 0xcc, 0x14, 0xbb, 0x67, 0x78, 0x62, 0xdc, 0x6c, 0x63, 0x9b, 0x3a,
+        0x63, 0x38, 0xd2, 0x4b, 0x31, 0x2d, 0x39, 0x89, 0xe5, 0x92, 0x0b, 0x5d, 0xbf, 0xc9, 0x76,
+        0x76, 0x5e, 0xfb, 0xfe, 0x57, 0xbb, 0x38, 0x59, 0x40, 0xa7, 0xa4, 0x3b, 0xdf, 0x05, 0xbd,
+        0xda, 0xe3, 0xc9, 0xd6, 0xa2, 0xfb, 0xbd, 0xfc, 0xc0, 0xcb, 0xa0,
+    };
+    string ciphertext_str(reinterpret_cast<char*>(ciphertext), sizeof(ciphertext));
+
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    begin_params.push_back(TAG_MAC_LENGTH, 128);
+    begin_params.push_back(TAG_NONCE, nonce, sizeof(nonce));
+
+    string plaintext;
+    size_t input_consumed;
+
+    // Import correct key and decrypt
+    uint8_t good_key[] = {
+        0xba, 0x76, 0x35, 0x4f, 0x0a, 0xed, 0x6e, 0x8d,
+        0x91, 0xf4, 0x5c, 0x4f, 0xf5, 0xa0, 0x62, 0xdb,
+    };
+    string good_key_str(reinterpret_cast<char*>(good_key), sizeof(good_key));
+    ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder()
+                                         .AesEncryptionKey(128)
+                                         .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+                                         .Authorization(TAG_PADDING, KM_PAD_NONE)
+                                         .Authorization(TAG_CALLER_NONCE)
+                                         .Authorization(TAG_MIN_MAC_LENGTH, 128),
+                                     KM_KEY_FORMAT_RAW, good_key_str));
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext_str, &plaintext, &input_consumed));
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
+
+    // Import bad key and decrypt
+    uint8_t bad_key[] = {
+        0xbb, 0x76, 0x35, 0x4f, 0x0a, 0xed, 0x6e, 0x8d,
+        0x91, 0xf4, 0x5c, 0x4f, 0xf5, 0xa0, 0x62, 0xdb,
+    };
+    string bad_key_str(reinterpret_cast<char*>(bad_key), sizeof(bad_key));
+    ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder()
+                                         .AesEncryptionKey(128)
+                                         .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+                                         .Authorization(TAG_PADDING, KM_PAD_NONE)
+                                         .Authorization(TAG_MIN_MAC_LENGTH, 128),
+                                     KM_KEY_FORMAT_RAW, bad_key_str));
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext_str, &plaintext, &input_consumed));
+    EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(&plaintext));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesGcmAadNoData) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+                                           .Authorization(TAG_PADDING, KM_PAD_NONE)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    string aad = "123456789012345678";
+    string empty_message;
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    begin_params.push_back(TAG_MAC_LENGTH, 128);
+
+    AuthorizationSet update_params;
+    update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
+    string ciphertext;
+    size_t input_consumed;
+    AuthorizationSet update_out_params;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, empty_message, &update_out_params,
+                                           &ciphertext, &input_consumed));
+    EXPECT_EQ(0U, input_consumed);
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+
+    // Grab nonce
+    EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
+    begin_params.push_back(begin_out_params);
+
+    // Decrypt.
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+    string plaintext;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params,
+                                           &plaintext, &input_consumed));
+    EXPECT_EQ(ciphertext.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
+
+    EXPECT_EQ(empty_message, plaintext);
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesGcmIncremental) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+                                           .Authorization(TAG_PADDING, KM_PAD_NONE)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    begin_params.push_back(TAG_MAC_LENGTH, 128);
+
+    AuthorizationSet update_params;
+    update_params.push_back(TAG_ASSOCIATED_DATA, "b", 1);
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
+    string ciphertext;
+    size_t input_consumed;
+    AuthorizationSet update_out_params;
+
+    // Send AAD, incrementally
+    for (int i = 0; i < 1000; ++i) {
+        EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, "", &update_out_params, &ciphertext,
+                                               &input_consumed));
+        EXPECT_EQ(0U, input_consumed);
+        EXPECT_EQ(0U, ciphertext.size());
+    }
+
+    // Now send data, incrementally, no data.
+    AuthorizationSet empty_params;
+    for (int i = 0; i < 1000; ++i) {
+        EXPECT_EQ(KM_ERROR_OK, UpdateOperation(empty_params, "a", &update_out_params, &ciphertext,
+                                               &input_consumed));
+        EXPECT_EQ(1U, input_consumed);
+    }
+    EXPECT_EQ(1000U, ciphertext.size());
+
+    // And finish.
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+    EXPECT_EQ(1016U, ciphertext.size());
+
+    // Grab nonce
+    EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
+    begin_params.push_back(begin_out_params);
+
+    // Decrypt.
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+    string plaintext;
+
+    // Send AAD, incrementally, no data
+    for (int i = 0; i < 1000; ++i) {
+        EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, "", &update_out_params, &plaintext,
+                                               &input_consumed));
+        EXPECT_EQ(0U, input_consumed);
+        EXPECT_EQ(0U, plaintext.size());
+    }
+
+    // Now send data, incrementally.
+    for (size_t i = 0; i < ciphertext.length(); ++i) {
+        EXPECT_EQ(KM_ERROR_OK, UpdateOperation(empty_params, string(ciphertext.data() + i, 1),
+                                               &update_out_params, &plaintext, &input_consumed));
+        EXPECT_EQ(1U, input_consumed);
+    }
+    EXPECT_EQ(1000U, plaintext.size());
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesGcmMultiPartAad) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+                                           .Authorization(TAG_PADDING, KM_PAD_NONE)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    string message = "123456789012345678901234567890123456";
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    begin_params.push_back(TAG_MAC_LENGTH, 128);
+    AuthorizationSet begin_out_params;
+
+    AuthorizationSet update_params;
+    update_params.push_back(TAG_ASSOCIATED_DATA, "foo", 3);
+
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
+
+    // No data, AAD only.
+    string ciphertext;
+    size_t input_consumed;
+    AuthorizationSet update_out_params;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, "" /* message */, &update_out_params,
+                                           &ciphertext, &input_consumed));
+    EXPECT_EQ(0U, input_consumed);
+
+    // AAD and data.
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext,
+                                           &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+
+    // Grab nonce.
+    EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
+    begin_params.push_back(begin_out_params);
+
+    // Decrypt
+    update_params.Clear();
+    update_params.push_back(TAG_ASSOCIATED_DATA, "foofoo", 6);
+
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+    string plaintext;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params,
+                                           &plaintext, &input_consumed));
+    EXPECT_EQ(ciphertext.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
+
+    EXPECT_EQ(message, plaintext);
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesGcmBadAad) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+                                           .Authorization(TAG_PADDING, KM_PAD_NONE)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    string message = "12345678901234567890123456789012";
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    begin_params.push_back(TAG_MAC_LENGTH, 128);
+
+    AuthorizationSet update_params;
+    update_params.push_back(TAG_ASSOCIATED_DATA, "foobar", 6);
+
+    AuthorizationSet finish_params;
+    AuthorizationSet finish_out_params;
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
+    AuthorizationSet update_out_params;
+    string ciphertext;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext,
+                                           &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+
+    // Grab nonce
+    EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
+    begin_params.push_back(begin_out_params);
+
+    update_params.Clear();
+    update_params.push_back(TAG_ASSOCIATED_DATA, "barfoo" /* Wrong AAD */, 6);
+
+    // Decrypt.
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params, &begin_out_params));
+    string plaintext;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params,
+                                           &plaintext, &input_consumed));
+    EXPECT_EQ(ciphertext.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(&plaintext));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesGcmWrongNonce) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+                                           .Authorization(TAG_PADDING, KM_PAD_NONE)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    string message = "12345678901234567890123456789012";
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    begin_params.push_back(TAG_MAC_LENGTH, 128);
+
+    AuthorizationSet update_params;
+    update_params.push_back(TAG_ASSOCIATED_DATA, "foobar", 6);
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
+    AuthorizationSet update_out_params;
+    string ciphertext;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext,
+                                           &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+
+    begin_params.push_back(TAG_NONCE, "123456789012", 12);
+
+    // Decrypt
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params, &begin_out_params));
+    string plaintext;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params,
+                                           &plaintext, &input_consumed));
+    EXPECT_EQ(ciphertext.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(&plaintext));
+
+    // With wrong nonce, should have gotten garbage plaintext.
+    EXPECT_NE(message, plaintext);
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesGcmCorruptTag) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+                                           .Authorization(TAG_PADDING, KM_PAD_NONE)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    string aad = "foobar";
+    string message = "123456789012345678901234567890123456";
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    begin_params.push_back(TAG_MAC_LENGTH, 128);
+    AuthorizationSet begin_out_params;
+
+    AuthorizationSet update_params;
+    update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+    // Encrypt
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
+    AuthorizationSet update_out_params;
+    string ciphertext;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext,
+                                           &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+
+    // Corrupt tag
+    (*ciphertext.rbegin())++;
+
+    // Grab nonce.
+    EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
+    begin_params.push_back(begin_out_params);
+
+    // Decrypt.
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params, &begin_out_params));
+    string plaintext;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params,
+                                           &plaintext, &input_consumed));
+    EXPECT_EQ(ciphertext.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(&plaintext));
+
+    EXPECT_EQ(message, plaintext);
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+typedef Keymaster2Test MaxOperationsTest;
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, MaxOperationsTest, test_params);
+
+TEST_P(MaxOperationsTest, TestLimit) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .EcbMode()
+                                           .Authorization(TAG_PADDING, KM_PAD_NONE)
+                                           .Authorization(TAG_MAX_USES_PER_BOOT, 3)));
+
+    string message = "1234567890123456";
+    string ciphertext1 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
+    string ciphertext2 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
+    string ciphertext3 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
+
+    // Fourth time should fail.
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    EXPECT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(MaxOperationsTest, TestAbort) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .EcbMode()
+                                           .Authorization(TAG_PADDING, KM_PAD_NONE)
+                                           .Authorization(TAG_MAX_USES_PER_BOOT, 3)));
+
+    string message = "1234567890123456";
+    string ciphertext1 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
+    string ciphertext2 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
+    string ciphertext3 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
+
+    // Fourth time should fail.
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    EXPECT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+typedef Keymaster2Test AddEntropyTest;
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, AddEntropyTest, test_params);
+
+TEST_P(AddEntropyTest, AddEntropy) {
+    // There's no obvious way to test that entropy is actually added, but we can test that the API
+    // doesn't blow up or return an error.
+    EXPECT_EQ(KM_ERROR_OK,
+              device()->add_rng_entropy(device(), reinterpret_cast<const uint8_t*>("foo"), 3));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+typedef Keymaster2Test Keymaster0AdapterTest;
+INSTANTIATE_TEST_CASE_P(
+    AndroidKeymasterTest, Keymaster0AdapterTest,
+    ::testing::Values(
+        InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(true /* support_ec */)),
+        InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(false /* support_ec */))));
+
+TEST_P(Keymaster0AdapterTest, OldSoftwareKeymaster1RsaBlob) {
+    // Load and use an old-style Keymaster1 software key blob.  These blobs contain OCB-encrypted
+    // key data.
+    string km1_sw = read_file("km1_sw_rsa_512.blob");
+    EXPECT_EQ(486U, km1_sw.length());
+
+    uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km1_sw.length()));
+    memcpy(key_data, km1_sw.data(), km1_sw.length());
+    set_key_blob(key_data, km1_sw.length());
+
+    string message(64, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(Keymaster0AdapterTest, UnversionedSoftwareKeymaster1RsaBlob) {
+    // Load and use an old-style Keymaster1 software key blob, without the version byte.  These
+    // blobs contain OCB-encrypted key data.
+    string km1_sw = read_file("km1_sw_rsa_512_unversioned.blob");
+    EXPECT_EQ(477U, km1_sw.length());
+
+    uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km1_sw.length()));
+    memcpy(key_data, km1_sw.data(), km1_sw.length());
+    set_key_blob(key_data, km1_sw.length());
+
+    string message(64, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(Keymaster0AdapterTest, OldSoftwareKeymaster1EcdsaBlob) {
+    // Load and use an old-style Keymaster1 software key blob.  These blobs contain OCB-encrypted
+    // key data.
+    string km1_sw = read_file("km1_sw_ecdsa_256.blob");
+    EXPECT_EQ(270U, km1_sw.length());
+
+    uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km1_sw.length()));
+    memcpy(key_data, km1_sw.data(), km1_sw.length());
+    set_key_blob(key_data, km1_sw.length());
+
+    string message(32, static_cast<char>(0xFF));
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+struct Malloc_Delete {
+    void operator()(void* p) { free(p); }
+};
+
+TEST_P(Keymaster0AdapterTest, OldSoftwareKeymaster0RsaBlob) {
+    // Load and use an old softkeymaster blob.  These blobs contain PKCS#8 key data.
+    string km0_sw = read_file("km0_sw_rsa_512.blob");
+    EXPECT_EQ(333U, km0_sw.length());
+
+    uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km0_sw.length()));
+    memcpy(key_data, km0_sw.data(), km0_sw.length());
+    set_key_blob(key_data, km0_sw.length());
+
+    string message(64, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(Keymaster0AdapterTest, OldSwKeymaster0RsaBlobGetCharacteristics) {
+    // Load and use an old softkeymaster blob.  These blobs contain PKCS#8 key data.
+    string km0_sw = read_file("km0_sw_rsa_512.blob");
+    EXPECT_EQ(333U, km0_sw.length());
+
+    uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km0_sw.length()));
+    memcpy(key_data, km0_sw.data(), km0_sw.length());
+    set_key_blob(key_data, km0_sw.length());
+
+    EXPECT_EQ(KM_ERROR_OK, GetCharacteristics());
+    EXPECT_TRUE(contains(sw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_RSA));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_KEY_SIZE, 512));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_RSA_PUBLIC_EXPONENT, 3));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_DIGEST, KM_DIGEST_NONE));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_PADDING, KM_PAD_NONE));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_SIGN));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_VERIFY));
+    EXPECT_TRUE(sw_enforced().GetTagValue(TAG_ALL_USERS));
+    EXPECT_TRUE(sw_enforced().GetTagValue(TAG_NO_AUTH_REQUIRED));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(Keymaster0AdapterTest, OldHwKeymaster0RsaBlob) {
+    // Load and use an old softkeymaster blob.  These blobs contain PKCS#8 key data.
+    string km0_sw = read_file("km0_sw_rsa_512.blob");
+    EXPECT_EQ(333U, km0_sw.length());
+
+    // The keymaster0 wrapper swaps the old softkeymaster leading 'P' for a 'Q' to make the key not
+    // be recognized as a software key.  Do the same here to pretend this is a hardware key.
+    EXPECT_EQ('P', km0_sw[0]);
+    km0_sw[0] = 'Q';
+
+    uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km0_sw.length()));
+    memcpy(key_data, km0_sw.data(), km0_sw.length());
+    set_key_blob(key_data, km0_sw.length());
+
+    string message(64, 'a');
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
+    VerifyMessage(message, signature, KM_DIGEST_NONE, KM_PAD_NONE);
+
+    EXPECT_EQ(5, GetParam()->keymaster0_calls());
+}
+
+TEST_P(Keymaster0AdapterTest, OldHwKeymaster0RsaBlobGetCharacteristics) {
+    // Load and use an old softkeymaster blob.  These blobs contain PKCS#8 key data.
+    string km0_sw = read_file("km0_sw_rsa_512.blob");
+    EXPECT_EQ(333U, km0_sw.length());
+
+    // The keymaster0 wrapper swaps the old softkeymaster leading 'P' for a 'Q' to make the key not
+    // be recognized as a software key.  Do the same here to pretend this is a hardware key.
+    EXPECT_EQ('P', km0_sw[0]);
+    km0_sw[0] = 'Q';
+
+    uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km0_sw.length()));
+    memcpy(key_data, km0_sw.data(), km0_sw.length());
+    set_key_blob(key_data, km0_sw.length());
+
+    EXPECT_EQ(KM_ERROR_OK, GetCharacteristics());
+    EXPECT_TRUE(contains(hw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_RSA));
+    EXPECT_TRUE(contains(hw_enforced(), TAG_KEY_SIZE, 512));
+    EXPECT_TRUE(contains(hw_enforced(), TAG_RSA_PUBLIC_EXPONENT, 3));
+    EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_NONE));
+    EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_MD5));
+    EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA1));
+    EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA_2_224));
+    EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA_2_256));
+    EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA_2_384));
+    EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA_2_512));
+    EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_NONE));
+    EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_ENCRYPT));
+    EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN));
+    EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_RSA_OAEP));
+    EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_RSA_PSS));
+    EXPECT_EQ(15U, hw_enforced().size());
+
+    EXPECT_TRUE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_SIGN));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_VERIFY));
+    EXPECT_TRUE(sw_enforced().GetTagValue(TAG_ALL_USERS));
+    EXPECT_TRUE(sw_enforced().GetTagValue(TAG_NO_AUTH_REQUIRED));
+
+    EXPECT_FALSE(contains(sw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_RSA));
+    EXPECT_FALSE(contains(sw_enforced(), TAG_KEY_SIZE, 512));
+    EXPECT_FALSE(contains(sw_enforced(), TAG_RSA_PUBLIC_EXPONENT, 3));
+    EXPECT_FALSE(contains(sw_enforced(), TAG_DIGEST, KM_DIGEST_NONE));
+    EXPECT_FALSE(contains(sw_enforced(), TAG_PADDING, KM_PAD_NONE));
+
+    EXPECT_EQ(1, GetParam()->keymaster0_calls());
+}
+
+typedef Keymaster2Test AttestationTest;
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, AttestationTest, test_params);
+
+static X509* parse_cert_blob(const keymaster_blob_t& blob) {
+    const uint8_t* p = blob.data;
+    return d2i_X509(nullptr, &p, blob.data_length);
+}
+
+static bool verify_chain(const keymaster_cert_chain_t& chain) {
+    for (size_t i = 0; i < chain.entry_count - 1; ++i) {
+        keymaster_blob_t& key_cert_blob = chain.entries[i];
+        keymaster_blob_t& signing_cert_blob = chain.entries[i + 1];
+
+        X509_Ptr key_cert(parse_cert_blob(key_cert_blob));
+        X509_Ptr signing_cert(parse_cert_blob(signing_cert_blob));
+        EXPECT_TRUE(!!key_cert.get() && !!signing_cert.get());
+        if (!key_cert.get() || !signing_cert.get())
+            return false;
+
+        EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
+        EXPECT_TRUE(!!signing_pubkey.get());
+        if (!signing_pubkey.get())
+            return false;
+
+        EXPECT_EQ(1, X509_verify(key_cert.get(), signing_pubkey.get()))
+            << "Verification of certificate " << i << " failed";
+    }
+
+    return true;
+}
+
+// Extract attestation record from cert. Returned object is still part of cert; don't free it
+// separately.
+static ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
+    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
+    EXPECT_TRUE(!!oid.get());
+    if (!oid.get())
+        return nullptr;
+
+    int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
+    EXPECT_NE(-1, location);
+    if (location == -1)
+        return nullptr;
+
+    X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
+    EXPECT_TRUE(!!attest_rec_ext);
+    if (!attest_rec_ext)
+        return nullptr;
+
+    ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
+    EXPECT_TRUE(!!attest_rec);
+    return attest_rec;
+}
+
+static bool verify_attestation_record(AuthorizationSet expected_sw_enforced,
+                                      AuthorizationSet expected_tee_enforced,
+                                      const keymaster_blob_t& attestation_cert) {
+
+    X509_Ptr cert(parse_cert_blob(attestation_cert));
+    EXPECT_TRUE(!!cert.get());
+    if (!cert.get())
+        return false;
+
+    ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
+    EXPECT_TRUE(!!attest_rec);
+    if (!attest_rec)
+        return false;
+
+    AuthorizationSet att_sw_enforced;
+    AuthorizationSet att_tee_enforced;
+    EXPECT_EQ(KM_ERROR_OK, parse_attestation_record(attest_rec->data, attest_rec->length,
+                                                    &att_sw_enforced, &att_tee_enforced));
+
+    // Add TAG_USER_ID to the attestation sw-enforced list, because user IDs are not included in
+    // attestations, since they're meaningless off-device.
+    uint32_t user_id;
+    if (expected_sw_enforced.GetTagValue(TAG_USER_ID, &user_id))
+        att_sw_enforced.push_back(TAG_USER_ID, user_id);
+    if (expected_tee_enforced.GetTagValue(TAG_USER_ID, &user_id))
+        att_tee_enforced.push_back(TAG_USER_ID, user_id);
+
+    att_sw_enforced.Sort();
+    expected_sw_enforced.Sort();
+    EXPECT_EQ(expected_sw_enforced, att_sw_enforced);
+
+    att_tee_enforced.Sort();
+    expected_tee_enforced.Sort();
+    EXPECT_EQ(expected_tee_enforced, att_tee_enforced);
+
+    return true;
+}
+
+TEST_P(AttestationTest, RsaSignedWithRsa) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(256, 3)
+                                           .Digest(KM_DIGEST_NONE)
+                                           .Padding(KM_PAD_NONE)));
+
+    keymaster_cert_chain_t cert_chain;
+    EXPECT_EQ(KM_ERROR_OK, AttestKey(KM_ALGORITHM_RSA, &cert_chain));
+    EXPECT_EQ(3U, cert_chain.entry_count);
+    EXPECT_TRUE(verify_chain(cert_chain));
+    EXPECT_TRUE(verify_attestation_record(sw_enforced(), hw_enforced(), cert_chain.entries[0]));
+
+    keymaster_free_cert_chain(&cert_chain);
+}
+
+TEST_P(AttestationTest, RsaSignedWithEc) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaSigningKey(256, 3)
+                                           .Digest(KM_DIGEST_NONE)
+                                           .Padding(KM_PAD_NONE)));
+
+    keymaster_cert_chain_t cert_chain;
+    EXPECT_EQ(KM_ERROR_OK, AttestKey(KM_ALGORITHM_EC, &cert_chain));
+    EXPECT_EQ(3U, cert_chain.entry_count);
+    EXPECT_TRUE(verify_chain(cert_chain));
+    EXPECT_TRUE(verify_attestation_record(sw_enforced(), hw_enforced(), cert_chain.entries[0]));
+
+    keymaster_free_cert_chain(&cert_chain);
+}
+
+TEST(SoftKeymasterWrapperTest, CheckKeymaster2Device) {
+    // Make a good fake device, and wrap it.
+    SoftKeymasterDevice* good_fake(new SoftKeymasterDevice(new TestKeymasterContext));
+
+    // Wrap it and check it.
+    SoftKeymasterDevice* good_fake_wrapper(new SoftKeymasterDevice(new TestKeymasterContext));
+    good_fake_wrapper->SetHardwareDevice(good_fake->keymaster_device());
+    EXPECT_TRUE(good_fake_wrapper->Keymaster1DeviceIsGood());
+
+    // Close and clean up wrapper and wrapped
+    good_fake_wrapper->keymaster_device()->common.close(good_fake_wrapper->hw_device());
+
+    // Make a "bad" (doesn't support all digests) device;
+    keymaster1_device_t* sha256_only_fake = make_device_sha256_only(
+        (new SoftKeymasterDevice(new TestKeymasterContext("256")))->keymaster_device());
+
+    // Wrap it and check it.
+    SoftKeymasterDevice* sha256_only_fake_wrapper(
+        (new SoftKeymasterDevice(new TestKeymasterContext)));
+    sha256_only_fake_wrapper->SetHardwareDevice(sha256_only_fake);
+    EXPECT_FALSE(sha256_only_fake_wrapper->Keymaster1DeviceIsGood());
+
+    // Close and clean up wrapper and wrapped
+    sha256_only_fake_wrapper->keymaster_device()->common.close(
+        sha256_only_fake_wrapper->hw_device());
+}
+
+}  // namespace test
+}  // namespace keymaster
diff --git a/keymaster/android_keymaster_test_utils.cpp b/keymaster/android_keymaster_test_utils.cpp
new file mode 100644
index 0000000..346421a
--- /dev/null
+++ b/keymaster/android_keymaster_test_utils.cpp
@@ -0,0 +1,890 @@
+/*
+ * 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 "android_keymaster_test_utils.h"
+
+#include <algorithm>
+
+#include <openssl/rand.h>
+
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/android_keymaster_utils.h>
+
+using std::copy_if;
+using std::find_if;
+using std::is_permutation;
+using std::ostream;
+using std::string;
+using std::vector;
+
+#ifndef KEYMASTER_NAME_TAGS
+#error Keymaster test code requires that KEYMASTER_NAME_TAGS is defined
+#endif
+
+std::ostream& operator<<(std::ostream& os, const keymaster_key_param_t& param) {
+    os << "Tag: " << keymaster::StringifyTag(param.tag);
+    switch (keymaster_tag_get_type(param.tag)) {
+    case KM_INVALID:
+        os << " Invalid";
+        break;
+    case KM_UINT_REP:
+        os << " (Rep)";
+    /* Falls through */
+    case KM_UINT:
+        os << " Int: " << param.integer;
+        break;
+    case KM_ENUM_REP:
+        os << " (Rep)";
+    /* Falls through */
+    case KM_ENUM:
+        os << " Enum: " << param.enumerated;
+        break;
+    case KM_ULONG_REP:
+        os << " (Rep)";
+    /* Falls through */
+    case KM_ULONG:
+        os << " Long: " << param.long_integer;
+        break;
+    case KM_DATE:
+        os << " Date: " << param.date_time;
+        break;
+    case KM_BOOL:
+        os << " Bool: " << param.boolean;
+        break;
+    case KM_BIGNUM:
+        os << " Bignum: ";
+        if (!param.blob.data)
+            os << "(null)";
+        else
+            for (size_t i = 0; i < param.blob.data_length; ++i)
+                os << std::hex << std::setw(2) << static_cast<int>(param.blob.data[i]) << std::dec;
+        break;
+    case KM_BYTES:
+        os << " Bytes: ";
+        if (!param.blob.data)
+            os << "(null)";
+        else
+            for (size_t i = 0; i < param.blob.data_length; ++i)
+                os << std::hex << std::setw(2) << static_cast<int>(param.blob.data[i]) << std::dec;
+        break;
+    }
+    return os;
+}
+
+bool operator==(const keymaster_key_param_t& a, const keymaster_key_param_t& b) {
+    if (a.tag != b.tag) {
+        return false;
+    }
+
+    switch (keymaster_tag_get_type(a.tag)) {
+    case KM_INVALID:
+        return true;
+    case KM_UINT_REP:
+    case KM_UINT:
+        return a.integer == b.integer;
+    case KM_ENUM_REP:
+    case KM_ENUM:
+        return a.enumerated == b.enumerated;
+    case KM_ULONG:
+    case KM_ULONG_REP:
+        return a.long_integer == b.long_integer;
+    case KM_DATE:
+        return a.date_time == b.date_time;
+    case KM_BOOL:
+        return a.boolean == b.boolean;
+    case KM_BIGNUM:
+    case KM_BYTES:
+        if ((a.blob.data == NULL || b.blob.data == NULL) && a.blob.data != b.blob.data)
+            return false;
+        return a.blob.data_length == b.blob.data_length &&
+               (memcmp(a.blob.data, b.blob.data, a.blob.data_length) == 0);
+    }
+
+    return false;
+}
+
+static char hex_value[256] = {
+    0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,
+    0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,
+    0, 1,  2,  3,  4,  5,  6,  7, 8, 9, 0, 0, 0, 0, 0, 0,  // '0'..'9'
+    0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 'A'..'F'
+    0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15, 0,
+    0, 0,  0,  0,  0,  0,  0,  0,  // 'a'..'f'
+    0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,
+    0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,
+    0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,
+    0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,
+    0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,
+    0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0};
+
+string hex2str(string a) {
+    string b;
+    size_t num = a.size() / 2;
+    b.resize(num);
+    for (size_t i = 0; i < num; i++) {
+        b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]);
+    }
+    return b;
+}
+
+namespace keymaster {
+
+bool operator==(const AuthorizationSet& a, const AuthorizationSet& b) {
+    if (a.size() != b.size())
+        return false;
+
+    for (size_t i = 0; i < a.size(); ++i)
+        if (!(a[i] == b[i]))
+            return false;
+    return true;
+}
+
+bool operator!=(const AuthorizationSet& a, const AuthorizationSet& b) {
+    return !(a == b);
+}
+
+std::ostream& operator<<(std::ostream& os, const AuthorizationSet& set) {
+    if (set.size() == 0)
+        os << "(Empty)" << std::endl;
+    else {
+        os << "\n";
+        for (size_t i = 0; i < set.size(); ++i)
+            os << set[i] << std::endl;
+    }
+    return os;
+}
+
+namespace test {
+
+Keymaster2Test::Keymaster2Test() : op_handle_(OP_HANDLE_SENTINEL) {
+    memset(&characteristics_, 0, sizeof(characteristics_));
+    blob_.key_material = nullptr;
+    RAND_seed("foobar", 6);
+    blob_.key_material = 0;
+    device_ = GetParam()->CreateDevice();
+}
+
+Keymaster2Test::~Keymaster2Test() {
+    FreeCharacteristics();
+    FreeKeyBlob();
+    device_->common.close(reinterpret_cast<hw_device_t*>(device_));
+}
+
+keymaster2_device_t* Keymaster2Test::device() {
+    return device_;
+}
+
+keymaster_error_t Keymaster2Test::GenerateKey(const AuthorizationSetBuilder& builder) {
+    AuthorizationSet params(builder.build());
+    params.push_back(UserAuthParams());
+    params.push_back(ClientParams());
+
+    FreeKeyBlob();
+    FreeCharacteristics();
+    return device()->generate_key(device(), &params, &blob_, &characteristics_);
+}
+
+keymaster_error_t Keymaster2Test::DeleteKey() {
+    return device()->delete_key(device(), &blob_);
+}
+
+keymaster_error_t Keymaster2Test::ImportKey(const AuthorizationSetBuilder& builder,
+                                            keymaster_key_format_t format,
+                                            const string& key_material) {
+    AuthorizationSet params(builder.build());
+    params.push_back(UserAuthParams());
+    params.push_back(ClientParams());
+
+    FreeKeyBlob();
+    FreeCharacteristics();
+    keymaster_blob_t key = {reinterpret_cast<const uint8_t*>(key_material.c_str()),
+                            key_material.length()};
+    return device()->import_key(device(), &params, format, &key, &blob_, &characteristics_);
+}
+
+AuthorizationSet Keymaster2Test::UserAuthParams() {
+    AuthorizationSet set;
+    set.push_back(TAG_USER_ID, 7);
+    set.push_back(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD);
+    set.push_back(TAG_AUTH_TIMEOUT, 300);
+    return set;
+}
+
+AuthorizationSet Keymaster2Test::ClientParams() {
+    AuthorizationSet set;
+    set.push_back(TAG_APPLICATION_ID, "app_id", 6);
+    return set;
+}
+
+keymaster_error_t Keymaster2Test::BeginOperation(keymaster_purpose_t purpose) {
+    AuthorizationSet in_params(client_params());
+    keymaster_key_param_set_t out_params;
+    keymaster_error_t error =
+        device()->begin(device(), purpose, &blob_, &in_params, &out_params, &op_handle_);
+    EXPECT_EQ(0U, out_params.length);
+    EXPECT_TRUE(out_params.params == nullptr);
+    return error;
+}
+
+keymaster_error_t Keymaster2Test::BeginOperation(keymaster_purpose_t purpose,
+                                                 const AuthorizationSet& input_set,
+                                                 AuthorizationSet* output_set) {
+    keymaster_key_param_set_t out_params;
+    keymaster_error_t error =
+        device()->begin(device(), purpose, &blob_, &input_set, &out_params, &op_handle_);
+    if (error == KM_ERROR_OK) {
+        if (output_set) {
+            output_set->Reinitialize(out_params);
+        } else {
+            EXPECT_EQ(0U, out_params.length);
+            EXPECT_TRUE(out_params.params == nullptr);
+        }
+        keymaster_free_param_set(&out_params);
+    }
+    return error;
+}
+
+keymaster_error_t Keymaster2Test::UpdateOperation(const string& message, string* output,
+                                                  size_t* input_consumed) {
+    EXPECT_NE(op_handle_, OP_HANDLE_SENTINEL);
+    keymaster_blob_t input = {reinterpret_cast<const uint8_t*>(message.c_str()), message.length()};
+    keymaster_blob_t out_tmp;
+    keymaster_key_param_set_t out_params;
+    keymaster_error_t error = device()->update(device(), op_handle_, nullptr /* params */, &input,
+                                               input_consumed, &out_params, &out_tmp);
+    if (error == KM_ERROR_OK && out_tmp.data)
+        output->append(reinterpret_cast<const char*>(out_tmp.data), out_tmp.data_length);
+    free(const_cast<uint8_t*>(out_tmp.data));
+    return error;
+}
+
+keymaster_error_t Keymaster2Test::UpdateOperation(const AuthorizationSet& additional_params,
+                                                  const string& message,
+                                                  AuthorizationSet* output_params, string* output,
+                                                  size_t* input_consumed) {
+    EXPECT_NE(op_handle_, OP_HANDLE_SENTINEL);
+    keymaster_blob_t input = {reinterpret_cast<const uint8_t*>(message.c_str()), message.length()};
+    keymaster_blob_t out_tmp;
+    keymaster_key_param_set_t out_params;
+    keymaster_error_t error = device()->update(device(), op_handle_, &additional_params, &input,
+                                               input_consumed, &out_params, &out_tmp);
+    if (error == KM_ERROR_OK && out_tmp.data)
+        output->append(reinterpret_cast<const char*>(out_tmp.data), out_tmp.data_length);
+    free((void*)out_tmp.data);
+    if (output_params)
+        output_params->Reinitialize(out_params);
+    keymaster_free_param_set(&out_params);
+    return error;
+}
+
+keymaster_error_t Keymaster2Test::FinishOperation(string* output) {
+    return FinishOperation("", output);
+}
+
+keymaster_error_t Keymaster2Test::FinishOperation(const string& signature, string* output) {
+    AuthorizationSet additional_params;
+    AuthorizationSet output_params;
+    return FinishOperation(additional_params, signature, &output_params, output);
+}
+
+keymaster_error_t Keymaster2Test::FinishOperation(const AuthorizationSet& additional_params,
+                                                  const string& signature,
+                                                  AuthorizationSet* output_params, string* output) {
+    keymaster_blob_t sig = {reinterpret_cast<const uint8_t*>(signature.c_str()),
+                            signature.length()};
+    keymaster_blob_t out_tmp;
+    keymaster_key_param_set_t out_params;
+    keymaster_error_t error = device()->finish(device(), op_handle_, &additional_params,
+                                               nullptr /* input */, &sig, &out_params, &out_tmp);
+    if (error != KM_ERROR_OK) {
+        EXPECT_TRUE(out_tmp.data == nullptr);
+        EXPECT_TRUE(out_params.params == nullptr);
+        return error;
+    }
+
+    if (out_tmp.data)
+        output->append(reinterpret_cast<const char*>(out_tmp.data), out_tmp.data_length);
+    free((void*)out_tmp.data);
+    if (output_params)
+        output_params->Reinitialize(out_params);
+    keymaster_free_param_set(&out_params);
+    return error;
+}
+
+keymaster_error_t Keymaster2Test::AbortOperation() {
+    return device()->abort(device(), op_handle_);
+}
+
+keymaster_error_t Keymaster2Test::AttestKey(keymaster_algorithm_t algorithm,
+                                            keymaster_cert_chain_t* cert_chain) {
+    AuthorizationSet attest_params(
+        AuthorizationSetBuilder().Authorization(TAG_ALGORITHM, algorithm));
+    attest_params.push_back(UserAuthParams());
+    attest_params.push_back(ClientParams());
+    return device()->attest_key(device(), &blob_, &attest_params, cert_chain);
+}
+
+string Keymaster2Test::ProcessMessage(keymaster_purpose_t purpose, const string& message) {
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, client_params(), NULL /* output_params */));
+
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(&result));
+    return result;
+}
+
+string Keymaster2Test::ProcessMessage(keymaster_purpose_t purpose, const string& message,
+                                      const AuthorizationSet& begin_params,
+                                      const AuthorizationSet& update_params,
+                                      AuthorizationSet* begin_out_params) {
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, begin_params, begin_out_params));
+
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, nullptr /* output_params */,
+                                           &result, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(update_params, "", &result));
+    return result;
+}
+
+string Keymaster2Test::ProcessMessage(keymaster_purpose_t purpose, const string& message,
+                                      const string& signature, const AuthorizationSet& begin_params,
+                                      const AuthorizationSet& update_params,
+                                      AuthorizationSet* output_params) {
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, begin_params, output_params));
+
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, nullptr /* output_params */,
+                                           &result, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(update_params, signature, &result));
+    return result;
+}
+
+string Keymaster2Test::ProcessMessage(keymaster_purpose_t purpose, const string& message,
+                                      const string& signature) {
+    EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, client_params(), NULL /* output_params */));
+
+    string result;
+    size_t input_consumed;
+    EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(KM_ERROR_OK, FinishOperation(signature, &result));
+    return result;
+}
+
+void Keymaster2Test::SignMessage(const string& message, string* signature,
+                                 keymaster_digest_t digest) {
+    SCOPED_TRACE("SignMessage");
+    AuthorizationSet input_params(AuthorizationSet(client_params_, array_length(client_params_)));
+    input_params.push_back(TAG_DIGEST, digest);
+    AuthorizationSet update_params;
+    AuthorizationSet output_params;
+    *signature =
+        ProcessMessage(KM_PURPOSE_SIGN, message, input_params, update_params, &output_params);
+    EXPECT_GT(signature->size(), 0U);
+}
+
+void Keymaster2Test::SignMessage(const string& message, string* signature,
+                                 keymaster_digest_t digest, keymaster_padding_t padding) {
+    SCOPED_TRACE("SignMessage");
+    AuthorizationSet input_params(AuthorizationSet(client_params_, array_length(client_params_)));
+    input_params.push_back(TAG_DIGEST, digest);
+    input_params.push_back(TAG_PADDING, padding);
+    AuthorizationSet update_params;
+    AuthorizationSet output_params;
+    *signature =
+        ProcessMessage(KM_PURPOSE_SIGN, message, input_params, update_params, &output_params);
+    EXPECT_GT(signature->size(), 0U);
+}
+
+void Keymaster2Test::MacMessage(const string& message, string* signature, size_t mac_length) {
+    SCOPED_TRACE("SignMessage");
+    AuthorizationSet input_params(AuthorizationSet(client_params_, array_length(client_params_)));
+    input_params.push_back(TAG_MAC_LENGTH, mac_length);
+    AuthorizationSet update_params;
+    AuthorizationSet output_params;
+    *signature =
+        ProcessMessage(KM_PURPOSE_SIGN, message, input_params, update_params, &output_params);
+    EXPECT_GT(signature->size(), 0U);
+}
+
+void Keymaster2Test::VerifyMessage(const string& message, const string& signature,
+                                   keymaster_digest_t digest) {
+    SCOPED_TRACE("VerifyMessage");
+    AuthorizationSet input_params(client_params());
+    input_params.push_back(TAG_DIGEST, digest);
+    AuthorizationSet update_params;
+    AuthorizationSet output_params;
+    ProcessMessage(KM_PURPOSE_VERIFY, message, signature, input_params, update_params,
+                   &output_params);
+}
+
+void Keymaster2Test::VerifyMessage(const string& message, const string& signature,
+                                   keymaster_digest_t digest, keymaster_padding_t padding) {
+    SCOPED_TRACE("VerifyMessage");
+    AuthorizationSet input_params(client_params());
+    input_params.push_back(TAG_DIGEST, digest);
+    input_params.push_back(TAG_PADDING, padding);
+    AuthorizationSet update_params;
+    AuthorizationSet output_params;
+    ProcessMessage(KM_PURPOSE_VERIFY, message, signature, input_params, update_params,
+                   &output_params);
+}
+
+void Keymaster2Test::VerifyMac(const string& message, const string& signature) {
+    SCOPED_TRACE("VerifyMac");
+    ProcessMessage(KM_PURPOSE_VERIFY, message, signature);
+}
+
+string Keymaster2Test::EncryptMessage(const string& message, keymaster_padding_t padding,
+                                      string* generated_nonce) {
+    SCOPED_TRACE("EncryptMessage");
+    AuthorizationSet begin_params(client_params()), output_params;
+    begin_params.push_back(TAG_PADDING, padding);
+    AuthorizationSet update_params;
+    string ciphertext =
+        ProcessMessage(KM_PURPOSE_ENCRYPT, message, begin_params, update_params, &output_params);
+    if (generated_nonce) {
+        keymaster_blob_t nonce_blob;
+        EXPECT_TRUE(output_params.GetTagValue(TAG_NONCE, &nonce_blob));
+        *generated_nonce = make_string(nonce_blob.data, nonce_blob.data_length);
+    } else {
+        EXPECT_EQ(-1, output_params.find(TAG_NONCE));
+    }
+    return ciphertext;
+}
+
+string Keymaster2Test::EncryptMessage(const string& message, keymaster_digest_t digest,
+                                      keymaster_padding_t padding, string* generated_nonce) {
+    AuthorizationSet update_params;
+    return EncryptMessage(update_params, message, digest, padding, generated_nonce);
+}
+
+string Keymaster2Test::EncryptMessage(const string& message, keymaster_block_mode_t block_mode,
+                                      keymaster_padding_t padding, string* generated_nonce) {
+    AuthorizationSet update_params;
+    return EncryptMessage(update_params, message, block_mode, padding, generated_nonce);
+}
+
+string Keymaster2Test::EncryptMessage(const AuthorizationSet& update_params, const string& message,
+                                      keymaster_digest_t digest, keymaster_padding_t padding,
+                                      string* generated_nonce) {
+    SCOPED_TRACE("EncryptMessage");
+    AuthorizationSet begin_params(client_params()), output_params;
+    begin_params.push_back(TAG_PADDING, padding);
+    begin_params.push_back(TAG_DIGEST, digest);
+    string ciphertext =
+        ProcessMessage(KM_PURPOSE_ENCRYPT, message, begin_params, update_params, &output_params);
+    if (generated_nonce) {
+        keymaster_blob_t nonce_blob;
+        EXPECT_TRUE(output_params.GetTagValue(TAG_NONCE, &nonce_blob));
+        *generated_nonce = make_string(nonce_blob.data, nonce_blob.data_length);
+    } else {
+        EXPECT_EQ(-1, output_params.find(TAG_NONCE));
+    }
+    return ciphertext;
+}
+
+string Keymaster2Test::EncryptMessage(const AuthorizationSet& update_params, const string& message,
+                                      keymaster_block_mode_t block_mode,
+                                      keymaster_padding_t padding, string* generated_nonce) {
+    SCOPED_TRACE("EncryptMessage");
+    AuthorizationSet begin_params(client_params()), output_params;
+    begin_params.push_back(TAG_PADDING, padding);
+    begin_params.push_back(TAG_BLOCK_MODE, block_mode);
+    string ciphertext =
+        ProcessMessage(KM_PURPOSE_ENCRYPT, message, begin_params, update_params, &output_params);
+    if (generated_nonce) {
+        keymaster_blob_t nonce_blob;
+        EXPECT_TRUE(output_params.GetTagValue(TAG_NONCE, &nonce_blob));
+        *generated_nonce = make_string(nonce_blob.data, nonce_blob.data_length);
+    } else {
+        EXPECT_EQ(-1, output_params.find(TAG_NONCE));
+    }
+    return ciphertext;
+}
+
+string Keymaster2Test::EncryptMessageWithParams(const string& message,
+                                                const AuthorizationSet& begin_params,
+                                                const AuthorizationSet& update_params,
+                                                AuthorizationSet* output_params) {
+    SCOPED_TRACE("EncryptMessageWithParams");
+    return ProcessMessage(KM_PURPOSE_ENCRYPT, message, begin_params, update_params, output_params);
+}
+
+string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_padding_t padding) {
+    SCOPED_TRACE("DecryptMessage");
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, padding);
+    AuthorizationSet update_params;
+    return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
+}
+
+string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_digest_t digest,
+                                      keymaster_padding_t padding) {
+    SCOPED_TRACE("DecryptMessage");
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, padding);
+    begin_params.push_back(TAG_DIGEST, digest);
+    AuthorizationSet update_params;
+    return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
+}
+
+string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_block_mode_t block_mode,
+                                      keymaster_padding_t padding) {
+    SCOPED_TRACE("DecryptMessage");
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, padding);
+    begin_params.push_back(TAG_BLOCK_MODE, block_mode);
+    AuthorizationSet update_params;
+    return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
+}
+
+string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_digest_t digest,
+                                      keymaster_padding_t padding, const string& nonce) {
+    SCOPED_TRACE("DecryptMessage");
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, padding);
+    begin_params.push_back(TAG_DIGEST, digest);
+    begin_params.push_back(TAG_NONCE, nonce.data(), nonce.size());
+    AuthorizationSet update_params;
+    return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
+}
+
+string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_block_mode_t block_mode,
+                                      keymaster_padding_t padding, const string& nonce) {
+    SCOPED_TRACE("DecryptMessage");
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, padding);
+    begin_params.push_back(TAG_BLOCK_MODE, block_mode);
+    begin_params.push_back(TAG_NONCE, nonce.data(), nonce.size());
+    AuthorizationSet update_params;
+    return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
+}
+
+string Keymaster2Test::DecryptMessage(const AuthorizationSet& update_params,
+                                      const string& ciphertext, keymaster_digest_t digest,
+                                      keymaster_padding_t padding, const string& nonce) {
+    SCOPED_TRACE("DecryptMessage");
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, padding);
+    begin_params.push_back(TAG_DIGEST, digest);
+    begin_params.push_back(TAG_NONCE, nonce.data(), nonce.size());
+    return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
+}
+
+keymaster_error_t Keymaster2Test::GetCharacteristics() {
+    FreeCharacteristics();
+    return device()->get_key_characteristics(device(), &blob_, &client_id_, NULL /* app_data */,
+                                             &characteristics_);
+}
+
+keymaster_error_t Keymaster2Test::ExportKey(keymaster_key_format_t format, string* export_data) {
+    keymaster_blob_t export_tmp;
+    keymaster_error_t error = device()->export_key(device(), format, &blob_, &client_id_,
+                                                   NULL /* app_data */, &export_tmp);
+
+    if (error != KM_ERROR_OK)
+        return error;
+
+    *export_data = string(reinterpret_cast<const char*>(export_tmp.data), export_tmp.data_length);
+    free((void*)export_tmp.data);
+    return error;
+}
+
+void Keymaster2Test::CheckHmacTestVector(const string& key, const string& message, keymaster_digest_t digest,
+                                         string expected_mac) {
+    ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder()
+                                         .HmacKey(key.size() * 8)
+                                         .Authorization(TAG_MIN_MAC_LENGTH, expected_mac.size() * 8)
+                                         .Digest(digest),
+                                     KM_KEY_FORMAT_RAW, key));
+    string signature;
+    MacMessage(message, &signature, expected_mac.size() * 8);
+    EXPECT_EQ(expected_mac, signature) << "Test vector didn't match for digest " << (int)digest;
+}
+
+void Keymaster2Test::CheckAesCtrTestVector(const string& key, const string& nonce,
+                                           const string& message,
+                                           const string& expected_ciphertext) {
+    ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder()
+                                         .AesEncryptionKey(key.size() * 8)
+                                         .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR)
+                                         .Authorization(TAG_CALLER_NONCE)
+                                         .Padding(KM_PAD_NONE),
+                                     KM_KEY_FORMAT_RAW, key));
+
+    AuthorizationSet begin_params(client_params()), update_params, output_params;
+    begin_params.push_back(TAG_NONCE, nonce.data(), nonce.size());
+    begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR);
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    string ciphertext =
+        EncryptMessageWithParams(message, begin_params, update_params, &output_params);
+    EXPECT_EQ(expected_ciphertext, ciphertext);
+}
+
+AuthorizationSet Keymaster2Test::hw_enforced() {
+    return AuthorizationSet(characteristics_.hw_enforced);
+}
+
+AuthorizationSet Keymaster2Test::sw_enforced() {
+    return AuthorizationSet(characteristics_.sw_enforced);
+}
+
+void Keymaster2Test::FreeCharacteristics() {
+    keymaster_free_characteristics(&characteristics_);
+}
+
+void Keymaster2Test::FreeKeyBlob() {
+    free(const_cast<uint8_t*>(blob_.key_material));
+    blob_.key_material = NULL;
+}
+
+void Keymaster2Test::corrupt_key_blob() {
+    assert(blob_.key_material);
+    uint8_t* tmp = const_cast<uint8_t*>(blob_.key_material);
+    ++tmp[blob_.key_material_size / 2];
+}
+
+class Sha256OnlyWrapper {
+  public:
+    explicit Sha256OnlyWrapper(const keymaster1_device_t* wrapped_device) : wrapped_device_(wrapped_device) {
+
+        new_module = *wrapped_device_->common.module;
+        new_module_name = std::string("SHA 256-only ") + wrapped_device_->common.module->name;
+        new_module.name = new_module_name.c_str();
+
+        memset(&device_, 0, sizeof(device_));
+        device_.common.module = &new_module;
+
+        device_.common.close = close_device;
+        device_.get_supported_algorithms = get_supported_algorithms;
+        device_.get_supported_block_modes = get_supported_block_modes;
+        device_.get_supported_padding_modes = get_supported_padding_modes;
+        device_.get_supported_digests = get_supported_digests;
+        device_.get_supported_import_formats = get_supported_import_formats;
+        device_.get_supported_export_formats = get_supported_export_formats;
+        device_.add_rng_entropy = add_rng_entropy;
+        device_.generate_key = generate_key;
+        device_.get_key_characteristics = get_key_characteristics;
+        device_.import_key = import_key;
+        device_.export_key = export_key;
+        device_.begin = begin;
+        device_.update = update;
+        device_.finish = finish;
+        device_.abort = abort;
+    }
+
+    keymaster1_device_t* keymaster_device() { return &device_; }
+
+    static bool is_supported(keymaster_digest_t digest) {
+        return digest == KM_DIGEST_NONE || digest == KM_DIGEST_SHA_2_256;
+    }
+
+    static bool all_digests_supported(const keymaster_key_param_set_t* params) {
+        for (size_t i = 0; i < params->length; ++i)
+            if (params->params[i].tag == TAG_DIGEST)
+                if (!is_supported(static_cast<keymaster_digest_t>(params->params[i].enumerated)))
+                    return false;
+        return true;
+    }
+
+    static const keymaster_key_param_t*
+    get_algorithm_param(const keymaster_key_param_set_t* params) {
+        keymaster_key_param_t* end = params->params + params->length;
+        auto alg_ptr = std::find_if(params->params, end, [](keymaster_key_param_t& p) {
+            return p.tag == KM_TAG_ALGORITHM;
+        });
+        if (alg_ptr == end)
+            return nullptr;
+        return alg_ptr;
+    }
+
+    static int close_device(hw_device_t* dev) {
+        Sha256OnlyWrapper* wrapper = reinterpret_cast<Sha256OnlyWrapper*>(dev);
+        const keymaster1_device_t* wrapped_device = wrapper->wrapped_device_;
+        delete wrapper;
+        return wrapped_device->common.close(const_cast<hw_device_t*>(&wrapped_device->common));
+    }
+
+    static const keymaster1_device_t* unwrap(const keymaster1_device_t* dev) {
+        return reinterpret_cast<const Sha256OnlyWrapper*>(dev)->wrapped_device_;
+    }
+
+    static keymaster_error_t get_supported_algorithms(const struct keymaster1_device* dev,
+                                                      keymaster_algorithm_t** algorithms,
+                                                      size_t* algorithms_length) {
+        return unwrap(dev)->get_supported_algorithms(unwrap(dev), algorithms, algorithms_length);
+    }
+    static keymaster_error_t get_supported_block_modes(const struct keymaster1_device* dev,
+                                                       keymaster_algorithm_t algorithm,
+                                                       keymaster_purpose_t purpose,
+                                                       keymaster_block_mode_t** modes,
+                                                       size_t* modes_length) {
+        return unwrap(dev)->get_supported_block_modes(unwrap(dev), algorithm, purpose, modes,
+                                                      modes_length);
+    }
+    static keymaster_error_t get_supported_padding_modes(const struct keymaster1_device* dev,
+                                                         keymaster_algorithm_t algorithm,
+                                                         keymaster_purpose_t purpose,
+                                                         keymaster_padding_t** modes,
+                                                         size_t* modes_length) {
+        return unwrap(dev)->get_supported_padding_modes(unwrap(dev), algorithm, purpose, modes,
+                                                        modes_length);
+    }
+
+    static keymaster_error_t get_supported_digests(const keymaster1_device_t* dev,
+                                                   keymaster_algorithm_t algorithm,
+                                                   keymaster_purpose_t purpose,
+                                                   keymaster_digest_t** digests,
+                                                   size_t* digests_length) {
+        keymaster_error_t error = unwrap(dev)->get_supported_digests(
+            unwrap(dev), algorithm, purpose, digests, digests_length);
+        if (error != KM_ERROR_OK)
+            return error;
+
+        std::vector<keymaster_digest_t> filtered_digests;
+        std::copy_if(*digests, *digests + *digests_length, std::back_inserter(filtered_digests),
+                     [](keymaster_digest_t digest) { return is_supported(digest); });
+
+        free(*digests);
+        *digests_length = filtered_digests.size();
+        *digests = reinterpret_cast<keymaster_digest_t*>(
+            malloc(*digests_length * sizeof(keymaster_digest_t)));
+        std::copy(filtered_digests.begin(), filtered_digests.end(), *digests);
+
+        return KM_ERROR_OK;
+    }
+
+    static keymaster_error_t get_supported_import_formats(const struct keymaster1_device* dev,
+                                                          keymaster_algorithm_t algorithm,
+                                                          keymaster_key_format_t** formats,
+                                                          size_t* formats_length) {
+        return unwrap(dev)->get_supported_import_formats(unwrap(dev), algorithm, formats,
+                                                         formats_length);
+    }
+    static keymaster_error_t get_supported_export_formats(const struct keymaster1_device* dev,
+                                                          keymaster_algorithm_t algorithm,
+                                                          keymaster_key_format_t** formats,
+                                                          size_t* formats_length) {
+        return unwrap(dev)->get_supported_export_formats(unwrap(dev), algorithm, formats,
+                                                         formats_length);
+    }
+    static keymaster_error_t add_rng_entropy(const struct keymaster1_device* dev,
+                                             const uint8_t* data, size_t data_length) {
+        return unwrap(dev)->add_rng_entropy(unwrap(dev), data, data_length);
+    }
+
+    static keymaster_error_t generate_key(const keymaster1_device_t* dev,
+                                          const keymaster_key_param_set_t* params,
+                                          keymaster_key_blob_t* key_blob,
+                                          keymaster_key_characteristics_t** characteristics) {
+        auto alg_ptr = get_algorithm_param(params);
+        if (!alg_ptr)
+            return KM_ERROR_UNSUPPORTED_ALGORITHM;
+        if (alg_ptr->enumerated == KM_ALGORITHM_HMAC && !all_digests_supported(params))
+            return KM_ERROR_UNSUPPORTED_DIGEST;
+
+        return unwrap(dev)->generate_key(unwrap(dev), params, key_blob, characteristics);
+    }
+
+    static keymaster_error_t
+    get_key_characteristics(const struct keymaster1_device* dev,
+                            const keymaster_key_blob_t* key_blob, const keymaster_blob_t* client_id,
+                            const keymaster_blob_t* app_data,
+                            keymaster_key_characteristics_t** characteristics) {
+        return unwrap(dev)->get_key_characteristics(unwrap(dev), key_blob, client_id, app_data,
+                                                    characteristics);
+    }
+
+    static keymaster_error_t
+    import_key(const keymaster1_device_t* dev, const keymaster_key_param_set_t* params,
+               keymaster_key_format_t key_format, const keymaster_blob_t* key_data,
+               keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t** characteristics) {
+        auto alg_ptr = get_algorithm_param(params);
+        if (!alg_ptr)
+            return KM_ERROR_UNSUPPORTED_ALGORITHM;
+        if (alg_ptr->enumerated == KM_ALGORITHM_HMAC && !all_digests_supported(params))
+            return KM_ERROR_UNSUPPORTED_DIGEST;
+
+        return unwrap(dev)->import_key(unwrap(dev), params, key_format, key_data, key_blob,
+                                       characteristics);
+    }
+
+    static keymaster_error_t export_key(const struct keymaster1_device* dev,  //
+                                        keymaster_key_format_t export_format,
+                                        const keymaster_key_blob_t* key_to_export,
+                                        const keymaster_blob_t* client_id,
+                                        const keymaster_blob_t* app_data,
+                                        keymaster_blob_t* export_data) {
+        return unwrap(dev)->export_key(unwrap(dev), export_format, key_to_export, client_id,
+                                       app_data, export_data);
+    }
+
+    static keymaster_error_t begin(const keymaster1_device_t* dev,  //
+                                   keymaster_purpose_t purpose, const keymaster_key_blob_t* key,
+                                   const keymaster_key_param_set_t* in_params,
+                                   keymaster_key_param_set_t* out_params,
+                                   keymaster_operation_handle_t* operation_handle) {
+        if (!all_digests_supported(in_params))
+            return KM_ERROR_UNSUPPORTED_DIGEST;
+        return unwrap(dev)->begin(unwrap(dev), purpose, key, in_params, out_params,
+                                  operation_handle);
+    }
+
+    static keymaster_error_t update(const keymaster1_device_t* dev,
+                                    keymaster_operation_handle_t operation_handle,
+                                    const keymaster_key_param_set_t* in_params,
+                                    const keymaster_blob_t* input, size_t* input_consumed,
+                                    keymaster_key_param_set_t* out_params,
+                                    keymaster_blob_t* output) {
+        return unwrap(dev)->update(unwrap(dev), operation_handle, in_params, input, input_consumed,
+                                   out_params, output);
+    }
+
+    static keymaster_error_t finish(const struct keymaster1_device* dev,  //
+                                    keymaster_operation_handle_t operation_handle,
+                                    const keymaster_key_param_set_t* in_params,
+                                    const keymaster_blob_t* signature,
+                                    keymaster_key_param_set_t* out_params,
+                                    keymaster_blob_t* output) {
+        return unwrap(dev)->finish(unwrap(dev), operation_handle, in_params, signature, out_params,
+                                   output);
+    }
+
+    static keymaster_error_t abort(const struct keymaster1_device* dev,
+                                   keymaster_operation_handle_t operation_handle) {
+        return unwrap(dev)->abort(unwrap(dev), operation_handle);
+    }
+
+  private:
+    keymaster1_device_t device_;
+    const keymaster1_device_t* wrapped_device_;
+    hw_module_t new_module;
+    string new_module_name;
+};
+
+keymaster1_device_t* make_device_sha256_only(keymaster1_device_t* device) {
+    return (new Sha256OnlyWrapper(device))->keymaster_device();
+}
+
+}  // namespace test
+}  // namespace keymaster
diff --git a/keymaster/android_keymaster_test_utils.h b/keymaster/android_keymaster_test_utils.h
new file mode 100644
index 0000000..7a4d35e
--- /dev/null
+++ b/keymaster/android_keymaster_test_utils.h
@@ -0,0 +1,464 @@
+/*
+ * 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_KEYMASTER_TEST_UTILS_H_
+#define SYSTEM_KEYMASTER_ANDROID_KEYMASTER_TEST_UTILS_H_
+
+/*
+ * Utilities used to help with testing.  Not used in production code.
+ */
+
+#include <stdarg.h>
+
+#include <algorithm>
+#include <memory>
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <hardware/keymaster0.h>
+#include <hardware/keymaster1.h>
+#include <hardware/keymaster2.h>
+#include <hardware/keymaster_defs.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/logger.h>
+
+std::ostream& operator<<(std::ostream& os, const keymaster_key_param_t& param);
+bool operator==(const keymaster_key_param_t& a, const keymaster_key_param_t& b);
+std::string hex2str(std::string);
+
+namespace keymaster {
+
+bool operator==(const AuthorizationSet& a, const AuthorizationSet& b);
+bool operator!=(const AuthorizationSet& a, const AuthorizationSet& b);
+
+std::ostream& operator<<(std::ostream& os, const AuthorizationSet& set);
+
+namespace test {
+
+template <keymaster_tag_t Tag, typename KeymasterEnum>
+bool contains(const AuthorizationSet& set, TypedEnumTag<KM_ENUM, Tag, KeymasterEnum> tag,
+              KeymasterEnum val) {
+    int pos = set.find(tag);
+    return pos != -1 && set[pos].enumerated == val;
+}
+
+template <keymaster_tag_t Tag, typename KeymasterEnum>
+bool contains(const AuthorizationSet& set, TypedEnumTag<KM_ENUM_REP, Tag, KeymasterEnum> tag,
+              KeymasterEnum val) {
+    int pos = -1;
+    while ((pos = set.find(tag, pos)) != -1)
+        if (set[pos].enumerated == val)
+            return true;
+    return false;
+}
+
+template <keymaster_tag_t Tag>
+bool contains(const AuthorizationSet& set, TypedTag<KM_UINT, Tag> tag, uint32_t val) {
+    int pos = set.find(tag);
+    return pos != -1 && set[pos].integer == val;
+}
+
+template <keymaster_tag_t Tag>
+bool contains(const AuthorizationSet& set, TypedTag<KM_UINT_REP, Tag> tag, uint32_t val) {
+    int pos = -1;
+    while ((pos = set.find(tag, pos)) != -1)
+        if (set[pos].integer == val)
+            return true;
+    return false;
+}
+
+template <keymaster_tag_t Tag>
+bool contains(const AuthorizationSet& set, TypedTag<KM_ULONG, Tag> tag, uint64_t val) {
+    int pos = set.find(tag);
+    return pos != -1 && set[pos].long_integer == val;
+}
+
+template <keymaster_tag_t Tag>
+bool contains(const AuthorizationSet& set, TypedTag<KM_BYTES, Tag> tag, const std::string& val) {
+    int pos = set.find(tag);
+    return pos != -1 &&
+           std::string(reinterpret_cast<const char*>(set[pos].blob.data),
+                       set[pos].blob.data_length) == val;
+}
+
+template <keymaster_tag_t Tag>
+bool contains(const AuthorizationSet& set, TypedTag<KM_BIGNUM, Tag> tag, const std::string& val) {
+    int pos = set.find(tag);
+    return pos != -1 &&
+           std::string(reinterpret_cast<const char*>(set[pos].blob.data),
+                       set[pos].blob.data_length) == val;
+}
+
+inline bool contains(const AuthorizationSet& set, keymaster_tag_t tag) {
+    return set.find(tag) != -1;
+}
+
+class StdoutLogger : public Logger {
+  public:
+    StdoutLogger() { set_instance(this); }
+
+    int log_msg(LogLevel level, const char* fmt, va_list args) const {
+        int output_len = 0;
+        switch (level) {
+        case DEBUG_LVL:
+            output_len = printf("DEBUG: ");
+            break;
+        case INFO_LVL:
+            output_len = printf("INFO: ");
+            break;
+        case WARNING_LVL:
+            output_len = printf("WARNING: ");
+            break;
+        case ERROR_LVL:
+            output_len = printf("ERROR: ");
+            break;
+        case SEVERE_LVL:
+            output_len = printf("SEVERE: ");
+            break;
+        }
+
+        output_len += vprintf(fmt, args);
+        output_len += printf("\n");
+        return output_len;
+    }
+};
+
+inline std::string make_string(const uint8_t* data, size_t length) {
+    return std::string(reinterpret_cast<const char*>(data), length);
+}
+
+template <size_t N> std::string make_string(const uint8_t (&a)[N]) {
+    return make_string(a, N);
+}
+
+/**
+ * Keymaster2TestInstance is used to parameterize Keymaster2Tests.  Its main function is to create a
+ * keymaster2_device_t to which test calls can be directed.  It also provides a place to specify
+ * various bits of alternative behavior, in cases where different devices are expected to behave
+ * differently (any such cases are a potential bug, but sometimes they may make sense).
+ */
+class Keymaster2TestInstanceCreator {
+  public:
+    virtual ~Keymaster2TestInstanceCreator(){};
+    virtual keymaster2_device_t* CreateDevice() const = 0;
+
+    virtual bool algorithm_in_km0_hardware(keymaster_algorithm_t algorithm) const = 0;
+    virtual int keymaster0_calls() const = 0;
+    virtual int minimal_digest_set() const { return false; }
+};
+
+// Use a shared_ptr because it's copyable.
+typedef std::shared_ptr<Keymaster2TestInstanceCreator> InstanceCreatorPtr;
+
+const uint64_t OP_HANDLE_SENTINEL = 0xFFFFFFFFFFFFFFFF;
+class Keymaster2Test : public testing::TestWithParam<InstanceCreatorPtr> {
+  protected:
+    Keymaster2Test();
+    ~Keymaster2Test();
+
+    keymaster2_device_t* device();
+
+    keymaster_error_t GenerateKey(const AuthorizationSetBuilder& builder);
+
+    keymaster_error_t DeleteKey();
+
+    keymaster_error_t ImportKey(const AuthorizationSetBuilder& builder,
+                                keymaster_key_format_t format, const std::string& key_material);
+
+    keymaster_error_t ExportKey(keymaster_key_format_t format, std::string* export_data);
+
+    keymaster_error_t GetCharacteristics();
+
+    keymaster_error_t BeginOperation(keymaster_purpose_t purpose);
+    keymaster_error_t BeginOperation(keymaster_purpose_t purpose, const AuthorizationSet& input_set,
+                                     AuthorizationSet* output_set = NULL);
+
+    keymaster_error_t UpdateOperation(const std::string& message, std::string* output,
+                                      size_t* input_consumed);
+    keymaster_error_t UpdateOperation(const AuthorizationSet& additional_params,
+                                      const std::string& message, AuthorizationSet* output_params,
+                                      std::string* output, size_t* input_consumed);
+
+    keymaster_error_t FinishOperation(std::string* output);
+    keymaster_error_t FinishOperation(const std::string& signature, std::string* output);
+    keymaster_error_t FinishOperation(const AuthorizationSet& additional_params,
+                                      const std::string& signature, std::string* output) {
+        return FinishOperation(additional_params, signature, nullptr /* output_params */, output);
+    }
+    keymaster_error_t FinishOperation(const AuthorizationSet& additional_params,
+                                      const std::string& signature, AuthorizationSet* output_params,
+                                      std::string* output);
+
+    keymaster_error_t AbortOperation();
+
+    keymaster_error_t AttestKey(keymaster_algorithm_t algorithm, keymaster_cert_chain_t* chain);
+
+    keymaster_error_t GetVersion(uint8_t* major, uint8_t* minor, uint8_t* subminor);
+
+    std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message);
+    std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message,
+                               const AuthorizationSet& begin_params,
+                               const AuthorizationSet& update_params,
+                               AuthorizationSet* output_params = NULL);
+    std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message,
+                               const std::string& signature, const AuthorizationSet& begin_params,
+                               const AuthorizationSet& update_params,
+                               AuthorizationSet* output_params = NULL);
+    std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message,
+                               const std::string& signature);
+
+    void SignMessage(const std::string& message, std::string* signature, keymaster_digest_t digest);
+    void SignMessage(const std::string& message, std::string* signature, keymaster_digest_t digest,
+                     keymaster_padding_t padding);
+    void MacMessage(const std::string& message, std::string* signature, size_t mac_length);
+
+    void VerifyMessage(const std::string& message, const std::string& signature,
+                       keymaster_digest_t digest);
+    void VerifyMessage(const std::string& message, const std::string& signature,
+                       keymaster_digest_t digest, keymaster_padding_t padding);
+    void VerifyMac(const std::string& message, const std::string& signature);
+
+    std::string EncryptMessage(const std::string& message, keymaster_padding_t padding,
+                               std::string* generated_nonce = NULL);
+    std::string EncryptMessage(const std::string& message, keymaster_digest_t digest,
+                               keymaster_padding_t padding, std::string* generated_nonce = NULL);
+    std::string EncryptMessage(const std::string& message, keymaster_block_mode_t block_mode,
+                               keymaster_padding_t padding, std::string* generated_nonce = NULL);
+    std::string EncryptMessage(const AuthorizationSet& update_params, const std::string& message,
+                               keymaster_digest_t digest, keymaster_padding_t padding,
+                               std::string* generated_nonce = NULL);
+    std::string EncryptMessage(const AuthorizationSet& update_params, const std::string& message,
+                               keymaster_block_mode_t block_mode, keymaster_padding_t padding,
+                               std::string* generated_nonce = NULL);
+    std::string EncryptMessageWithParams(const std::string& message,
+                                         const AuthorizationSet& begin_params,
+                                         const AuthorizationSet& update_params,
+                                         AuthorizationSet* output_params);
+
+    std::string DecryptMessage(const std::string& ciphertext, keymaster_padding_t padding);
+    std::string DecryptMessage(const std::string& ciphertext, keymaster_digest_t digest,
+                               keymaster_padding_t padding);
+    std::string DecryptMessage(const std::string& ciphertext, keymaster_block_mode_t block_mode,
+                               keymaster_padding_t padding);
+    std::string DecryptMessage(const std::string& ciphertext, keymaster_digest_t digest,
+                               keymaster_padding_t padding, const std::string& nonce);
+    std::string DecryptMessage(const std::string& ciphertext, keymaster_block_mode_t block_mode,
+                               keymaster_padding_t padding, const std::string& nonce);
+    std::string DecryptMessage(const AuthorizationSet& update_params, const std::string& ciphertext,
+                               keymaster_digest_t digest, keymaster_padding_t padding,
+                               const std::string& nonce);
+    std::string DecryptMessage(const AuthorizationSet& update_params, const std::string& ciphertext,
+                               keymaster_block_mode_t block_mode, keymaster_padding_t padding,
+                               const std::string& nonce);
+
+    void CheckHmacTestVector(const std::string& key, const std::string& message, keymaster_digest_t digest,
+                             std::string expected_mac);
+    void CheckAesOcbTestVector(const std::string& key, const std::string& nonce,
+                               const std::string& associated_data, const std::string& message,
+                               const std::string& expected_ciphertext);
+    void CheckAesCtrTestVector(const std::string& key, const std::string& nonce,
+                               const std::string& message, const std::string& expected_ciphertext);
+    AuthorizationSet UserAuthParams();
+    AuthorizationSet ClientParams();
+
+    template <typename T>
+    bool ResponseContains(const std::vector<T>& expected, const T* values, size_t len) {
+        return expected.size() == len &&
+               std::is_permutation(values, values + len, expected.begin());
+    }
+
+    template <typename T> bool ResponseContains(T expected, const T* values, size_t len) {
+        return (len == 1 && *values == expected);
+    }
+
+    AuthorizationSet hw_enforced();
+    AuthorizationSet sw_enforced();
+
+    void FreeCharacteristics();
+    void FreeKeyBlob();
+
+    void corrupt_key_blob();
+
+    void set_key_blob(const uint8_t* key, size_t key_length) {
+        FreeKeyBlob();
+        blob_.key_material = key;
+        blob_.key_material_size = key_length;
+    }
+
+    AuthorizationSet client_params() {
+        return AuthorizationSet(client_params_, sizeof(client_params_) / sizeof(client_params_[0]));
+    }
+
+  private:
+    keymaster2_device_t* device_;
+    keymaster_blob_t client_id_ = {.data = reinterpret_cast<const uint8_t*>("app_id"),
+                                   .data_length = 6};
+    keymaster_key_param_t client_params_[1] = {
+        Authorization(TAG_APPLICATION_ID, client_id_.data, client_id_.data_length)};
+
+    uint64_t op_handle_;
+
+    keymaster_key_blob_t blob_;
+    keymaster_key_characteristics_t characteristics_;
+};
+
+struct Keymaster0CountingWrapper : public keymaster0_device_t {
+    explicit Keymaster0CountingWrapper(keymaster0_device_t* device) : device_(device), counter_(0) {
+        common = device_->common;
+        common.close = counting_close_device;
+        client_version = device_->client_version;
+        flags = device_->flags;
+        context = this;
+
+        generate_keypair = counting_generate_keypair;
+        import_keypair = counting_import_keypair;
+        get_keypair_public = counting_get_keypair_public;
+        delete_keypair = counting_delete_keypair;
+        delete_all = counting_delete_all;
+        sign_data = counting_sign_data;
+        verify_data = counting_verify_data;
+    }
+
+    int count() { return counter_; }
+
+    // The blobs generated by the underlying softkeymaster start with "PK#8".  Tweak the prefix so
+    // they don't get identified as softkeymaster blobs.
+    static void munge_blob(uint8_t* blob, size_t blob_length) {
+        if (blob && blob_length > 0 && *blob == 'P')
+            *blob = 'Q';  // Mind your Ps and Qs!
+    }
+
+    // Copy and un-modfy the blob.  The caller must clean up the return value.
+    static uint8_t* unmunge_blob(const uint8_t* blob, size_t blob_length) {
+        uint8_t* dup_blob = dup_buffer(blob, blob_length);
+        if (dup_blob && blob_length > 0 && *dup_blob == 'Q')
+            *dup_blob = 'P';
+        return dup_blob;
+    }
+
+    static keymaster0_device_t* device(const keymaster0_device_t* dev) {
+        Keymaster0CountingWrapper* wrapper =
+            reinterpret_cast<Keymaster0CountingWrapper*>(dev->context);
+        return wrapper->device_;
+    }
+
+    static void increment(const keymaster0_device_t* dev) {
+        Keymaster0CountingWrapper* wrapper =
+            reinterpret_cast<Keymaster0CountingWrapper*>(dev->context);
+        wrapper->counter_++;
+    }
+
+    static int counting_close_device(hw_device_t* dev) {
+        keymaster0_device_t* k0_dev = reinterpret_cast<keymaster0_device_t*>(dev);
+        increment(k0_dev);
+        Keymaster0CountingWrapper* wrapper =
+            reinterpret_cast<Keymaster0CountingWrapper*>(k0_dev->context);
+        int retval =
+            wrapper->device_->common.close(reinterpret_cast<hw_device_t*>(wrapper->device_));
+        delete wrapper;
+        return retval;
+    }
+
+    static int counting_generate_keypair(const struct keymaster0_device* dev,
+                                         const keymaster_keypair_t key_type, const void* key_params,
+                                         uint8_t** key_blob, size_t* key_blob_length) {
+        increment(dev);
+        int result = device(dev)->generate_keypair(device(dev), key_type, key_params, key_blob,
+                                                   key_blob_length);
+        if (result == 0)
+            munge_blob(*key_blob, *key_blob_length);
+        return result;
+    }
+
+    static int counting_import_keypair(const struct keymaster0_device* dev, const uint8_t* key,
+                                       const size_t key_length, uint8_t** key_blob,
+                                       size_t* key_blob_length) {
+        increment(dev);
+        int result =
+            device(dev)->import_keypair(device(dev), key, key_length, key_blob, key_blob_length);
+        if (result == 0)
+            munge_blob(*key_blob, *key_blob_length);
+        return result;
+    }
+
+    static int counting_get_keypair_public(const struct keymaster0_device* dev,
+                                           const uint8_t* key_blob, const size_t key_blob_length,
+                                           uint8_t** x509_data, size_t* x509_data_length) {
+        increment(dev);
+        std::unique_ptr<uint8_t[]> dup_blob(unmunge_blob(key_blob, key_blob_length));
+        return device(dev)->get_keypair_public(device(dev), dup_blob.get(), key_blob_length,
+                                               x509_data, x509_data_length);
+    }
+
+    static int counting_delete_keypair(const struct keymaster0_device* dev, const uint8_t* key_blob,
+                                       const size_t key_blob_length) {
+        increment(dev);
+        if (key_blob && key_blob_length > 0)
+            EXPECT_EQ('Q', *key_blob);
+        if (device(dev)->delete_keypair) {
+            std::unique_ptr<uint8_t[]> dup_blob(unmunge_blob(key_blob, key_blob_length));
+            return device(dev)->delete_keypair(device(dev), dup_blob.get(), key_blob_length);
+        }
+        return 0;
+    }
+
+    static int counting_delete_all(const struct keymaster0_device* dev) {
+        increment(dev);
+        if (device(dev)->delete_all)
+            return device(dev)->delete_all(device(dev));
+        return 0;
+    }
+
+    static int counting_sign_data(const struct keymaster0_device* dev, const void* signing_params,
+                                  const uint8_t* key_blob, const size_t key_blob_length,
+                                  const uint8_t* data, const size_t data_length,
+                                  uint8_t** signed_data, size_t* signed_data_length) {
+        increment(dev);
+        std::unique_ptr<uint8_t[]> dup_blob(unmunge_blob(key_blob, key_blob_length));
+        return device(dev)->sign_data(device(dev), signing_params, dup_blob.get(), key_blob_length,
+                                      data, data_length, signed_data, signed_data_length);
+    }
+
+    static int counting_verify_data(const struct keymaster0_device* dev, const void* signing_params,
+                                    const uint8_t* key_blob, const size_t key_blob_length,
+                                    const uint8_t* signed_data, const size_t signed_data_length,
+                                    const uint8_t* signature, const size_t signature_length) {
+        increment(dev);
+        std::unique_ptr<uint8_t[]> dup_blob(unmunge_blob(key_blob, key_blob_length));
+        return device(dev)->verify_data(device(dev), signing_params, dup_blob.get(),
+                                        key_blob_length, signed_data, signed_data_length, signature,
+                                        signature_length);
+    }
+
+  private:
+    keymaster0_device_t* device_;
+    int counter_;
+};
+
+/**
+ * This function takes a keymaster1_device_t and wraps it in an adapter that supports only
+ * KM_DIGEST_SHA_2_256.
+ */
+keymaster1_device_t* make_device_sha256_only(keymaster1_device_t* device);
+
+}  // namespace test
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_TEST_UTILS_H_
diff --git a/keymaster/android_keymaster_utils.cpp b/keymaster/android_keymaster_utils.cpp
new file mode 100644
index 0000000..053e72a
--- /dev/null
+++ b/keymaster/android_keymaster_utils.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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 <keymaster/android_keymaster_utils.h>
+
+#include <new>
+
+namespace keymaster {
+
+// Keymaster never manages enormous buffers, so anything particularly large is bad data or the
+// result of a bug.  We arbitrarily set a 16 MiB limit.
+const size_t kMaxDupBufferSize = 16 * 1024 * 1024;
+
+uint8_t* dup_buffer(const void* buf, size_t size) {
+    if (size >= kMaxDupBufferSize)
+        return nullptr;
+    uint8_t* retval = new (std::nothrow) uint8_t[size];
+    if (retval)
+        memcpy(retval, buf, size);
+    return retval;
+}
+
+int memcmp_s(const void* p1, const void* p2, size_t length) {
+    const uint8_t* s1 = static_cast<const uint8_t*>(p1);
+    const uint8_t* s2 = static_cast<const uint8_t*>(p2);
+    uint8_t result = 0;
+    while (length-- > 0)
+        result |= *s1++ ^ *s2++;
+    return result == 0 ? 0 : 1;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/asymmetric_key.cpp b/keymaster/asymmetric_key.cpp
new file mode 100644
index 0000000..02a7f15
--- /dev/null
+++ b/keymaster/asymmetric_key.cpp
@@ -0,0 +1,245 @@
+/*
+ * 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 "asymmetric_key.h"
+
+#include <new>
+
+#include <openssl/asn1.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+
+#include "attestation_record.h"
+#include "openssl_err.h"
+#include "openssl_utils.h"
+
+namespace keymaster {
+
+keymaster_error_t AsymmetricKey::formatted_key_material(keymaster_key_format_t format,
+                                                        UniquePtr<uint8_t[]>* material,
+                                                        size_t* size) const {
+    if (format != KM_KEY_FORMAT_X509)
+        return KM_ERROR_UNSUPPORTED_KEY_FORMAT;
+
+    if (material == NULL || size == NULL)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    EVP_PKEY_Ptr pkey(EVP_PKEY_new());
+    if (!InternalToEvp(pkey.get()))
+        return TranslateLastOpenSslError();
+
+    int key_data_length = i2d_PUBKEY(pkey.get(), NULL);
+    if (key_data_length <= 0)
+        return TranslateLastOpenSslError();
+
+    material->reset(new (std::nothrow) uint8_t[key_data_length]);
+    if (material->get() == NULL)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    uint8_t* tmp = material->get();
+    if (i2d_PUBKEY(pkey.get(), &tmp) != key_data_length) {
+        material->reset();
+        return TranslateLastOpenSslError();
+    }
+
+    *size = key_data_length;
+    return KM_ERROR_OK;
+}
+
+static keymaster_error_t build_attestation_extension(const AuthorizationSet& tee_enforced,
+                                                     const AuthorizationSet& sw_enforced,
+                                                     X509_EXTENSION_Ptr* extension) {
+    ASN1_OBJECT_Ptr oid(
+        OBJ_txt2obj(kAttestionRecordOid, 1 /* accept numerical dotted string form only */));
+    if (!oid.get())
+        return TranslateLastOpenSslError();
+
+    UniquePtr<uint8_t[]> attest_bytes;
+    size_t attest_bytes_len;
+    keymaster_error_t error =
+        build_attestation_record(sw_enforced, tee_enforced, &attest_bytes, &attest_bytes_len);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    ASN1_OCTET_STRING_Ptr attest_str(ASN1_OCTET_STRING_new());
+    if (!attest_str.get() ||
+        !ASN1_OCTET_STRING_set(attest_str.get(), attest_bytes.get(), attest_bytes_len))
+        return TranslateLastOpenSslError();
+
+    extension->reset(
+        X509_EXTENSION_create_by_OBJ(nullptr, oid.get(), 0 /* not critical */, attest_str.get()));
+    if (!extension->get())
+        return TranslateLastOpenSslError();
+
+    return KM_ERROR_OK;
+}
+
+static bool add_public_key(EVP_PKEY* key, X509* certificate, keymaster_error_t* error) {
+    if (!X509_set_pubkey(certificate, key)) {
+        *error = TranslateLastOpenSslError();
+        return false;
+    }
+    return true;
+}
+
+static bool add_attestation_extension(const AuthorizationSet& tee_enforced,
+                                      const AuthorizationSet& sw_enforced, X509* certificate,
+                                      keymaster_error_t* error) {
+    X509_EXTENSION_Ptr attest_extension;
+    *error = build_attestation_extension(tee_enforced, sw_enforced, &attest_extension);
+    if (*error != KM_ERROR_OK)
+        return false;
+
+    if (!X509_add_ext(certificate, attest_extension.get() /* Don't release; copied */,
+                      -1 /* insert at end */)) {
+        *error = TranslateLastOpenSslError();
+        return false;
+    }
+
+    return true;
+}
+
+static keymaster_error_t get_certificate_blob(X509* certificate, keymaster_blob_t* blob) {
+    int len = i2d_X509(certificate, nullptr);
+    if (len < 0)
+        return TranslateLastOpenSslError();
+
+    uint8_t* data = new uint8_t[len];
+    if (!data)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    uint8_t* p = data;
+    i2d_X509(certificate, &p);
+
+    blob->data_length = len;
+    blob->data = data;
+
+    return KM_ERROR_OK;
+}
+
+static bool allocate_cert_chain(size_t entry_count, keymaster_cert_chain_t* chain,
+                                keymaster_error_t* error) {
+    if (chain->entries) {
+        for (size_t i = 0; i < chain->entry_count; ++i)
+            delete[] chain->entries[i].data;
+        delete[] chain->entries;
+    }
+
+    chain->entry_count = entry_count;
+    chain->entries = new keymaster_blob_t[entry_count];
+    if (!chain->entries) {
+        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        return false;
+    }
+    return true;
+}
+
+// Copies the intermediate and root certificates into chain, leaving the first slot for the leaf
+// certificate.
+static bool copy_attestation_chain(const KeymasterContext& context,
+                                   keymaster_algorithm_t sign_algorithm,
+                                   keymaster_cert_chain_t* chain, keymaster_error_t* error) {
+
+    UniquePtr<keymaster_cert_chain_t, CertificateChainDelete> attest_key_chain(
+        context.AttestationChain(sign_algorithm, error));
+    if (!attest_key_chain.get())
+        return false;
+
+    if (!allocate_cert_chain(attest_key_chain->entry_count + 1, chain, error))
+        return false;
+
+    chain->entries[0].data = nullptr;  // Leave empty for the leaf certificate.
+    chain->entries[0].data_length = 0;
+
+    for (size_t i = 0; i < attest_key_chain->entry_count; ++i) {
+        chain->entries[i + 1] = attest_key_chain->entries[i];
+        attest_key_chain->entries[i].data = nullptr;
+    }
+
+    return true;
+}
+
+keymaster_error_t AsymmetricKey::GenerateAttestation(const KeymasterContext& context,
+                                                     const AuthorizationSet& attest_params,
+                                                     const AuthorizationSet& tee_enforced,
+                                                     const AuthorizationSet& sw_enforced,
+                                                     keymaster_cert_chain_t* cert_chain) const {
+
+    keymaster_algorithm_t sign_algorithm;
+    if (!attest_params.GetTagValue(TAG_ALGORITHM, &sign_algorithm) ||
+        (sign_algorithm != KM_ALGORITHM_RSA && sign_algorithm != KM_ALGORITHM_EC))
+        return KM_ERROR_INCOMPATIBLE_ALGORITHM;
+
+    EVP_PKEY_Ptr pkey(EVP_PKEY_new());
+    if (!InternalToEvp(pkey.get()))
+        return TranslateLastOpenSslError();
+
+    X509_Ptr certificate(X509_new());
+    if (!certificate.get())
+        return TranslateLastOpenSslError();
+
+    if (!X509_set_version(certificate.get(), 2 /* version 3, but zero-based */))
+        return TranslateLastOpenSslError();
+
+    ASN1_INTEGER_Ptr serialNumber(ASN1_INTEGER_new());
+    if (!serialNumber.get() ||
+        !ASN1_INTEGER_set(
+            serialNumber.get(),
+            10000 /* TODO(swillden): Figure out what should go in serial number; probably a random
+                   * value */) ||
+        !X509_set_serialNumber(certificate.get(), serialNumber.get() /* Don't release; copied */))
+        return TranslateLastOpenSslError();
+
+    // TODO(swillden): Find useful values (if possible) for issuerName and subjectName.
+    X509_NAME_Ptr issuerName(X509_NAME_new());
+    if (!issuerName.get() ||
+        !X509_set_subject_name(certificate.get(), issuerName.get() /* Don't release; copied  */))
+        return TranslateLastOpenSslError();
+
+    X509_NAME_Ptr subjectName(X509_NAME_new());
+    if (!subjectName.get() ||
+        !X509_set_subject_name(certificate.get(), subjectName.get() /* Don't release; copied */))
+        return TranslateLastOpenSslError();
+
+    // TODO(swillden): Use key activity and expiration dates for notBefore and notAfter.
+    ASN1_TIME_Ptr notBefore(ASN1_TIME_new());
+    if (!notBefore.get() || !ASN1_TIME_set(notBefore.get(), 0) ||
+        !X509_set_notBefore(certificate.get(), notBefore.get() /* Don't release; copied */))
+        return TranslateLastOpenSslError();
+
+    ASN1_TIME_Ptr notAfter(ASN1_TIME_new());
+    if (!notAfter.get() || !ASN1_TIME_set(notAfter.get(), 10000) ||
+        !X509_set_notAfter(certificate.get(), notAfter.get() /* Don't release; copied */))
+        return TranslateLastOpenSslError();
+
+    keymaster_error_t error = KM_ERROR_OK;
+    EVP_PKEY_Ptr sign_key(context.AttestationKey(sign_algorithm, &error));
+
+    if (!sign_key.get() ||  //
+        !add_public_key(pkey.get(), certificate.get(), &error) ||
+        !add_attestation_extension(tee_enforced, sw_enforced, certificate.get(), &error))
+        return error;
+
+    if (!X509_sign(certificate.get(), sign_key.get(), EVP_sha256()))
+        return TranslateLastOpenSslError();
+
+    if (!copy_attestation_chain(context, sign_algorithm, cert_chain, &error))
+        return error;
+
+    return get_certificate_blob(certificate.get(), &cert_chain->entries[0]);
+}
+
+}  // namespace keymaster
diff --git a/keymaster/asymmetric_key.h b/keymaster/asymmetric_key.h
new file mode 100644
index 0000000..99ee585
--- /dev/null
+++ b/keymaster/asymmetric_key.h
@@ -0,0 +1,48 @@
+/*
+ * 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_ASYMMETRIC_KEY_H
+#define SYSTEM_KEYMASTER_ASYMMETRIC_KEY_H
+
+#include <openssl/evp.h>
+
+#include "key.h"
+
+namespace keymaster {
+
+class AsymmetricKey : public Key {
+  public:
+    AsymmetricKey(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+                  keymaster_error_t* error)
+        : Key(hw_enforced, sw_enforced, error) {}
+
+    keymaster_error_t formatted_key_material(keymaster_key_format_t format,
+                                             UniquePtr<uint8_t[]>* material,
+                                             size_t* size) const override;
+
+    keymaster_error_t GenerateAttestation(const KeymasterContext& context,
+                                          const AuthorizationSet& attest_params,
+                                          const AuthorizationSet& tee_enforced,
+                                          const AuthorizationSet& sw_enforced,
+                                          keymaster_cert_chain_t* certificate_chain) const override;
+
+    virtual bool InternalToEvp(EVP_PKEY* pkey) const = 0;
+    virtual bool EvpToInternal(const EVP_PKEY* pkey) = 0;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_ASYMMETRIC_KEY_H
diff --git a/keymaster/asymmetric_key_factory.cpp b/keymaster/asymmetric_key_factory.cpp
new file mode 100644
index 0000000..b06d0d8
--- /dev/null
+++ b/keymaster/asymmetric_key_factory.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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 <keymaster/asymmetric_key_factory.h>
+
+#include <keymaster/android_keymaster_utils.h>
+
+#include "asymmetric_key.h"
+#include "openssl_err.h"
+#include "openssl_utils.h"
+
+namespace keymaster {
+
+static const keymaster_key_format_t supported_import_formats[] = {KM_KEY_FORMAT_PKCS8};
+const keymaster_key_format_t*
+AsymmetricKeyFactory::SupportedImportFormats(size_t* format_count) const {
+    *format_count = array_length(supported_import_formats);
+    return supported_import_formats;
+}
+
+static const keymaster_key_format_t supported_export_formats[] = {KM_KEY_FORMAT_X509};
+const keymaster_key_format_t*
+AsymmetricKeyFactory::SupportedExportFormats(size_t* format_count) const {
+    *format_count = array_length(supported_export_formats);
+    return supported_export_formats;
+}
+
+keymaster_error_t AsymmetricKeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+                                                const AuthorizationSet& /* additional_params */,
+                                                const AuthorizationSet& hw_enforced,
+                                                const AuthorizationSet& sw_enforced,
+                                                UniquePtr<Key>* key) const {
+    UniquePtr<AsymmetricKey> asymmetric_key;
+    keymaster_error_t error = CreateEmptyKey(hw_enforced, sw_enforced, &asymmetric_key);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    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();
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey_deleter(pkey);
+
+    if (!asymmetric_key->EvpToInternal(pkey))
+        error = TranslateLastOpenSslError();
+    else
+        key->reset(asymmetric_key.release());
+
+    return error;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/attestation_record.cpp b/keymaster/attestation_record.cpp
new file mode 100644
index 0000000..809f7c8
--- /dev/null
+++ b/keymaster/attestation_record.cpp
@@ -0,0 +1,654 @@
+/*
+ * Copyright 2016 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 "attestation_record.h"
+
+#include <assert.h>
+
+#include <openssl/asn1t.h>
+
+#include "openssl_err.h"
+#include "openssl_utils.h"
+
+namespace keymaster {
+
+struct stack_st_ASN1_TYPE_Delete {
+    void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); }
+};
+
+struct ASN1_STRING_Delete {
+    void operator()(ASN1_STRING* p) { ASN1_STRING_free(p); }
+};
+
+struct ASN1_TYPE_Delete {
+    void operator()(ASN1_TYPE* p) { ASN1_TYPE_free(p); }
+};
+
+#define ASN1_INTEGER_SET STACK_OF(ASN1_INTEGER)
+
+typedef struct km_root_of_trust {
+    ASN1_OCTET_STRING* verified_boot_key;
+    ASN1_INTEGER* os_version;
+    ASN1_INTEGER* os_patchlevel;
+} KM_ROOT_OF_TRUST;
+
+ASN1_SEQUENCE(KM_ROOT_OF_TRUST) = {
+    ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_key, ASN1_OCTET_STRING),
+    ASN1_SIMPLE(KM_ROOT_OF_TRUST, os_version, ASN1_INTEGER),
+    ASN1_SIMPLE(KM_ROOT_OF_TRUST, os_patchlevel, ASN1_INTEGER),
+} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
+
+typedef struct km_auth_list {
+    ASN1_INTEGER_SET* purpose;
+    ASN1_INTEGER* algorithm;
+    ASN1_INTEGER* key_size;
+    ASN1_INTEGER_SET* block_mode;
+    ASN1_INTEGER_SET* digest;
+    ASN1_INTEGER_SET* padding;
+    ASN1_NULL* caller_nonce;
+    ASN1_INTEGER* min_mac_length;
+    ASN1_INTEGER_SET* kdf;
+    ASN1_INTEGER* ec_curve;
+    ASN1_INTEGER* rsa_public_exponent;
+    ASN1_NULL* ecies_single_hash_mode;
+    ASN1_NULL* include_unique_id;
+    ASN1_INTEGER* blob_usage_requirement;
+    ASN1_NULL* bootloader_only;
+    ASN1_INTEGER* active_date_time;
+    ASN1_INTEGER* origination_expire_date_time;
+    ASN1_INTEGER* usage_expire_date_time;
+    ASN1_INTEGER* min_seconds_between_ops;
+    ASN1_INTEGER* max_uses_per_boot;
+    ASN1_NULL* no_auth_required;
+    ASN1_INTEGER* user_auth_type;
+    ASN1_INTEGER* auth_timeout;
+    ASN1_NULL* allow_while_on_body;
+    ASN1_NULL* all_applications;
+    ASN1_OCTET_STRING* application_id;
+    ASN1_OCTET_STRING* application_data;
+    ASN1_INTEGER* creation_date_time;
+    ASN1_INTEGER* origin;
+    ASN1_NULL* rollback_resistant;
+    KM_ROOT_OF_TRUST* root_of_trust;
+    ASN1_INTEGER* os_version;
+    ASN1_INTEGER* os_patchlevel;
+    ASN1_OCTET_STRING* unique_id;
+} KM_AUTH_LIST;
+
+ASN1_SEQUENCE(KM_AUTH_LIST) = {
+    ASN1_IMP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.masked_tag()),
+    ASN1_IMP_SET_OF_OPT(KM_AUTH_LIST, block_mode, ASN1_INTEGER, TAG_BLOCK_MODE.masked_tag()),
+    ASN1_IMP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.masked_tag()),
+    ASN1_IMP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, caller_nonce, ASN1_NULL, TAG_CALLER_NONCE.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, min_mac_length, ASN1_INTEGER, TAG_MIN_MAC_LENGTH.masked_tag()),
+    ASN1_IMP_SET_OF_OPT(KM_AUTH_LIST, kdf, ASN1_INTEGER, TAG_KDF.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
+                 TAG_RSA_PUBLIC_EXPONENT.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, ecies_single_hash_mode, ASN1_NULL,
+                 TAG_ECIES_SINGLE_HASH_MODE.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, include_unique_id, ASN1_NULL, TAG_INCLUDE_UNIQUE_ID.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, blob_usage_requirement, ASN1_INTEGER,
+                 TAG_BLOB_USAGE_REQUIREMENTS.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, bootloader_only, ASN1_NULL, TAG_BOOTLOADER_ONLY.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
+                 TAG_ORIGINATION_EXPIRE_DATETIME.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
+                 TAG_USAGE_EXPIRE_DATETIME.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, min_seconds_between_ops, ASN1_INTEGER,
+                 TAG_MIN_SECONDS_BETWEEN_OPS.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, max_uses_per_boot, ASN1_INTEGER, TAG_MAX_USES_PER_BOOT.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL,
+                 TAG_ALLOW_WHILE_ON_BODY.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, all_applications, ASN1_NULL, TAG_ALL_APPLICATIONS.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, application_id, ASN1_OCTET_STRING, TAG_APPLICATION_ID.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, application_data, ASN1_OCTET_STRING,
+                 TAG_APPLICATION_DATA.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER,
+                 TAG_CREATION_DATETIME.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, rollback_resistant, ASN1_NULL, TAG_ROLLBACK_RESISTANT.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.masked_tag()),
+    ASN1_IMP_OPT(KM_AUTH_LIST, unique_id, ASN1_NULL, TAG_UNIQUE_ID.masked_tag()),
+} ASN1_SEQUENCE_END(KM_AUTH_LIST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
+
+typedef struct km_key_description {
+    KM_AUTH_LIST* software_enforced;
+    KM_AUTH_LIST* tee_enforced;
+} KM_KEY_DESCRIPTION;
+
+ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = {
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, software_enforced, KM_AUTH_LIST),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, tee_enforced, KM_AUTH_LIST),
+} ASN1_SEQUENCE_END(KM_KEY_DESCRIPTION);
+IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION);
+
+struct KM_AUTH_LIST_Delete {
+    void operator()(KM_AUTH_LIST* p) { KM_AUTH_LIST_free(p); }
+};
+
+struct KM_KEY_DESCRIPTION_Delete {
+    void operator()(KM_KEY_DESCRIPTION* p) { KM_KEY_DESCRIPTION_free(p); }
+};
+
+static uint32_t get_uint32_value(const keymaster_key_param_t& param) {
+    switch (keymaster_tag_get_type(param.tag)) {
+    case KM_ENUM:
+    case KM_ENUM_REP:
+        return param.enumerated;
+    case KM_UINT:
+    case KM_UINT_REP:
+        return param.integer;
+    default:
+        assert(false);
+        return 0xFFFFFFFF;
+    }
+}
+
+// Insert value in either the dest_integer or the dest_integer_set, whichever is provided.
+static keymaster_error_t insert_integer(ASN1_INTEGER* value, ASN1_INTEGER** dest_integer,
+                                        ASN1_INTEGER_SET** dest_integer_set) {
+    assert((dest_integer == nullptr) ^ (dest_integer_set == nullptr));
+    assert(value);
+
+    if (dest_integer_set) {
+        if (!*dest_integer_set)
+            *dest_integer_set = sk_ASN1_INTEGER_new_null();
+        if (!*dest_integer_set)
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        if (!sk_ASN1_INTEGER_push(*dest_integer_set, value))
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        return KM_ERROR_OK;
+
+    } else if (dest_integer) {
+        if (*dest_integer)
+            ASN1_INTEGER_free(*dest_integer);
+        *dest_integer = value;
+        return KM_ERROR_OK;
+    }
+
+    assert(false);  // Should never get here.
+    return KM_ERROR_OK;
+}
+
+// Put the contents of the keymaster AuthorizationSet auth_list in to the ASN.1 record structure,
+// record.
+static keymaster_error_t build_auth_list(const AuthorizationSet& auth_list, KM_AUTH_LIST* record) {
+
+    assert(record);
+
+    for (auto entry : auth_list) {
+
+        ASN1_INTEGER_SET** integer_set = nullptr;
+        ASN1_INTEGER** integer_ptr = nullptr;
+        ASN1_OCTET_STRING** string_ptr = nullptr;
+        ASN1_NULL** bool_ptr = nullptr;
+
+        switch (entry.tag) {
+
+        /* Ignored tags */
+        case KM_TAG_INVALID:
+        case KM_TAG_ASSOCIATED_DATA:
+        case KM_TAG_NONCE:
+        case KM_TAG_AUTH_TOKEN:
+        case KM_TAG_MAC_LENGTH:
+        case KM_TAG_ALL_USERS:
+        case KM_TAG_USER_ID:
+        case KM_TAG_USER_SECURE_ID:
+        case KM_TAG_EXPORTABLE:
+        case KM_TAG_RESET_SINCE_ID_ROTATION:
+            continue;
+
+        /* Non-repeating enumerations */
+        case KM_TAG_ALGORITHM:
+            integer_ptr = &record->algorithm;
+            break;
+        case KM_TAG_EC_CURVE:
+            integer_ptr = &record->ec_curve;
+            break;
+        case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+            integer_ptr = &record->blob_usage_requirement;
+            break;
+        case KM_TAG_USER_AUTH_TYPE:
+            integer_ptr = &record->user_auth_type;
+            break;
+        case KM_TAG_ORIGIN:
+            integer_ptr = &record->origin;
+            break;
+
+        /* Repeating enumerations */
+        case KM_TAG_PURPOSE:
+            integer_set = &record->purpose;
+            break;
+        case KM_TAG_BLOCK_MODE:
+            integer_set = &record->block_mode;
+            break;
+        case KM_TAG_PADDING:
+            integer_set = &record->padding;
+            break;
+        case KM_TAG_DIGEST:
+            integer_set = &record->digest;
+            break;
+        case KM_TAG_KDF:
+            integer_set = &record->kdf;
+            break;
+
+        /* Non-repeating unsigned integers */
+        case KM_TAG_KEY_SIZE:
+            integer_ptr = &record->key_size;
+            break;
+        case KM_TAG_MIN_MAC_LENGTH:
+            integer_ptr = &record->min_mac_length;
+            break;
+        case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
+            integer_ptr = &record->min_seconds_between_ops;
+            break;
+        case KM_TAG_MAX_USES_PER_BOOT:
+            integer_ptr = &record->max_uses_per_boot;
+            break;
+        case KM_TAG_AUTH_TIMEOUT:
+            integer_ptr = &record->auth_timeout;
+            break;
+
+        /* Non-repeating long unsigned integers */
+        case KM_TAG_RSA_PUBLIC_EXPONENT:
+            integer_ptr = &record->rsa_public_exponent;
+            break;
+
+        /* Dates */
+        case KM_TAG_ACTIVE_DATETIME:
+            integer_ptr = &record->active_date_time;
+            break;
+        case KM_TAG_ORIGINATION_EXPIRE_DATETIME:
+            integer_ptr = &record->origination_expire_date_time;
+            break;
+        case KM_TAG_USAGE_EXPIRE_DATETIME:
+            integer_ptr = &record->usage_expire_date_time;
+            break;
+        case KM_TAG_CREATION_DATETIME:
+            integer_ptr = &record->creation_date_time;
+            break;
+
+        /* Booleans */
+        case KM_TAG_CALLER_NONCE:
+            bool_ptr = &record->caller_nonce;
+            break;
+        case KM_TAG_ECIES_SINGLE_HASH_MODE:
+            bool_ptr = &record->ecies_single_hash_mode;
+            break;
+        case KM_TAG_BOOTLOADER_ONLY:
+            bool_ptr = &record->bootloader_only;
+            break;
+        case KM_TAG_NO_AUTH_REQUIRED:
+            bool_ptr = &record->no_auth_required;
+            break;
+        case KM_TAG_ALL_APPLICATIONS:
+            bool_ptr = &record->all_applications;
+            break;
+        case KM_TAG_ROLLBACK_RESISTANT:
+            bool_ptr = &record->rollback_resistant;
+            break;
+        case KM_TAG_INCLUDE_UNIQUE_ID:
+            bool_ptr = &record->include_unique_id;
+            break;
+        case KM_TAG_ALLOW_WHILE_ON_BODY:
+            bool_ptr = &record->allow_while_on_body;
+            break;
+
+        /* Byte arrays*/
+        case KM_TAG_APPLICATION_ID:
+            string_ptr = &record->application_id;
+            break;
+        case KM_TAG_APPLICATION_DATA:
+            string_ptr = &record->application_data;
+            break;
+        case KM_TAG_UNIQUE_ID:
+            string_ptr = &record->unique_id;
+            break;
+
+        /* Root of Trust components */
+        case KM_TAG_OS_VERSION:
+        case KM_TAG_OS_PATCHLEVEL:
+        case KM_TAG_ROOT_OF_TRUST:
+            if (!record->root_of_trust)
+                record->root_of_trust = KM_ROOT_OF_TRUST_new();
+            if (!record->root_of_trust)
+                return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+            switch (entry.tag) {
+            case KM_TAG_OS_VERSION:
+                integer_ptr = &record->root_of_trust->os_version;
+                break;
+            case KM_TAG_OS_PATCHLEVEL:
+                integer_ptr = &record->root_of_trust->os_patchlevel;
+                break;
+            case KM_TAG_ROOT_OF_TRUST:
+                string_ptr = &record->root_of_trust->verified_boot_key;
+                break;
+            default:
+                assert(false);  // Can't get here.
+            }
+            break;
+        }
+
+        keymaster_tag_type_t type = keymaster_tag_get_type(entry.tag);
+        switch (type) {
+        case KM_ENUM:
+        case KM_ENUM_REP:
+        case KM_UINT:
+        case KM_UINT_REP: {
+            assert((keymaster_tag_repeatable(entry.tag) && integer_set) ||
+                   (!keymaster_tag_repeatable(entry.tag) && integer_ptr));
+
+            UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> value(ASN1_INTEGER_new());
+            if (!value.get())
+                return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+            if (!ASN1_INTEGER_set(value.get(), get_uint32_value(entry)))
+                return TranslateLastOpenSslError();
+
+            insert_integer(value.release(), integer_ptr, integer_set);
+            break;
+        }
+
+        case KM_ULONG:
+        case KM_ULONG_REP:
+        case KM_DATE: {
+            assert((keymaster_tag_repeatable(entry.tag) && integer_set) ||
+                   (!keymaster_tag_repeatable(entry.tag) && integer_ptr));
+
+            UniquePtr<BIGNUM, BIGNUM_Delete> exponent(BN_new());
+            if (!exponent.get())
+                return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+            if (type == KM_DATE) {
+                if (!BN_set_word(exponent.get(), entry.date_time))
+                    return TranslateLastOpenSslError();
+            } else {
+                if (!BN_set_word(exponent.get(), entry.long_integer))
+                    return TranslateLastOpenSslError();
+            }
+
+            UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> value(
+                BN_to_ASN1_INTEGER(exponent.get(), nullptr));
+            if (!value.get())
+                return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+            insert_integer(value.release(), integer_ptr, integer_set);
+            break;
+        }
+
+        case KM_BOOL:
+            assert(bool_ptr);
+            if (!*bool_ptr)
+                *bool_ptr = ASN1_NULL_new();
+            if (!*bool_ptr)
+                return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+            break;
+
+        /* Byte arrays*/
+        case KM_BYTES:
+            assert(string_ptr);
+            if (!*string_ptr)
+                *string_ptr = ASN1_OCTET_STRING_new();
+            if (!*string_ptr)
+                return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+            if (!ASN1_OCTET_STRING_set(*string_ptr, entry.blob.data, entry.blob.data_length))
+                return TranslateLastOpenSslError();
+            break;
+
+        default:
+            return KM_ERROR_UNIMPLEMENTED;
+        }
+    }
+
+    return KM_ERROR_OK;
+}
+
+// Construct an ASN1.1 DER-encoded attestation record containing the values from sw_enforced and
+// tee_enforced.
+keymaster_error_t build_attestation_record(const AuthorizationSet& sw_enforced,
+                                           const AuthorizationSet& tee_enforced,
+                                           UniquePtr<uint8_t[]>* asn1_key_desc,
+                                           size_t* asn1_key_desc_len) {
+    assert(asn1_key_desc && asn1_key_desc_len);
+
+    UniquePtr<KM_KEY_DESCRIPTION, KM_KEY_DESCRIPTION_Delete> key_desc(KM_KEY_DESCRIPTION_new());
+    if (!key_desc.get())
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    keymaster_error_t error;
+
+    error = build_auth_list(sw_enforced, key_desc->software_enforced);
+    if (error != KM_ERROR_OK)
+        return error;
+    error = build_auth_list(tee_enforced, key_desc->tee_enforced);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    int len = i2d_KM_KEY_DESCRIPTION(key_desc.get(), nullptr);
+    if (len < 0)
+        return TranslateLastOpenSslError();
+    *asn1_key_desc_len = len;
+    asn1_key_desc->reset(new uint8_t[*asn1_key_desc_len]);
+    if (!asn1_key_desc->get())
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    uint8_t* p = asn1_key_desc->get();
+    len = i2d_KM_KEY_DESCRIPTION(key_desc.get(), &p);
+    if (len < 0)
+        return TranslateLastOpenSslError();
+
+    return KM_ERROR_OK;
+}
+
+// Copy all enumerated values with the specified tag from stack to auth_list.
+static bool get_repeated_enums(const stack_st_ASN1_INTEGER* stack, keymaster_tag_t tag,
+                               AuthorizationSet* auth_list) {
+    assert(keymaster_tag_get_type(tag) == KM_ENUM_REP);
+    for (size_t i = 0; i < sk_ASN1_INTEGER_num(stack); ++i) {
+        if (!auth_list->push_back(
+                keymaster_param_enum(tag, ASN1_INTEGER_get(sk_ASN1_INTEGER_value(stack, i)))))
+            return false;
+    }
+    return true;
+}
+
+// Add the specified integer tag/value pair to auth_list.
+template <keymaster_tag_type_t Type, keymaster_tag_t Tag, typename KeymasterEnum>
+static bool get_enum(const ASN1_INTEGER* asn1_int, TypedEnumTag<Type, Tag, KeymasterEnum> tag,
+                     AuthorizationSet* auth_list) {
+    if (!asn1_int)
+        return true;
+    return auth_list->push_back(tag, static_cast<KeymasterEnum>(ASN1_INTEGER_get(asn1_int)));
+}
+
+// Add the specified ulong tag/value pair to auth_list.
+static bool get_ulong(const ASN1_INTEGER* asn1_int, keymaster_tag_t tag,
+                      AuthorizationSet* auth_list) {
+    if (!asn1_int)
+        return true;
+    UniquePtr<BIGNUM, BIGNUM_Delete> bn(ASN1_INTEGER_to_BN(asn1_int, nullptr));
+    if (!bn.get())
+        return false;
+    uint64_t ulong = BN_get_word(bn.get());
+    return auth_list->push_back(keymaster_param_long(tag, ulong));
+}
+
+// Extract the values from the specified ASN.1 record and place them in auth_list.
+static keymaster_error_t extract_auth_list(const KM_AUTH_LIST* record,
+                                           AuthorizationSet* auth_list) {
+    // Purpose
+    if (!get_repeated_enums(record->purpose, TAG_PURPOSE, auth_list))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Algorithm
+    if (!get_enum(record->algorithm, TAG_ALGORITHM, auth_list))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Key size
+    if (record->key_size && !auth_list->push_back(TAG_KEY_SIZE, ASN1_INTEGER_get(record->key_size)))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Block mode
+    if (!get_repeated_enums(record->block_mode, TAG_BLOCK_MODE, auth_list))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Digest
+    if (!get_repeated_enums(record->digest, TAG_DIGEST, auth_list))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Padding
+    if (!get_repeated_enums(record->padding, TAG_PADDING, auth_list))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Caller NONCE
+    if (record->caller_nonce && !auth_list->push_back(TAG_CALLER_NONCE))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Min MAC length
+    if (record->min_mac_length &&
+        !auth_list->push_back(TAG_MIN_MAC_LENGTH, ASN1_INTEGER_get(record->min_mac_length)))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // EC curve
+    if (!get_enum(record->ec_curve, TAG_EC_CURVE, auth_list))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // RSA public exponent
+    if (!get_ulong(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // ECIES single hash mode
+    if (record->ecies_single_hash_mode && !auth_list->push_back(TAG_ECIES_SINGLE_HASH_MODE))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Blob usage requirement
+    if (!get_enum(record->blob_usage_requirement, TAG_BLOB_USAGE_REQUIREMENTS, auth_list))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Bootloader only
+    if (record->bootloader_only && !auth_list->push_back(TAG_BOOTLOADER_ONLY))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Active date time
+    if (!get_ulong(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Origination expire date time
+    if (!get_ulong(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME,
+                   auth_list))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Usage Expire date time
+    if (!get_ulong(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Min seconds between ops
+    if (record->min_seconds_between_ops &&
+        !auth_list->push_back(TAG_MIN_SECONDS_BETWEEN_OPS,
+                              ASN1_INTEGER_get(record->min_seconds_between_ops)))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Max uses per boot
+    if (record->max_uses_per_boot &&
+        !auth_list->push_back(TAG_MAX_USES_PER_BOOT, ASN1_INTEGER_get(record->max_uses_per_boot)))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // No auth required
+    if (record->no_auth_required && !auth_list->push_back(TAG_NO_AUTH_REQUIRED))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // User auth type
+    if (!get_enum(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Auth timeout
+    if (record->auth_timeout &&
+        !auth_list->push_back(TAG_AUTH_TIMEOUT, ASN1_INTEGER_get(record->auth_timeout)))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // All applications
+    if (record->all_applications && !auth_list->push_back(TAG_ALL_APPLICATIONS))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Application ID
+    if (record->application_id &&
+        !auth_list->push_back(TAG_APPLICATION_ID, record->application_id->data,
+                              record->application_id->length))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Application data
+    if (record->application_data &&
+        !auth_list->push_back(TAG_APPLICATION_DATA, record->application_data->data,
+                              record->application_data->length))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Creation date time
+    if (!get_ulong(record->creation_date_time, TAG_CREATION_DATETIME, auth_list))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Origin
+    if (!get_enum(record->origin, TAG_ORIGIN, auth_list))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Rollback resistant
+    if (record->rollback_resistant && !auth_list->push_back(TAG_ROLLBACK_RESISTANT))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // Root of trust
+    if (record->root_of_trust) {
+        KM_ROOT_OF_TRUST* rot = record->root_of_trust;
+        if (!rot->verified_boot_key || !rot->os_version || !rot->os_patchlevel)
+            return KM_ERROR_INVALID_KEY_BLOB;
+
+        if (!auth_list->push_back(TAG_OS_VERSION, ASN1_INTEGER_get(rot->os_version)) ||
+            !auth_list->push_back(TAG_OS_PATCHLEVEL, ASN1_INTEGER_get(rot->os_patchlevel)) ||
+            !auth_list->push_back(TAG_ROOT_OF_TRUST, rot->verified_boot_key->data,
+                                  rot->verified_boot_key->length))
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    return KM_ERROR_OK;
+}
+
+// Parse the DER-encoded attestation record, placing the results in software_enforced and
+// tee_enforced.
+keymaster_error_t parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+                                           AuthorizationSet* software_enforced,
+                                           AuthorizationSet* tee_enforced) {
+    const uint8_t* p = asn1_key_desc;
+    UniquePtr<KM_KEY_DESCRIPTION, KM_KEY_DESCRIPTION_Delete> record(
+        d2i_KM_KEY_DESCRIPTION(nullptr, &p, asn1_key_desc_len));
+    if (!record.get())
+        return TranslateLastOpenSslError();
+
+    keymaster_error_t error = extract_auth_list(record->software_enforced, software_enforced);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    return extract_auth_list(record->tee_enforced, tee_enforced);
+}
+
+}  // namepace keymaster
diff --git a/keymaster/attestation_record.h b/keymaster/attestation_record.h
new file mode 100644
index 0000000..3cd5dde
--- /dev/null
+++ b/keymaster/attestation_record.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016 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_ATTESTATION_RECORD_H_
+#define SYSTEM_KEYMASTER_ATTESTATION_RECORD_H_
+
+#include <hardware/keymaster_defs.h>
+
+#include <keymaster/authorization_set.h>
+
+namespace keymaster {
+
+/**
+ * The OID for Android attestation records.  For the curious, it breaks down as follows:
+ *
+ * 1 = ISO
+ * 3 = org
+ * 6 = DoD (Huh? OIDs are weird.)
+ * 1 = IANA
+ * 4 = Private
+ * 1 = Enterprises
+ * 11129 = Google
+ * 2 = Google security
+ * 1 = certificate extension
+ * 17 = Android attestation extension.
+ */
+static const char kAttestionRecordOid[] = "1.3.6.1.4.1.11129.2.1.17";
+
+keymaster_error_t build_attestation_record(const AuthorizationSet& software_enforced,
+                                           const AuthorizationSet& tee_enforced,
+                                           UniquePtr<uint8_t[]>* asn1_key_desc,
+                                           size_t* asn1_key_desc_len);
+
+keymaster_error_t parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+                                           AuthorizationSet* software_enforced,
+                                           AuthorizationSet* tee_enforced);
+}
+
+#endif  // SYSTEM_KEYMASTER_ATTESTATION_RECORD_H_
diff --git a/keymaster/attestation_record_test.cpp b/keymaster/attestation_record_test.cpp
new file mode 100644
index 0000000..21a7eee
--- /dev/null
+++ b/keymaster/attestation_record_test.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016 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 <fstream>
+
+#include <gtest/gtest.h>
+
+#include "android_keymaster_test_utils.h"
+#include "attestation_record.h"
+
+namespace keymaster {
+namespace test {
+
+TEST(AttestTest, Simple) {
+    AuthorizationSet hw_set(AuthorizationSetBuilder()
+                                .RsaSigningKey(512, 3)
+                                .Digest(KM_DIGEST_SHA_2_256)
+                                .Digest(KM_DIGEST_SHA_2_384)
+                                .Authorization(TAG_ROOT_OF_TRUST, "foo", 3)
+                                .Authorization(TAG_OS_VERSION, 60000)
+                                .Authorization(TAG_OS_PATCHLEVEL, 201512)
+                                .Authorization(TAG_APPLICATION_ID, "bar", 3));
+    AuthorizationSet sw_set(AuthorizationSetBuilder().Authorization(TAG_ACTIVE_DATETIME, 10));
+
+    UniquePtr<uint8_t[]> asn1;
+    size_t asn1_len;
+    EXPECT_EQ(KM_ERROR_OK, build_attestation_record(sw_set, hw_set, &asn1, &asn1_len));
+    EXPECT_GT(asn1_len, 0U);
+
+    std::ofstream output("attest.der",
+                         std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
+    if (output)
+        output.write(reinterpret_cast<const char*>(asn1.get()), asn1_len);
+    output.close();
+
+    AuthorizationSet parsed_hw_set;
+    AuthorizationSet parsed_sw_set;
+    EXPECT_EQ(KM_ERROR_OK,
+              parse_attestation_record(asn1.get(), asn1_len, &parsed_sw_set, &parsed_hw_set));
+
+    hw_set.Sort();
+    sw_set.Sort();
+    parsed_hw_set.Sort();
+    parsed_sw_set.Sort();
+    EXPECT_EQ(hw_set, parsed_hw_set);
+    EXPECT_EQ(sw_set, parsed_sw_set);
+}
+
+}  // namespace test
+}  // namespace keymaster
diff --git a/keymaster/auth_encrypted_key_blob.cpp b/keymaster/auth_encrypted_key_blob.cpp
new file mode 100644
index 0000000..655bc12
--- /dev/null
+++ b/keymaster/auth_encrypted_key_blob.cpp
@@ -0,0 +1,137 @@
+/*
+ * 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;
+}
+
+static keymaster_error_t DeserializeUnversionedBlob(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;
+
+    if (!nonce->reserve(OCB_NONCE_LENGTH) || !tag->reserve(OCB_TAG_LENGTH))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    if (!copy_from_buf(buf_ptr, end, nonce->peek_write(), OCB_NONCE_LENGTH) ||
+        !encrypted_key_material->Deserialize(buf_ptr, end) ||
+        !copy_from_buf(buf_ptr, end, tag->peek_write(), OCB_TAG_LENGTH) ||
+        !hw_enforced->Deserialize(buf_ptr, end) ||  //
+        !sw_enforced->Deserialize(buf_ptr, end)) {
+        LOG_D("Failed to deserialize unversioned blob (may be a HW-backed key)", 0);
+        return KM_ERROR_INVALID_KEY_BLOB;
+    }
+    if (!nonce->advance_write(OCB_NONCE_LENGTH) || !tag->advance_write(OCB_TAG_LENGTH))
+        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) {
+    if (!key_blob.key_material || key_blob.key_material_size == 0)
+        return KM_ERROR_INVALID_KEY_BLOB;
+
+    const uint8_t* tmp = key_blob.key_material;
+    const uint8_t** buf_ptr = &tmp;
+    const uint8_t* end = tmp + key_blob.key_material_size;
+
+    if (end <= *buf_ptr)
+        return KM_ERROR_INVALID_KEY_BLOB;
+
+    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)) {
+        // 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_D("Failed to deserialize versioned key blob.  Assuming unversioned.", 0);
+        return DeserializeUnversionedBlob(key_blob, encrypted_key_material, hw_enforced,
+                                          sw_enforced, nonce, tag);
+    }
+    return KM_ERROR_OK;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/auth_encrypted_key_blob.h b/keymaster/auth_encrypted_key_blob.h
new file mode 100644
index 0000000..b987d77
--- /dev/null
+++ b/keymaster/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/keymaster/authorization_set.cpp b/keymaster/authorization_set.cpp
new file mode 100644
index 0000000..09093c9
--- /dev/null
+++ b/keymaster/authorization_set.cpp
@@ -0,0 +1,616 @@
+/*
+ * Copyright (C) 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 <keymaster/authorization_set.h>
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <new>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/logger.h>
+
+namespace keymaster {
+
+static inline bool is_blob_tag(keymaster_tag_t tag) {
+    return (keymaster_tag_get_type(tag) == KM_BYTES || keymaster_tag_get_type(tag) == KM_BIGNUM);
+}
+
+const size_t STARTING_ELEMS_CAPACITY = 8;
+
+AuthorizationSet::AuthorizationSet(AuthorizationSetBuilder& builder) {
+    elems_ = builder.set.elems_;
+    builder.set.elems_ = NULL;
+
+    elems_size_ = builder.set.elems_size_;
+    builder.set.elems_size_ = 0;
+
+    elems_capacity_ = builder.set.elems_capacity_;
+    builder.set.elems_capacity_ = 0;
+
+    indirect_data_ = builder.set.indirect_data_;
+    builder.set.indirect_data_ = NULL;
+
+    indirect_data_capacity_ = builder.set.indirect_data_capacity_;
+    builder.set.indirect_data_capacity_ = 0;
+
+    indirect_data_size_ = builder.set.indirect_data_size_;
+    builder.set.indirect_data_size_ = 0;
+
+    error_ = builder.set.error_;
+    builder.set.error_ = OK;
+}
+
+AuthorizationSet::~AuthorizationSet() {
+    FreeData();
+}
+
+bool AuthorizationSet::reserve_elems(size_t count) {
+    if (is_valid() != OK)
+        return false;
+
+    if (count >= elems_capacity_) {
+        keymaster_key_param_t* new_elems = new (std::nothrow) keymaster_key_param_t[count];
+        if (new_elems == NULL) {
+            set_invalid(ALLOCATION_FAILURE);
+            return false;
+        }
+        memcpy(new_elems, elems_, sizeof(*elems_) * elems_size_);
+        delete[] elems_;
+        elems_ = new_elems;
+        elems_capacity_ = count;
+    }
+    return true;
+}
+
+bool AuthorizationSet::reserve_indirect(size_t length) {
+    if (is_valid() != OK)
+        return false;
+
+    if (length > indirect_data_capacity_) {
+        uint8_t* new_data = new (std::nothrow) uint8_t[length];
+        if (new_data == NULL) {
+            set_invalid(ALLOCATION_FAILURE);
+            return false;
+        }
+        memcpy(new_data, indirect_data_, indirect_data_size_);
+
+        // Fix up the data pointers to point into the new region.
+        for (size_t i = 0; i < elems_size_; ++i) {
+            if (is_blob_tag(elems_[i].tag))
+                elems_[i].blob.data = new_data + (elems_[i].blob.data - indirect_data_);
+        }
+        delete[] indirect_data_;
+        indirect_data_ = new_data;
+        indirect_data_capacity_ = length;
+    }
+    return true;
+}
+
+bool AuthorizationSet::Reinitialize(const keymaster_key_param_t* elems, const size_t count) {
+    FreeData();
+
+    if (elems == NULL || count == 0) {
+        error_ = OK;
+        return true;
+    }
+
+    if (!reserve_elems(count))
+        return false;
+
+    if (!reserve_indirect(ComputeIndirectDataSize(elems, count)))
+        return false;
+
+    memcpy(elems_, elems, sizeof(keymaster_key_param_t) * count);
+    elems_size_ = count;
+    CopyIndirectData();
+    error_ = OK;
+    return true;
+}
+
+void AuthorizationSet::set_invalid(Error error) {
+    FreeData();
+    error_ = error;
+}
+
+void AuthorizationSet::Sort() {
+    qsort(elems_, elems_size_, sizeof(*elems_),
+          reinterpret_cast<int (*)(const void*, const void*)>(keymaster_param_compare));
+}
+
+void AuthorizationSet::Deduplicate() {
+    Sort();
+
+    size_t invalid_count = 0;
+    for (size_t i = 1; i < size(); ++i) {
+        if (elems_[i - 1].tag == KM_TAG_INVALID)
+            ++invalid_count;
+        else if (keymaster_param_compare(elems_ + i - 1, elems_ + i) == 0) {
+            // Mark dups as invalid.  Note that this "leaks" the data referenced by KM_BYTES and
+            // KM_BIGNUM entries, but those are just pointers into indirect_data_, so it will all
+            // get cleaned up.
+            elems_[i - 1].tag = KM_TAG_INVALID;
+            ++invalid_count;
+        }
+    }
+    if (size() > 0 && elems_[size() - 1].tag == KM_TAG_INVALID)
+        ++invalid_count;
+
+    if (invalid_count == 0)
+        return;
+
+    Sort();
+
+    // Since KM_TAG_INVALID == 0, all of the invalid entries are first.
+    elems_size_ -= invalid_count;
+    memmove(elems_, elems_ + invalid_count, size() * sizeof(*elems_));
+}
+
+void AuthorizationSet::CopyToParamSet(keymaster_key_param_set_t* set) const {
+    assert(set);
+
+    set->length = size();
+    set->params =
+        reinterpret_cast<keymaster_key_param_t*>(malloc(sizeof(keymaster_key_param_t) * size()));
+
+    for (size_t i = 0; i < size(); ++i) {
+        const keymaster_key_param_t src = (*this)[i];
+        keymaster_key_param_t& dst(set->params[i]);
+
+        dst = src;
+        keymaster_tag_type_t type = keymaster_tag_get_type(src.tag);
+        if (type == KM_BIGNUM || type == KM_BYTES) {
+            void* tmp = malloc(src.blob.data_length);
+            memcpy(tmp, src.blob.data, src.blob.data_length);
+            dst.blob.data = reinterpret_cast<uint8_t*>(tmp);
+        }
+    }
+}
+
+int AuthorizationSet::find(keymaster_tag_t tag, int begin) const {
+    if (is_valid() != OK)
+        return -1;
+
+    int i = ++begin;
+    while (i < (int)elems_size_ && elems_[i].tag != tag)
+        ++i;
+    if (i == (int)elems_size_)
+        return -1;
+    else
+        return i;
+}
+
+bool AuthorizationSet::erase(size_t index) {
+    if (index >= size())
+        return false;
+
+    --elems_size_;
+    for (size_t i = index; i < elems_size_; ++i)
+        elems_[i] = elems_[i + 1];
+    return true;
+}
+
+keymaster_key_param_t empty_set = {KM_TAG_INVALID, {}};
+keymaster_key_param_t& AuthorizationSet::operator[](int at) {
+    if (is_valid() == OK && at < (int)elems_size_) {
+        return elems_[at];
+    }
+    empty_set = {KM_TAG_INVALID, {}};
+    return empty_set;
+}
+
+keymaster_key_param_t AuthorizationSet::operator[](int at) const {
+    if (is_valid() == OK && at < (int)elems_size_) {
+        return elems_[at];
+    }
+    empty_set = {KM_TAG_INVALID, {}};
+    return empty_set;
+}
+
+bool AuthorizationSet::push_back(const keymaster_key_param_set_t& set) {
+    if (is_valid() != OK)
+        return false;
+
+    if (!reserve_elems(elems_size_ + set.length))
+        return false;
+
+    if (!reserve_indirect(indirect_data_size_ + ComputeIndirectDataSize(set.params, set.length)))
+        return false;
+
+    for (size_t i = 0; i < set.length; ++i)
+        if (!push_back(set.params[i]))
+            return false;
+
+    return true;
+}
+
+bool AuthorizationSet::push_back(keymaster_key_param_t elem) {
+    if (is_valid() != OK)
+        return false;
+
+    if (elems_size_ >= elems_capacity_)
+        if (!reserve_elems(elems_capacity_ ? elems_capacity_ * 2 : STARTING_ELEMS_CAPACITY))
+            return false;
+
+    if (is_blob_tag(elem.tag)) {
+        if (indirect_data_capacity_ - indirect_data_size_ < elem.blob.data_length)
+            if (!reserve_indirect(2 * (indirect_data_capacity_ + elem.blob.data_length)))
+                return false;
+
+        memcpy(indirect_data_ + indirect_data_size_, elem.blob.data, elem.blob.data_length);
+        elem.blob.data = indirect_data_ + indirect_data_size_;
+        indirect_data_size_ += elem.blob.data_length;
+    }
+
+    elems_[elems_size_++] = elem;
+    return true;
+}
+
+static size_t serialized_size(const keymaster_key_param_t& param) {
+    switch (keymaster_tag_get_type(param.tag)) {
+    case KM_INVALID:
+        return sizeof(uint32_t);
+    case KM_ENUM:
+    case KM_ENUM_REP:
+    case KM_UINT:
+    case KM_UINT_REP:
+        return sizeof(uint32_t) * 2;
+    case KM_ULONG:
+    case KM_ULONG_REP:
+    case KM_DATE:
+        return sizeof(uint32_t) + sizeof(uint64_t);
+    case KM_BOOL:
+        return sizeof(uint32_t) + 1;
+    case KM_BIGNUM:
+    case KM_BYTES:
+        return sizeof(uint32_t) * 3;
+    }
+
+    return sizeof(uint32_t);
+}
+
+static uint8_t* serialize(const keymaster_key_param_t& param, uint8_t* buf, const uint8_t* end,
+                          const uint8_t* indirect_base) {
+    buf = append_uint32_to_buf(buf, end, param.tag);
+    switch (keymaster_tag_get_type(param.tag)) {
+    case KM_INVALID:
+        break;
+    case KM_ENUM:
+    case KM_ENUM_REP:
+        buf = append_uint32_to_buf(buf, end, param.enumerated);
+        break;
+    case KM_UINT:
+    case KM_UINT_REP:
+        buf = append_uint32_to_buf(buf, end, param.integer);
+        break;
+    case KM_ULONG:
+    case KM_ULONG_REP:
+        buf = append_uint64_to_buf(buf, end, param.long_integer);
+        break;
+    case KM_DATE:
+        buf = append_uint64_to_buf(buf, end, param.date_time);
+        break;
+    case KM_BOOL:
+        if (buf < end)
+            *buf = static_cast<uint8_t>(param.boolean);
+        buf++;
+        break;
+    case KM_BIGNUM:
+    case KM_BYTES:
+        buf = append_uint32_to_buf(buf, end, param.blob.data_length);
+        buf = append_uint32_to_buf(buf, end, param.blob.data - indirect_base);
+        break;
+    }
+    return buf;
+}
+
+static bool deserialize(keymaster_key_param_t* param, const uint8_t** buf_ptr, const uint8_t* end,
+                        const uint8_t* indirect_base, const uint8_t* indirect_end) {
+    if (!copy_uint32_from_buf(buf_ptr, end, &param->tag))
+        return false;
+
+    switch (keymaster_tag_get_type(param->tag)) {
+    case KM_INVALID:
+        return false;
+    case KM_ENUM:
+    case KM_ENUM_REP:
+        return copy_uint32_from_buf(buf_ptr, end, &param->enumerated);
+    case KM_UINT:
+    case KM_UINT_REP:
+        return copy_uint32_from_buf(buf_ptr, end, &param->integer);
+    case KM_ULONG:
+    case KM_ULONG_REP:
+        return copy_uint64_from_buf(buf_ptr, end, &param->long_integer);
+    case KM_DATE:
+        return copy_uint64_from_buf(buf_ptr, end, &param->date_time);
+        break;
+    case KM_BOOL:
+        if (*buf_ptr < end) {
+            param->boolean = static_cast<bool>(**buf_ptr);
+            (*buf_ptr)++;
+            return true;
+        }
+        return false;
+
+    case KM_BIGNUM:
+    case KM_BYTES: {
+        uint32_t offset;
+        if (!copy_uint32_from_buf(buf_ptr, end, &param->blob.data_length) ||
+            !copy_uint32_from_buf(buf_ptr, end, &offset))
+            return false;
+        if (param->blob.data_length + offset < param->blob.data_length ||  // Overflow check
+            static_cast<ptrdiff_t>(offset) > indirect_end - indirect_base ||
+            static_cast<ptrdiff_t>(offset + param->blob.data_length) > indirect_end - indirect_base)
+            return false;
+        param->blob.data = indirect_base + offset;
+        return true;
+    }
+    }
+
+    return false;
+}
+
+size_t AuthorizationSet::SerializedSizeOfElements() const {
+    size_t size = 0;
+    for (size_t i = 0; i < elems_size_; ++i) {
+        size += serialized_size(elems_[i]);
+    }
+    return size;
+}
+
+size_t AuthorizationSet::SerializedSize() const {
+    return sizeof(uint32_t) +           // Size of indirect_data_
+           indirect_data_size_ +        // indirect_data_
+           sizeof(uint32_t) +           // Number of elems_
+           sizeof(uint32_t) +           // Size of elems_
+           SerializedSizeOfElements();  // elems_
+}
+
+uint8_t* AuthorizationSet::Serialize(uint8_t* buf, const uint8_t* end) const {
+    buf = append_size_and_data_to_buf(buf, end, indirect_data_, indirect_data_size_);
+    buf = append_uint32_to_buf(buf, end, elems_size_);
+    buf = append_uint32_to_buf(buf, end, SerializedSizeOfElements());
+    for (size_t i = 0; i < elems_size_; ++i) {
+        buf = serialize(elems_[i], buf, end, indirect_data_);
+    }
+    return buf;
+}
+
+bool AuthorizationSet::DeserializeIndirectData(const uint8_t** buf_ptr, const uint8_t* end) {
+    UniquePtr<uint8_t[]> indirect_buf;
+    if (!copy_size_and_data_from_buf(buf_ptr, end, &indirect_data_size_, &indirect_buf)) {
+        LOG_E("Malformed data found in AuthorizationSet deserialization", 0);
+        set_invalid(MALFORMED_DATA);
+        return false;
+    }
+    indirect_data_ = indirect_buf.release();
+    return true;
+}
+
+bool AuthorizationSet::DeserializeElementsData(const uint8_t** buf_ptr, const uint8_t* end) {
+    uint32_t elements_count;
+    uint32_t elements_size;
+    if (!copy_uint32_from_buf(buf_ptr, end, &elements_count) ||
+        !copy_uint32_from_buf(buf_ptr, end, &elements_size)) {
+        LOG_E("Malformed data found in AuthorizationSet deserialization", 0);
+        set_invalid(MALFORMED_DATA);
+        return false;
+    }
+
+    // Note that the following validation of elements_count is weak, but it prevents allocation of
+    // elems_ arrays which are clearly too large to be reasonable.
+    if (static_cast<ptrdiff_t>(elements_size) > end - *buf_ptr ||
+        elements_count * sizeof(uint32_t) > elements_size ||
+        *buf_ptr + (elements_count * sizeof(*elems_)) < *buf_ptr) {
+        LOG_E("Malformed data found in AuthorizationSet deserialization", 0);
+        set_invalid(MALFORMED_DATA);
+        return false;
+    }
+
+    if (!reserve_elems(elements_count))
+        return false;
+
+    uint8_t* indirect_end = indirect_data_ + indirect_data_size_;
+    const uint8_t* elements_end = *buf_ptr + elements_size;
+    for (size_t i = 0; i < elements_count; ++i) {
+        if (!deserialize(elems_ + i, buf_ptr, elements_end, indirect_data_, indirect_end)) {
+            LOG_E("Malformed data found in AuthorizationSet deserialization", 0);
+            set_invalid(MALFORMED_DATA);
+            return false;
+        }
+    }
+    elems_size_ = elements_count;
+    return true;
+}
+
+bool AuthorizationSet::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    FreeData();
+
+    if (!DeserializeIndirectData(buf_ptr, end) || !DeserializeElementsData(buf_ptr, end))
+        return false;
+
+    if (indirect_data_size_ != ComputeIndirectDataSize(elems_, elems_size_)) {
+        LOG_E("Malformed data found in AuthorizationSet deserialization", 0);
+        set_invalid(MALFORMED_DATA);
+        return false;
+    }
+    return true;
+}
+
+void AuthorizationSet::Clear() {
+    memset_s(elems_, 0, elems_size_ * sizeof(keymaster_key_param_t));
+    memset_s(indirect_data_, 0, indirect_data_size_);
+    elems_size_ = 0;
+    indirect_data_size_ = 0;
+}
+
+void AuthorizationSet::FreeData() {
+    Clear();
+
+    delete[] elems_;
+    delete[] indirect_data_;
+
+    elems_ = NULL;
+    indirect_data_ = NULL;
+    elems_capacity_ = 0;
+    indirect_data_capacity_ = 0;
+    error_ = OK;
+}
+
+/* static */
+size_t AuthorizationSet::ComputeIndirectDataSize(const keymaster_key_param_t* elems, size_t count) {
+    size_t size = 0;
+    for (size_t i = 0; i < count; ++i) {
+        if (is_blob_tag(elems[i].tag)) {
+            size += elems[i].blob.data_length;
+        }
+    }
+    return size;
+}
+
+void AuthorizationSet::CopyIndirectData() {
+    memset_s(indirect_data_, 0, indirect_data_capacity_);
+
+    uint8_t* indirect_data_pos = indirect_data_;
+    for (size_t i = 0; i < elems_size_; ++i) {
+        assert(indirect_data_pos <= indirect_data_ + indirect_data_capacity_);
+        if (is_blob_tag(elems_[i].tag)) {
+            memcpy(indirect_data_pos, elems_[i].blob.data, elems_[i].blob.data_length);
+            elems_[i].blob.data = indirect_data_pos;
+            indirect_data_pos += elems_[i].blob.data_length;
+        }
+    }
+    assert(indirect_data_pos == indirect_data_ + indirect_data_capacity_);
+    indirect_data_size_ = indirect_data_pos - indirect_data_;
+}
+
+size_t AuthorizationSet::GetTagCount(keymaster_tag_t tag) const {
+    size_t count = 0;
+    for (int pos = -1; (pos = find(tag, pos)) != -1;)
+        ++count;
+    return count;
+}
+
+bool AuthorizationSet::GetTagValueEnum(keymaster_tag_t tag, uint32_t* val) const {
+    int pos = find(tag);
+    if (pos == -1) {
+        return false;
+    }
+    *val = elems_[pos].enumerated;
+    return true;
+}
+
+bool AuthorizationSet::GetTagValueEnumRep(keymaster_tag_t tag, size_t instance,
+                                          uint32_t* val) const {
+    size_t count = 0;
+    int pos = -1;
+    while (count <= instance) {
+        pos = find(tag, pos);
+        if (pos == -1) {
+            return false;
+        }
+        ++count;
+    }
+    *val = elems_[pos].enumerated;
+    return true;
+}
+
+bool AuthorizationSet::GetTagValueInt(keymaster_tag_t tag, uint32_t* val) const {
+    int pos = find(tag);
+    if (pos == -1) {
+        return false;
+    }
+    *val = elems_[pos].integer;
+    return true;
+}
+
+bool AuthorizationSet::GetTagValueIntRep(keymaster_tag_t tag, size_t instance,
+                                         uint32_t* val) const {
+    size_t count = 0;
+    int pos = -1;
+    while (count <= instance) {
+        pos = find(tag, pos);
+        if (pos == -1) {
+            return false;
+        }
+        ++count;
+    }
+    *val = elems_[pos].integer;
+    return true;
+}
+
+bool AuthorizationSet::GetTagValueLong(keymaster_tag_t tag, uint64_t* val) const {
+    int pos = find(tag);
+    if (pos == -1) {
+        return false;
+    }
+    *val = elems_[pos].long_integer;
+    return true;
+}
+
+bool AuthorizationSet::GetTagValueLongRep(keymaster_tag_t tag, size_t instance,
+                                          uint64_t* val) const {
+    size_t count = 0;
+    int pos = -1;
+    while (count <= instance) {
+        pos = find(tag, pos);
+        if (pos == -1) {
+            return false;
+        }
+        ++count;
+    }
+    *val = elems_[pos].long_integer;
+    return true;
+}
+
+bool AuthorizationSet::GetTagValueDate(keymaster_tag_t tag, uint64_t* val) const {
+    int pos = find(tag);
+    if (pos == -1) {
+        return false;
+    }
+    *val = elems_[pos].date_time;
+    return true;
+}
+
+bool AuthorizationSet::GetTagValueBlob(keymaster_tag_t tag, keymaster_blob_t* val) const {
+    int pos = find(tag);
+    if (pos == -1) {
+        return false;
+    }
+    *val = elems_[pos].blob;
+    return true;
+}
+
+bool AuthorizationSet::GetTagValueBool(keymaster_tag_t tag) const {
+    int pos = find(tag);
+    if (pos == -1) {
+        return false;
+    }
+    assert(elems_[pos].boolean);
+    return elems_[pos].boolean;
+}
+
+bool AuthorizationSet::ContainsEnumValue(keymaster_tag_t tag, uint32_t value) const {
+    for (auto& entry : *this)
+        if (entry.tag == tag && entry.enumerated == value)
+            return true;
+    return false;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/authorization_set_test.cpp b/keymaster/authorization_set_test.cpp
new file mode 100644
index 0000000..ddc7df3
--- /dev/null
+++ b/keymaster/authorization_set_test.cpp
@@ -0,0 +1,630 @@
+/*
+ * Copyright (C) 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 <gtest/gtest.h>
+
+#include <keymaster/authorization_set.h>
+#include <keymaster/android_keymaster_utils.h>
+
+#include "android_keymaster_test_utils.h"
+
+namespace keymaster {
+
+namespace test {
+
+TEST(Construction, ListProvided) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_USER_ID, 7),
+        Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD),
+        Authorization(TAG_APPLICATION_ID, "my_app", 6), Authorization(TAG_KEY_SIZE, 256),
+        Authorization(TAG_AUTH_TIMEOUT, 300),
+    };
+    AuthorizationSet set(params, array_length(params));
+    EXPECT_EQ(8U, set.size());
+}
+
+TEST(Construction, Copy) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_USER_ID, 7),
+        Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD),
+        Authorization(TAG_APPLICATION_ID, "my_app", 6), Authorization(TAG_KEY_SIZE, 256),
+        Authorization(TAG_AUTH_TIMEOUT, 300),
+    };
+    AuthorizationSet set(params, array_length(params));
+    AuthorizationSet set2(set);
+    EXPECT_EQ(set, set2);
+}
+
+TEST(Construction, NullProvided) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+    };
+
+    AuthorizationSet set1(params, 0);
+    EXPECT_EQ(0U, set1.size());
+    EXPECT_EQ(AuthorizationSet::OK, set1.is_valid());
+
+    AuthorizationSet set2(reinterpret_cast<keymaster_key_param_t*>(NULL), array_length(params));
+    EXPECT_EQ(0U, set2.size());
+    EXPECT_EQ(AuthorizationSet::OK, set2.is_valid());
+}
+
+TEST(Lookup, NonRepeated) {
+    AuthorizationSet set(AuthorizationSetBuilder()
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                             .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                             .Authorization(TAG_USER_ID, 7)
+                             .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
+                             .Authorization(TAG_APPLICATION_ID, "my_app", 6)
+                             .Authorization(TAG_KEY_SIZE, 256)
+                             .Authorization(TAG_AUTH_TIMEOUT, 300));
+
+    EXPECT_EQ(8U, set.size());
+
+    int pos = set.find(TAG_ALGORITHM);
+    ASSERT_NE(-1, pos);
+    EXPECT_EQ(KM_TAG_ALGORITHM, set[pos].tag);
+    EXPECT_EQ(KM_ALGORITHM_RSA, set[pos].enumerated);
+
+    pos = set.find(TAG_MAC_LENGTH);
+    EXPECT_EQ(-1, pos);
+
+    uint32_t int_val = 0;
+    EXPECT_TRUE(set.GetTagValue(TAG_USER_ID, &int_val));
+    EXPECT_EQ(7U, int_val);
+
+    keymaster_blob_t blob_val;
+    EXPECT_TRUE(set.GetTagValue(TAG_APPLICATION_ID, &blob_val));
+    EXPECT_EQ(6U, blob_val.data_length);
+    EXPECT_EQ(0, memcmp(blob_val.data, "my_app", 6));
+}
+
+TEST(Lookup, Repeated) {
+    AuthorizationSet set(AuthorizationSetBuilder()
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                             .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                             .Authorization(TAG_USER_ID, 7)
+                             .Authorization(TAG_USER_SECURE_ID, 47727)
+                             .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
+                             .Authorization(TAG_APPLICATION_ID, "my_app", 6)
+                             .Authorization(TAG_KEY_SIZE, 256)
+                             .Authorization(TAG_AUTH_TIMEOUT, 300));
+    EXPECT_EQ(9U, set.size());
+
+    int pos = set.find(TAG_PURPOSE);
+    ASSERT_FALSE(pos == -1);
+    EXPECT_EQ(KM_TAG_PURPOSE, set[pos].tag);
+    EXPECT_EQ(KM_PURPOSE_SIGN, set[pos].enumerated);
+
+    pos = set.find(TAG_PURPOSE, pos);
+    EXPECT_EQ(KM_TAG_PURPOSE, set[pos].tag);
+    EXPECT_EQ(KM_PURPOSE_VERIFY, set[pos].enumerated);
+
+    EXPECT_EQ(-1, set.find(TAG_PURPOSE, pos));
+
+    pos = set.find(TAG_USER_SECURE_ID, pos);
+    EXPECT_EQ(KM_TAG_USER_SECURE_ID, set[pos].tag);
+    EXPECT_EQ(47727U, set[pos].long_integer);
+}
+
+TEST(Lookup, Indexed) {
+    AuthorizationSet set(AuthorizationSetBuilder()
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                             .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                             .Authorization(TAG_USER_ID, 7)
+                             .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
+                             .Authorization(TAG_APPLICATION_ID, "my_app", 6)
+                             .Authorization(TAG_KEY_SIZE, 256)
+                             .Authorization(TAG_AUTH_TIMEOUT, 300));
+    EXPECT_EQ(8U, set.size());
+
+    EXPECT_EQ(KM_TAG_PURPOSE, set[0].tag);
+    EXPECT_EQ(KM_PURPOSE_SIGN, set[0].enumerated);
+
+    // Lookup beyond end doesn't work, just returns zeros, but doens't blow up either (verify by
+    // running under valgrind).
+    EXPECT_EQ(KM_TAG_INVALID, set[10].tag);
+}
+
+TEST(Serialization, RoundTrip) {
+    AuthorizationSet set(AuthorizationSetBuilder()
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                             .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                             .Authorization(TAG_USER_ID, 7)
+                             .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
+                             .Authorization(TAG_APPLICATION_ID, "my_app", 6)
+                             .Authorization(TAG_KEY_SIZE, 256)
+                             .Authorization(TAG_USER_SECURE_ID, 47727)
+                             .Authorization(TAG_AUTH_TIMEOUT, 300)
+                             .Authorization(TAG_ALL_USERS)
+                             .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3)
+                             .Authorization(TAG_ACTIVE_DATETIME, 10));
+
+    size_t size = set.SerializedSize();
+    EXPECT_TRUE(size > 0);
+
+    UniquePtr<uint8_t[]> buf(new uint8_t[size]);
+    EXPECT_EQ(buf.get() + size, set.Serialize(buf.get(), buf.get() + size));
+    AuthorizationSet deserialized(buf.get(), size);
+
+    EXPECT_EQ(AuthorizationSet::OK, deserialized.is_valid());
+    EXPECT_EQ(set, deserialized);
+
+    int pos = deserialized.find(TAG_APPLICATION_ID);
+    ASSERT_NE(-1, pos);
+    EXPECT_EQ(KM_TAG_APPLICATION_ID, deserialized[pos].tag);
+    EXPECT_EQ(6U, deserialized[pos].blob.data_length);
+    EXPECT_EQ(0, memcmp(deserialized[pos].blob.data, "my_app", 6));
+}
+
+TEST(Deserialization, Deserialize) {
+    AuthorizationSet set(AuthorizationSetBuilder()
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                             .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                             .Authorization(TAG_USER_ID, 7)
+                             .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
+                             .Authorization(TAG_APPLICATION_ID, "my_app", 6)
+                             .Authorization(TAG_KEY_SIZE, 256)
+                             .Authorization(TAG_AUTH_TIMEOUT, 300));
+
+    size_t size = set.SerializedSize();
+    EXPECT_TRUE(size > 0);
+
+    UniquePtr<uint8_t[]> buf(new uint8_t[size]);
+    EXPECT_EQ(buf.get() + size, set.Serialize(buf.get(), buf.get() + size));
+    AuthorizationSet deserialized;
+    const uint8_t* p = buf.get();
+    EXPECT_TRUE(deserialized.Deserialize(&p, p + size));
+    EXPECT_EQ(p, buf.get() + size);
+
+    EXPECT_EQ(AuthorizationSet::OK, deserialized.is_valid());
+
+    EXPECT_EQ(set.size(), deserialized.size());
+    for (size_t i = 0; i < set.size(); ++i) {
+        EXPECT_EQ(set[i].tag, deserialized[i].tag);
+    }
+
+    int pos = deserialized.find(TAG_APPLICATION_ID);
+    ASSERT_NE(-1, pos);
+    EXPECT_EQ(KM_TAG_APPLICATION_ID, deserialized[pos].tag);
+    EXPECT_EQ(6U, deserialized[pos].blob.data_length);
+    EXPECT_EQ(0, memcmp(deserialized[pos].blob.data, "my_app", 6));
+}
+
+TEST(Deserialization, TooShortBuffer) {
+    uint8_t buf[] = {0, 0, 0};
+    AuthorizationSet deserialized(buf, array_length(buf));
+    EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized.is_valid());
+
+    const uint8_t* p = buf;
+    EXPECT_FALSE(deserialized.Deserialize(&p, p + array_length(buf)));
+    EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized.is_valid());
+}
+
+TEST(Deserialization, InvalidLengthField) {
+    AuthorizationSet set(AuthorizationSetBuilder()
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                             .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                             .Authorization(TAG_USER_ID, 7)
+                             .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
+                             .Authorization(TAG_APPLICATION_ID, "my_app", 6)
+                             .Authorization(TAG_KEY_SIZE, 256)
+                             .Authorization(TAG_AUTH_TIMEOUT, 300));
+
+    size_t size = set.SerializedSize();
+    EXPECT_TRUE(size > 0);
+
+    UniquePtr<uint8_t[]> buf(new uint8_t[size]);
+    EXPECT_EQ(buf.get() + size, set.Serialize(buf.get(), buf.get() + size));
+    *reinterpret_cast<uint32_t*>(buf.get()) = 9;
+
+    AuthorizationSet deserialized(buf.get(), size);
+    EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized.is_valid());
+
+    const uint8_t* p = buf.get();
+    EXPECT_FALSE(deserialized.Deserialize(&p, p + size));
+    EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized.is_valid());
+}
+
+static uint32_t read_uint32(const uint8_t* buf) {
+    uint32_t val;
+    memcpy(&val, buf, sizeof(val));
+    return val;
+}
+
+static void add_to_uint32(uint8_t* buf, int delta) {
+    uint32_t val;
+    memcpy(&val, buf, sizeof(val));
+    val += delta;
+    memcpy(buf, &val, sizeof(val));
+}
+
+TEST(Deserialization, MalformedIndirectData) {
+    AuthorizationSet set(AuthorizationSetBuilder()
+                             .Authorization(TAG_APPLICATION_ID, "my_app", 6)
+                             .Authorization(TAG_APPLICATION_DATA, "foo", 3));
+    size_t size = set.SerializedSize();
+
+    UniquePtr<uint8_t[]> buf(new uint8_t[size]);
+    EXPECT_EQ(buf.get() + size, set.Serialize(buf.get(), buf.get() + size));
+
+    // This sucks.  This test, as written, requires intimate knowledge of the serialized layout of
+    // this particular set, which means it's brittle.  But it's important to test that we handle
+    // broken serialized data and I can't think of a better way to write this.
+    //
+    // The contents of buf are:
+    //
+    // Bytes:   Content:
+    // 0-3      Length of string data, which is 9.
+    // 4-9      "my_app"
+    // 10-12    "foo"
+    // 13-16    Number of elements, which is 2.
+    // 17-20    Length of elements, which is 24.
+    // 21-24    First tag, TAG_APPLICATION_ID
+    // 25-28    Length of string "my_app", 6
+    // 29-32    Offset of string "my_app", 0
+    // 33-36    Second tag, TAG_APPLICATION_DATA
+    // 37-40    Length of string "foo", 3
+    // 41-44    Offset of string "foo", 6
+
+    // Check that stuff is where we think.
+    EXPECT_EQ('m', buf[4]);
+    EXPECT_EQ('f', buf[10]);
+    // Length of "my_app"
+    EXPECT_EQ(6U, read_uint32(buf.get() + 25));
+    // Offset of "my_app"
+    EXPECT_EQ(0U, read_uint32(buf.get() + 29));
+    // Length of "foo"
+    EXPECT_EQ(3U, read_uint32(buf.get() + 37));
+    // Offset of "foo"
+    EXPECT_EQ(6U, read_uint32(buf.get() + 41));
+
+    // Check that deserialization works.
+    AuthorizationSet deserialized1(buf.get(), size);
+    EXPECT_EQ(AuthorizationSet::OK, deserialized1.is_valid());
+
+    const uint8_t* p = buf.get();
+    EXPECT_TRUE(deserialized1.Deserialize(&p, p + size));
+    EXPECT_EQ(AuthorizationSet::OK, deserialized1.is_valid());
+
+    //
+    // Now mess them up in various ways:
+    //
+
+    // Move "foo" offset so offset + length goes off the end
+    add_to_uint32(buf.get() + 41, 1);
+    AuthorizationSet deserialized2(buf.get(), size);
+    EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized2.is_valid());
+    add_to_uint32(buf.get() + 41, -1);
+
+    // Shorten the "my_app" length to make a gap between the blobs.
+    add_to_uint32(buf.get() + 25, -1);
+    AuthorizationSet deserialized3(buf.get(), size);
+    EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized3.is_valid());
+    add_to_uint32(buf.get() + 25, 1);
+
+    // Extend the "my_app" length to make them overlap, and decrease the "foo" length to keep the
+    // total length the same.  We don't detect this but should.
+    // TODO(swillden): Detect overlaps and holes that leave total size correct.
+    add_to_uint32(buf.get() + 25, 1);
+    add_to_uint32(buf.get() + 37, -1);
+    AuthorizationSet deserialized4(buf.get(), size);
+    EXPECT_EQ(AuthorizationSet::OK, deserialized4.is_valid());
+}
+
+TEST(Growable, SuccessfulRoundTrip) {
+    AuthorizationSet growable;
+    EXPECT_TRUE(growable.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)));
+    EXPECT_EQ(1U, growable.size());
+
+    EXPECT_TRUE(growable.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)));
+    EXPECT_EQ(2U, growable.size());
+
+    EXPECT_TRUE(growable.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)));
+    EXPECT_EQ(3U, growable.size());
+
+    EXPECT_TRUE(growable.push_back(Authorization(TAG_APPLICATION_ID, "data", 4)));
+    EXPECT_EQ(4U, growable.size());
+
+    EXPECT_TRUE(growable.push_back(Authorization(TAG_APPLICATION_DATA, "some more data", 14)));
+    EXPECT_EQ(5U, growable.size());
+
+    size_t serialize_size = growable.SerializedSize();
+    UniquePtr<uint8_t[]> serialized(new uint8_t[serialize_size]);
+    EXPECT_EQ(serialized.get() + serialize_size,
+              growable.Serialize(serialized.get(), serialized.get() + serialize_size));
+
+    AuthorizationSet deserialized(serialized.get(), serialize_size);
+    EXPECT_EQ(growable, deserialized);
+}
+
+TEST(Growable, InsufficientElemBuf) {
+    AuthorizationSet growable;
+    EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
+
+    // First insertion fits.
+    EXPECT_TRUE(growable.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)));
+    EXPECT_EQ(1U, growable.size());
+    EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
+
+    // Second does too.
+    EXPECT_TRUE(growable.push_back(Authorization(TAG_RSA_PUBLIC_EXPONENT, 3)));
+    EXPECT_EQ(2U, growable.size());
+}
+
+TEST(Growable, InsufficientIndirectBuf) {
+    AuthorizationSet growable;
+    EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
+
+    EXPECT_TRUE(growable.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)));
+    EXPECT_EQ(1U, growable.size());
+    EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
+
+    EXPECT_TRUE(growable.push_back(Authorization(TAG_APPLICATION_ID, "1234567890", 10)));
+    EXPECT_EQ(2U, growable.size());
+    EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
+
+    EXPECT_TRUE(growable.push_back(Authorization(TAG_APPLICATION_DATA, "1", 1)));
+    EXPECT_EQ(3U, growable.size());
+    EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
+
+    // Can still add another entry without indirect data.  Now it's full.
+    EXPECT_TRUE(growable.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)));
+    EXPECT_EQ(4U, growable.size());
+    EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
+}
+
+TEST(Growable, PushBackSets) {
+    AuthorizationSetBuilder builder;
+    builder.Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+        .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+        .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+        .Authorization(TAG_USER_ID, 7)
+        .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
+        .Authorization(TAG_APPLICATION_ID, "my_app", 6)
+        .Authorization(TAG_KEY_SIZE, 256)
+        .Authorization(TAG_AUTH_TIMEOUT, 300);
+
+    AuthorizationSet set1(builder.build());
+    AuthorizationSet set2(builder.build());
+
+    AuthorizationSet combined;
+    EXPECT_TRUE(combined.push_back(set1));
+    EXPECT_TRUE(combined.push_back(set2));
+    EXPECT_EQ(set1.size() + set2.size(), combined.size());
+    EXPECT_EQ(12U, combined.indirect_size());
+}
+
+TEST(GetValue, GetInt) {
+    AuthorizationSet set(AuthorizationSetBuilder()
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                             .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                             .Authorization(TAG_USER_ID, 7)
+                             .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
+                             .Authorization(TAG_APPLICATION_ID, "my_app", 6)
+                             .Authorization(TAG_AUTH_TIMEOUT, 300));
+
+    uint32_t val;
+    EXPECT_TRUE(set.GetTagValue(TAG_USER_ID, &val));
+    EXPECT_EQ(7U, val);
+
+    // Find one that isn't there
+    EXPECT_FALSE(set.GetTagValue(TAG_KEY_SIZE, &val));
+}
+
+TEST(GetValue, GetLong) {
+    AuthorizationSet set1(AuthorizationSetBuilder()
+                              .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+                              .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                              .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                              .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3));
+
+    AuthorizationSet set2(AuthorizationSetBuilder()
+                              .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+                              .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                              .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA));
+
+    uint64_t val;
+    EXPECT_TRUE(set1.GetTagValue(TAG_RSA_PUBLIC_EXPONENT, &val));
+    EXPECT_EQ(3U, val);
+
+    // Find one that isn't there
+    EXPECT_FALSE(set2.GetTagValue(TAG_RSA_PUBLIC_EXPONENT, &val));
+}
+
+TEST(GetValue, GetLongRep) {
+    AuthorizationSet set1(AuthorizationSetBuilder()
+                              .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+                              .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                              .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                              .Authorization(TAG_USER_SECURE_ID, 8338)
+                              .Authorization(TAG_USER_SECURE_ID, 4334)
+                              .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3));
+
+    AuthorizationSet set2(AuthorizationSetBuilder()
+                              .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+                              .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                              .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA));
+
+    uint64_t val;
+    EXPECT_TRUE(set1.GetTagValue(TAG_USER_SECURE_ID, 0, &val));
+    EXPECT_EQ(8338U, val);
+    EXPECT_TRUE(set1.GetTagValue(TAG_USER_SECURE_ID, 1, &val));
+    EXPECT_EQ(4334U, val);
+
+    // Find one that isn't there
+    EXPECT_FALSE(set2.GetTagValue(TAG_USER_SECURE_ID, &val));
+}
+
+TEST(GetValue, GetEnum) {
+    AuthorizationSet set(AuthorizationSetBuilder()
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                             .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                             .Authorization(TAG_USER_ID, 7)
+                             .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
+                             .Authorization(TAG_APPLICATION_ID, "my_app", 6)
+                             .Authorization(TAG_AUTH_TIMEOUT, 300));
+
+    keymaster_algorithm_t val;
+    EXPECT_TRUE(set.GetTagValue(TAG_ALGORITHM, &val));
+    EXPECT_EQ(KM_ALGORITHM_RSA, val);
+
+    // Find one that isn't there
+    keymaster_padding_t val2;
+    EXPECT_FALSE(set.GetTagValue(TAG_PADDING, &val2));
+}
+
+TEST(GetValue, GetEnumRep) {
+    AuthorizationSet set(AuthorizationSetBuilder()
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                             .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                             .Authorization(TAG_USER_ID, 7)
+                             .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
+                             .Authorization(TAG_APPLICATION_ID, "my_app", 6)
+                             .Authorization(TAG_AUTH_TIMEOUT, 300));
+
+    keymaster_purpose_t val;
+    EXPECT_TRUE(set.GetTagValue(TAG_PURPOSE, 0, &val));
+    EXPECT_EQ(KM_PURPOSE_SIGN, val);
+    EXPECT_TRUE(set.GetTagValue(TAG_PURPOSE, 1, &val));
+    EXPECT_EQ(KM_PURPOSE_VERIFY, val);
+
+    // Find one that isn't there
+    EXPECT_FALSE(set.GetTagValue(TAG_PURPOSE, 2, &val));
+}
+
+TEST(GetValue, GetDate) {
+    AuthorizationSet set(AuthorizationSetBuilder()
+                             .Authorization(TAG_ACTIVE_DATETIME, 10)
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                             .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                             .Authorization(TAG_USER_ID, 7)
+                             .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
+                             .Authorization(TAG_APPLICATION_ID, "my_app", 6)
+                             .Authorization(TAG_AUTH_TIMEOUT, 300));
+
+    uint64_t val;
+    EXPECT_TRUE(set.GetTagValue(TAG_ACTIVE_DATETIME, &val));
+    EXPECT_EQ(10U, val);
+
+    // Find one that isn't there
+    EXPECT_FALSE(set.GetTagValue(TAG_USAGE_EXPIRE_DATETIME, &val));
+}
+
+TEST(GetValue, GetBlob) {
+    AuthorizationSet set(AuthorizationSetBuilder()
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                             .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                             .Authorization(TAG_USER_ID, 7)
+                             .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
+                             .Authorization(TAG_APPLICATION_ID, "my_app", 6)
+                             .Authorization(TAG_AUTH_TIMEOUT, 300));
+
+    keymaster_blob_t val;
+    EXPECT_TRUE(set.GetTagValue(TAG_APPLICATION_ID, &val));
+    EXPECT_EQ(6U, val.data_length);
+    EXPECT_EQ(0, memcmp(val.data, "my_app", 6));
+
+    // Find one that isn't there
+    EXPECT_FALSE(set.GetTagValue(TAG_APPLICATION_DATA, &val));
+}
+
+TEST(Deduplication, NoDuplicates) {
+    AuthorizationSet set(AuthorizationSetBuilder()
+                             .Authorization(TAG_ACTIVE_DATETIME, 10)
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                             .Authorization(TAG_USER_ID, 7)
+                             .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
+    AuthorizationSet copy(set);
+
+    EXPECT_EQ(copy, set);
+    set.Deduplicate();
+    EXPECT_EQ(copy.size(), set.size());
+
+    // Sets no longer compare equal, because of ordering (ugh, maybe it should be
+    // AuthorizationList, not AuthorizationSet).
+    EXPECT_NE(copy, set);
+}
+
+TEST(Deduplication, NoDuplicatesHasInvalid) {
+    AuthorizationSet set(AuthorizationSetBuilder()
+                             .Authorization(TAG_ACTIVE_DATETIME, 10)
+                             .Authorization(TAG_INVALID)
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                             .Authorization(TAG_USER_ID, 7)
+                             .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
+    AuthorizationSet copy(set);
+
+    EXPECT_EQ(copy, set);
+    set.Deduplicate();
+
+    // Deduplicate should have removed the invalid.
+    EXPECT_EQ(copy.size() - 1, set.size());
+    EXPECT_NE(copy, set);
+}
+
+TEST(Deduplication, DuplicateEnum) {
+    AuthorizationSet set(AuthorizationSetBuilder()
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                             .Authorization(TAG_ACTIVE_DATETIME, 10)
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                             .Authorization(TAG_USER_ID, 7)
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                             .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
+    AuthorizationSet copy(set);
+
+    EXPECT_EQ(copy, set);
+    set.Deduplicate();
+    EXPECT_EQ(copy.size() - 2, set.size());
+    EXPECT_NE(copy, set);
+}
+
+TEST(Deduplication, DuplicateBlob) {
+    AuthorizationSet set(AuthorizationSetBuilder()
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                             .Authorization(TAG_ACTIVE_DATETIME, 10)
+                             .Authorization(TAG_APPLICATION_DATA, "data", 4)
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                             .Authorization(TAG_USER_ID, 7)
+                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                             .Authorization(TAG_APPLICATION_DATA, "data", 4)
+                             .Authorization(TAG_APPLICATION_DATA, "foo", 3)
+                             .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
+    AuthorizationSet copy(set);
+
+    EXPECT_EQ(copy, set);
+    set.Deduplicate();
+    EXPECT_EQ(copy.size() - 3, set.size());
+    EXPECT_NE(copy, set);
+
+    // The real test here is that valgrind reports no leak.
+}
+
+}  // namespace test
+}  // namespace keymaster
diff --git a/keymaster/ec_key.cpp b/keymaster/ec_key.cpp
new file mode 100644
index 0000000..64ffc7a
--- /dev/null
+++ b/keymaster/ec_key.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "ec_key.h"
+
+#if defined(OPENSSL_IS_BORINGSSL)
+typedef size_t openssl_size_t;
+#else
+typedef int openssl_size_t;
+#endif
+
+namespace keymaster {
+
+bool EcKey::EvpToInternal(const EVP_PKEY* pkey) {
+    ec_key_.reset(EVP_PKEY_get1_EC_KEY(const_cast<EVP_PKEY*>(pkey)));
+    return ec_key_.get() != NULL;
+}
+
+bool EcKey::InternalToEvp(EVP_PKEY* pkey) const {
+    return EVP_PKEY_set1_EC_KEY(pkey, ec_key_.get()) == 1;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/ec_key.h b/keymaster/ec_key.h
new file mode 100644
index 0000000..8230d23
--- /dev/null
+++ b/keymaster/ec_key.h
@@ -0,0 +1,51 @@
+/*
+ * 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_EC_KEY_H_
+#define SYSTEM_KEYMASTER_EC_KEY_H_
+
+#include <openssl/ec.h>
+
+#include "asymmetric_key.h"
+#include "openssl_utils.h"
+
+namespace keymaster {
+
+class EcdsaOperationFactory;
+
+class EcKey : public AsymmetricKey {
+  public:
+    EcKey(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+          keymaster_error_t* error)
+        : AsymmetricKey(hw_enforced, sw_enforced, error) {}
+
+    bool InternalToEvp(EVP_PKEY* pkey) const override;
+    bool EvpToInternal(const EVP_PKEY* pkey) override;
+
+    EC_KEY* key() const { return ec_key_.get(); }
+
+  protected:
+    EcKey(EC_KEY* ec_key, const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+          keymaster_error_t* error)
+        : AsymmetricKey(hw_enforced, sw_enforced, error), ec_key_(ec_key) {}
+
+  private:
+    UniquePtr<EC_KEY, EC_KEY_Delete> ec_key_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_EC_KEY_H_
diff --git a/keymaster/ec_key_factory.cpp b/keymaster/ec_key_factory.cpp
new file mode 100644
index 0000000..14c8327
--- /dev/null
+++ b/keymaster/ec_key_factory.cpp
@@ -0,0 +1,182 @@
+/*
+ * 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/ec_key_factory.h>
+
+#include <openssl/evp.h>
+
+#include <keymaster/keymaster_context.h>
+
+#include "ec_key.h"
+#include "ecdsa_operation.h"
+#include "openssl_err.h"
+
+namespace keymaster {
+
+static EcdsaSignOperationFactory sign_factory;
+static EcdsaVerifyOperationFactory verify_factory;
+
+OperationFactory* EcKeyFactory::GetOperationFactory(keymaster_purpose_t purpose) const {
+    switch (purpose) {
+    case KM_PURPOSE_SIGN:
+        return &sign_factory;
+    case KM_PURPOSE_VERIFY:
+        return &verify_factory;
+    default:
+        return nullptr;
+    }
+}
+
+keymaster_error_t EcKeyFactory::GenerateKey(const AuthorizationSet& key_description,
+                                            KeymasterKeyBlob* key_blob,
+                                            AuthorizationSet* hw_enforced,
+                                            AuthorizationSet* sw_enforced) const {
+    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");
+        return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+    }
+
+    UniquePtr<EC_KEY, EC_KEY_Delete> ec_key(EC_KEY_new());
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
+    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) {
+        LOG_E("Unable to get EC group for key of size %d", key_size);
+        return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+    }
+
+#if !defined(OPENSSL_IS_BORINGSSL)
+    EC_GROUP_set_point_conversion_form(group.get(), POINT_CONVERSION_UNCOMPRESSED);
+    EC_GROUP_set_asn1_flag(group.get(), OPENSSL_EC_NAMED_CURVE);
+#endif
+
+    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) {
+        return TranslateLastOpenSslError();
+    }
+
+    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);
+}
+
+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) const {
+    if (!output_key_blob || !hw_enforced || !sw_enforced)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    AuthorizationSet authorizations;
+    uint32_t key_size;
+    keymaster_error_t error = UpdateImportKeyDescription(
+        key_description, input_key_material_format, input_key_material, &authorizations, &key_size);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    return context_->CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material,
+                                   output_key_blob, hw_enforced, sw_enforced);
+}
+
+keymaster_error_t EcKeyFactory::UpdateImportKeyDescription(const AuthorizationSet& key_description,
+                                                           keymaster_key_format_t key_format,
+                                                           const KeymasterKeyBlob& key_material,
+                                                           AuthorizationSet* updated_description,
+                                                           uint32_t* key_size_bits) const {
+    if (!updated_description || !key_size_bits)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey;
+    keymaster_error_t error =
+        KeyMaterialToEvpKey(key_format, key_material, keymaster_key_type(), &pkey);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    UniquePtr<EC_KEY, EC_KEY_Delete> ec_key(EVP_PKEY_get1_EC_KEY(pkey.get()));
+    if (!ec_key.get())
+        return TranslateLastOpenSslError();
+
+    updated_description->Reinitialize(key_description);
+
+    size_t extracted_key_size_bits;
+    error = ec_get_group_size(EC_KEY_get0_group(ec_key.get()), &extracted_key_size_bits);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    *key_size_bits = extracted_key_size_bits;
+    if (!updated_description->GetTagValue(TAG_KEY_SIZE, key_size_bits))
+        updated_description->push_back(TAG_KEY_SIZE, extracted_key_size_bits);
+    if (*key_size_bits != extracted_key_size_bits)
+        return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+
+    keymaster_algorithm_t algorithm = KM_ALGORITHM_EC;
+    if (!updated_description->GetTagValue(TAG_ALGORITHM, &algorithm))
+        updated_description->push_back(TAG_ALGORITHM, KM_ALGORITHM_EC);
+    if (algorithm != KM_ALGORITHM_EC)
+        return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+
+    return KM_ERROR_OK;
+}
+
+/* static */
+EC_GROUP* EcKeyFactory::choose_group(size_t key_size_bits) {
+    switch (key_size_bits) {
+    case 224:
+        return EC_GROUP_new_by_curve_name(NID_secp224r1);
+        break;
+    case 256:
+        return EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+        break;
+    case 384:
+        return EC_GROUP_new_by_curve_name(NID_secp384r1);
+        break;
+    case 521:
+        return EC_GROUP_new_by_curve_name(NID_secp521r1);
+        break;
+    default:
+        return NULL;
+        break;
+    }
+}
+
+keymaster_error_t EcKeyFactory::CreateEmptyKey(const AuthorizationSet& hw_enforced,
+                                               const AuthorizationSet& sw_enforced,
+                                               UniquePtr<AsymmetricKey>* key) const {
+    keymaster_error_t error;
+    key->reset(new (std::nothrow) EcKey(hw_enforced, sw_enforced, &error));
+    if (!key->get())
+        error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    return error;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/ec_keymaster0_key.cpp b/keymaster/ec_keymaster0_key.cpp
new file mode 100644
index 0000000..705ee73
--- /dev/null
+++ b/keymaster/ec_keymaster0_key.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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 "ec_keymaster0_key.h"
+
+#include <memory>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/logger.h>
+#include <keymaster/soft_keymaster_context.h>
+
+#include "keymaster0_engine.h"
+#include "openssl_utils.h"
+
+using std::unique_ptr;
+
+namespace keymaster {
+
+EcdsaKeymaster0KeyFactory::EcdsaKeymaster0KeyFactory(const SoftKeymasterContext* context,
+                                                     const Keymaster0Engine* engine)
+    : EcKeyFactory(context), engine_(engine) {}
+
+keymaster_error_t EcdsaKeymaster0KeyFactory::GenerateKey(const AuthorizationSet& key_description,
+                                                         KeymasterKeyBlob* key_blob,
+                                                         AuthorizationSet* hw_enforced,
+                                                         AuthorizationSet* sw_enforced) const {
+    if (!key_blob || !hw_enforced || !sw_enforced)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    if (!engine_ || !engine_->supports_ec())
+        return super::GenerateKey(key_description, key_blob, hw_enforced, sw_enforced);
+
+    uint32_t key_size;
+    if (!key_description.GetTagValue(TAG_KEY_SIZE, &key_size)) {
+        LOG_E("%s", "No key size specified for EC key generation");
+        return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+    }
+
+    KeymasterKeyBlob key_material;
+    if (!engine_->GenerateEcKey(key_size, &key_material))
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    // These tags are hardware-enforced.  Putting them in the hw_enforced set here will ensure that
+    // context_->CreateKeyBlob doesn't put them in sw_enforced.
+    hw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_EC);
+    hw_enforced->push_back(TAG_KEY_SIZE, key_size);
+    hw_enforced->push_back(TAG_ORIGIN, KM_ORIGIN_UNKNOWN);
+
+    return context_->CreateKeyBlob(key_description, KM_ORIGIN_UNKNOWN, key_material, key_blob,
+                                   hw_enforced, sw_enforced);
+}
+
+keymaster_error_t EcdsaKeymaster0KeyFactory::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) const {
+    if (!output_key_blob || !hw_enforced || !sw_enforced)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    if (!engine_ || !engine_->supports_ec())
+        return super::ImportKey(key_description, input_key_material_format, input_key_material,
+                                output_key_blob, hw_enforced, sw_enforced);
+
+    AuthorizationSet authorizations;
+    uint32_t key_size;
+    keymaster_error_t error = UpdateImportKeyDescription(
+        key_description, input_key_material_format, input_key_material, &authorizations, &key_size);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    KeymasterKeyBlob imported_hw_key;
+    if (!engine_->ImportKey(input_key_material_format, input_key_material, &imported_hw_key))
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    // These tags are hardware-enforced.  Putting them in the hw_enforced set here will ensure that
+    // context_->CreateKeyBlob doesn't put them in sw_enforced.
+    hw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_EC);
+    hw_enforced->push_back(TAG_KEY_SIZE, key_size);
+    hw_enforced->push_back(TAG_ORIGIN, KM_ORIGIN_UNKNOWN);
+
+    return context_->CreateKeyBlob(authorizations, KM_ORIGIN_UNKNOWN, imported_hw_key,
+                                   output_key_blob, hw_enforced, sw_enforced);
+}
+
+keymaster_error_t EcdsaKeymaster0KeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+                                                     const AuthorizationSet& additional_params,
+                                                     const AuthorizationSet& hw_enforced,
+                                                     const AuthorizationSet& sw_enforced,
+                                                     UniquePtr<Key>* key) const {
+    if (!key)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    if (sw_enforced.GetTagCount(TAG_ALGORITHM) == 1)
+        return super::LoadKey(key_material, additional_params, hw_enforced, sw_enforced, key);
+
+    unique_ptr<EC_KEY, EC_KEY_Delete> ec_key(engine_->BlobToEcKey(key_material));
+    if (!ec_key)
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    keymaster_error_t error;
+    key->reset(new (std::nothrow)
+                   EcKeymaster0Key(ec_key.release(), hw_enforced, sw_enforced, &error));
+    if (error != KM_ERROR_OK)
+        return error;
+
+    return KM_ERROR_OK;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/ec_keymaster0_key.h b/keymaster/ec_keymaster0_key.h
new file mode 100644
index 0000000..0d0af3d
--- /dev/null
+++ b/keymaster/ec_keymaster0_key.h
@@ -0,0 +1,70 @@
+/*
+ * 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_EC_KEYMASTER0_KEY_H_
+#define SYSTEM_KEYMASTER_EC_KEYMASTER0_KEY_H_
+
+#include <openssl/ec_key.h>
+
+#include <keymaster/ec_key_factory.h>
+
+#include "ec_key.h"
+
+namespace keymaster {
+
+class Keymaster0Engine;
+class SoftKeymasterContext;
+
+/**
+ * An EcdsaKeyFactory which can delegate key generation, importing and loading operations to a
+ * keymaster0-backed OpenSSL engine.
+ */
+class EcdsaKeymaster0KeyFactory : public EcKeyFactory {
+    typedef EcKeyFactory super;
+
+  public:
+    EcdsaKeymaster0KeyFactory(const SoftKeymasterContext* context, const Keymaster0Engine* engine);
+
+    keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+                                  KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
+                                  AuthorizationSet* sw_enforced) const 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) const override;
+
+    keymaster_error_t LoadKey(const KeymasterKeyBlob& key_material,
+                              const AuthorizationSet& additional_params,
+                              const AuthorizationSet& hw_enforced,
+                              const AuthorizationSet& sw_enforced,
+                              UniquePtr<Key>* key) const override;
+
+  private:
+    const Keymaster0Engine* engine_;
+};
+
+class EcKeymaster0Key : public EcKey {
+  public:
+    EcKeymaster0Key(EC_KEY* ec_key, const AuthorizationSet& hw_enforced,
+                    const AuthorizationSet& sw_enforced, keymaster_error_t* error)
+        : EcKey(ec_key, hw_enforced, sw_enforced, error) {}
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_EC_KEYMASTER0_KEY_H_
diff --git a/keymaster/ec_keymaster1_key.cpp b/keymaster/ec_keymaster1_key.cpp
new file mode 100644
index 0000000..5cc2539
--- /dev/null
+++ b/keymaster/ec_keymaster1_key.cpp
@@ -0,0 +1,120 @@
+/*
+ * 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 "ec_keymaster1_key.h"
+
+#include <memory>
+
+#include <keymaster/logger.h>
+
+#include "ecdsa_keymaster1_operation.h"
+#include "ecdsa_operation.h"
+
+using std::unique_ptr;
+
+namespace keymaster {
+
+EcdsaKeymaster1KeyFactory::EcdsaKeymaster1KeyFactory(const SoftKeymasterContext* context,
+                                                     const Keymaster1Engine* engine)
+    : EcKeyFactory(context), engine_(engine),
+      sign_factory_(new EcdsaKeymaster1OperationFactory(KM_PURPOSE_SIGN, engine)),
+      // For pubkey ops we can use the normal operation factories.
+      verify_factory_(new EcdsaVerifyOperationFactory) {}
+
+static bool is_supported(uint32_t digest) {
+    return digest == KM_DIGEST_NONE || digest == KM_DIGEST_SHA_2_256;
+}
+
+static void UpdateToWorkAroundUnsupportedDigests(const AuthorizationSet& key_description,
+                                                 AuthorizationSet* new_description) {
+    bool have_unsupported_digests = false;
+    bool have_digest_none = false;
+    for (const keymaster_key_param_t& entry : key_description) {
+        new_description->push_back(entry);
+
+        if (entry.tag == TAG_DIGEST) {
+            if (entry.enumerated == KM_DIGEST_NONE) {
+                have_digest_none = true;
+            } else if (!is_supported(entry.enumerated)) {
+                LOG_D("Found request for unsupported digest %u", entry.enumerated);
+                have_unsupported_digests = true;
+            }
+        }
+    }
+
+    if (have_unsupported_digests && !have_digest_none) {
+        LOG_I("Adding KM_DIGEST_NONE to key authorization, to enable software digesting", 0);
+        new_description->push_back(TAG_DIGEST, KM_DIGEST_NONE);
+    }
+}
+
+keymaster_error_t EcdsaKeymaster1KeyFactory::GenerateKey(const AuthorizationSet& key_description,
+                                                         KeymasterKeyBlob* key_blob,
+                                                         AuthorizationSet* hw_enforced,
+                                                         AuthorizationSet* sw_enforced) const {
+    AuthorizationSet key_params_copy;
+    UpdateToWorkAroundUnsupportedDigests(key_description, &key_params_copy);
+    return engine_->GenerateKey(key_params_copy, key_blob, hw_enforced, sw_enforced);
+}
+
+keymaster_error_t EcdsaKeymaster1KeyFactory::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) const {
+    AuthorizationSet key_params_copy;
+    UpdateToWorkAroundUnsupportedDigests(key_description, &key_params_copy);
+    return engine_->ImportKey(key_params_copy, input_key_material_format, input_key_material,
+                              output_key_blob, hw_enforced, sw_enforced);
+}
+
+keymaster_error_t EcdsaKeymaster1KeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+                                                     const AuthorizationSet& additional_params,
+                                                     const AuthorizationSet& hw_enforced,
+                                                     const AuthorizationSet& sw_enforced,
+                                                     UniquePtr<Key>* key) const {
+    if (!key)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    keymaster_error_t error;
+    unique_ptr<EC_KEY, EC_KEY_Delete> ecdsa(
+        engine_->BuildEcKey(key_material, additional_params, &error));
+    if (!ecdsa)
+        return error;
+
+    key->reset(new (std::nothrow)
+                   EcdsaKeymaster1Key(ecdsa.release(), hw_enforced, sw_enforced, &error));
+    if (!key->get())
+        error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    if (error != KM_ERROR_OK)
+        return error;
+
+    return KM_ERROR_OK;
+}
+
+OperationFactory*
+EcdsaKeymaster1KeyFactory::GetOperationFactory(keymaster_purpose_t purpose) const {
+    switch (purpose) {
+    case KM_PURPOSE_SIGN:
+        return sign_factory_.get();
+    case KM_PURPOSE_VERIFY:
+        return verify_factory_.get();
+    default:
+        return nullptr;
+    }
+}
+
+}  // namespace keymaster
diff --git a/keymaster/ec_keymaster1_key.h b/keymaster/ec_keymaster1_key.h
new file mode 100644
index 0000000..2702b35
--- /dev/null
+++ b/keymaster/ec_keymaster1_key.h
@@ -0,0 +1,79 @@
+/*
+ * 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_EC_KEYMASTER1_KEY_H_
+#define SYSTEM_KEYMASTER_EC_KEYMASTER1_KEY_H_
+
+#include <openssl/ecdsa.h>
+
+#include <hardware/keymaster1.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/logger.h>
+#include <keymaster/ec_key_factory.h>
+#include <keymaster/soft_keymaster_context.h>
+
+#include "ec_key.h"
+#include "keymaster1_engine.h"
+
+namespace keymaster {
+
+class SoftKeymasterContext;
+
+/**
+ * EcdsaKeymaster1KeyFactory is a KeyFactory that creates and loads keys which are actually backed
+ * by a hardware keymaster1 module, but which does not support all keymaster1 digests.  During
+ * generation or import any unsupported digests in the key description are silently replaced with
+ * KM_DIGEST_NONE.
+ */
+class EcdsaKeymaster1KeyFactory : public EcKeyFactory {
+  public:
+    EcdsaKeymaster1KeyFactory(const SoftKeymasterContext* context, const Keymaster1Engine* engine);
+
+    keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+                                  KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
+                                  AuthorizationSet* sw_enforced) const 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) const override;
+
+    keymaster_error_t LoadKey(const KeymasterKeyBlob& key_material,
+                              const AuthorizationSet& additional_params,
+                              const AuthorizationSet& hw_enforced,
+                              const AuthorizationSet& sw_enforced,
+                              UniquePtr<Key>* key) const override;
+
+    OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const override;
+
+  private:
+    const Keymaster1Engine* engine_;
+
+    std::unique_ptr<OperationFactory> sign_factory_;
+    std::unique_ptr<OperationFactory> verify_factory_;
+};
+
+class EcdsaKeymaster1Key : public EcKey {
+  public:
+    EcdsaKeymaster1Key(EC_KEY* ecdsa_key, const AuthorizationSet& hw_enforced,
+                       const AuthorizationSet& sw_enforced, keymaster_error_t* error)
+        : EcKey(ecdsa_key, hw_enforced, sw_enforced, error) {}
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_ECDSA_KEYMASTER1_KEY_H_
diff --git a/keymaster/ec_privkey_pk8.der b/keymaster/ec_privkey_pk8.der
new file mode 100644
index 0000000..a4af673
--- /dev/null
+++ b/keymaster/ec_privkey_pk8.der
Binary files differ
diff --git a/keymaster/ecdsa_keymaster1_operation.cpp b/keymaster/ecdsa_keymaster1_operation.cpp
new file mode 100644
index 0000000..7e1a4f5
--- /dev/null
+++ b/keymaster/ecdsa_keymaster1_operation.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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 "ecdsa_keymaster1_operation.h"
+
+#include <memory>
+
+#include <keymaster/android_keymaster_utils.h>
+
+#include "openssl_err.h"
+#include "openssl_utils.h"
+#include "ec_keymaster1_key.h"
+
+using std::unique_ptr;
+
+namespace keymaster {
+
+keymaster_error_t EcdsaKeymaster1WrappedOperation::Begin(EVP_PKEY* ecdsa_key,
+                                                         const AuthorizationSet& input_params) {
+    Keymaster1Engine::KeyData* key_data = engine_->GetData(ecdsa_key);
+    if (!key_data)
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    // Copy the input params and substitute KM_DIGEST_NONE for whatever was specified.  Also change
+    // KM_PAD_ECDSA_PSS and KM_PAD_OAEP to KM_PAD_NONE, if necessary. These are the params we'll
+    // pass
+    // to the hardware module.  The regular Ecdsa*Operation classes will do software digesting and
+    // padding where we've told the HW not to.
+    //
+    // The reason we don't change KM_PAD_ECDSA_PKCS1_1_5_SIGN or KM_PAD_ECDSA_PKCS1_1_5_ENCRYPT to
+    // KM_PAD_NONE is because the hardware can to those padding modes, since they don't involve
+    // digesting.
+    //
+    // We also cache in the key the padding value that we expect to be passed to the engine crypto
+    // operation.  This just allows us to double-check that the correct padding value is reaching
+    // that layer.
+    AuthorizationSet begin_params(input_params);
+    int pos = begin_params.find(TAG_DIGEST);
+    if (pos == -1)
+        return KM_ERROR_UNSUPPORTED_DIGEST;
+    begin_params[pos].enumerated = KM_DIGEST_NONE;
+
+    return engine_->device()->begin(engine_->device(), purpose_, &key_data->key_material,
+                                    &begin_params, nullptr /* out_params */, &operation_handle_);
+}
+
+keymaster_error_t
+EcdsaKeymaster1WrappedOperation::PrepareFinish(EVP_PKEY* ecdsa_key,
+                                               const AuthorizationSet& input_params) {
+    Keymaster1Engine::KeyData* key_data = engine_->GetData(ecdsa_key);
+    if (!key_data) {
+        LOG_E("Could not get extended key data... not a Keymaster1Engine key?", 0);
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+    key_data->op_handle = operation_handle_;
+    key_data->finish_params.Reinitialize(input_params);
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t EcdsaKeymaster1WrappedOperation::Abort() {
+    return engine_->device()->abort(engine_->device(), operation_handle_);
+}
+
+keymaster_error_t EcdsaKeymaster1WrappedOperation::GetError(EVP_PKEY* ecdsa_key) {
+    Keymaster1Engine::KeyData* key_data = engine_->GetData(ecdsa_key);
+    if (!key_data)
+        return KM_ERROR_UNKNOWN_ERROR;
+    return key_data->error;
+}
+
+static EVP_PKEY* GetEvpKey(const EcdsaKeymaster1Key& key, keymaster_error_t* error) {
+    if (!key.key()) {
+        *error = KM_ERROR_UNKNOWN_ERROR;
+        return nullptr;
+    }
+
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
+    if (!key.InternalToEvp(pkey.get())) {
+        *error = KM_ERROR_UNKNOWN_ERROR;
+        return nullptr;
+    }
+    return pkey.release();
+}
+
+Operation* EcdsaKeymaster1OperationFactory::CreateOperation(const Key& key,
+                                                            const AuthorizationSet& begin_params,
+                                                            keymaster_error_t* error) {
+    keymaster_digest_t digest;
+    if (!GetAndValidateDigest(begin_params, key, &digest, error))
+        return nullptr;
+
+    const EcdsaKeymaster1Key& ecdsa_km1_key(static_cast<const EcdsaKeymaster1Key&>(key));
+    unique_ptr<EVP_PKEY, EVP_PKEY_Delete> ecdsa(GetEvpKey(ecdsa_km1_key, error));
+    if (!ecdsa)
+        return nullptr;
+
+    switch (purpose_) {
+    case KM_PURPOSE_SIGN:
+        return new EcdsaKeymaster1Operation<EcdsaSignOperation>(digest, ecdsa.release(), engine_);
+    default:
+        LOG_E(
+            "Bug: Pubkey operation requested.  Those should be handled by normal ECDSA operations.",
+            0);
+        *error = KM_ERROR_UNSUPPORTED_PURPOSE;
+        return nullptr;
+    }
+}
+
+static const keymaster_digest_t supported_digests[] = {
+    KM_DIGEST_NONE,      KM_DIGEST_MD5,       KM_DIGEST_SHA1,     KM_DIGEST_SHA_2_224,
+    KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512};
+
+const keymaster_digest_t*
+EcdsaKeymaster1OperationFactory::SupportedDigests(size_t* digest_count) const {
+    *digest_count = array_length(supported_digests);
+    return supported_digests;
+}
+
+const keymaster_padding_t*
+EcdsaKeymaster1OperationFactory::SupportedPaddingModes(size_t* padding_mode_count) const {
+    *padding_mode_count = 0;
+    return nullptr;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/ecdsa_keymaster1_operation.h b/keymaster/ecdsa_keymaster1_operation.h
new file mode 100644
index 0000000..6045686
--- /dev/null
+++ b/keymaster/ecdsa_keymaster1_operation.h
@@ -0,0 +1,120 @@
+/*
+ * 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_ECDSA_KEYMASTER1_OPERATION_H_
+#define SYSTEM_KEYMASTER_ECDSA_KEYMASTER1_OPERATION_H_
+
+#include <openssl/evp.h>
+
+#include <hardware/keymaster1.h>
+#include <keymaster/android_keymaster_utils.h>
+
+#include "ecdsa_operation.h"
+#include "keymaster1_engine.h"
+
+namespace keymaster {
+
+class EcdsaKeymaster1WrappedOperation {
+  public:
+    EcdsaKeymaster1WrappedOperation(keymaster_purpose_t purpose, const Keymaster1Engine* engine)
+        : purpose_(purpose), operation_handle_(0), engine_(engine) {}
+    ~EcdsaKeymaster1WrappedOperation() {
+        if (operation_handle_)
+            Abort();
+    }
+
+    keymaster_error_t Begin(EVP_PKEY* ecdsa_key, const AuthorizationSet& input_params);
+    keymaster_error_t PrepareFinish(EVP_PKEY* ecdsa_key, const AuthorizationSet& input_params);
+    void Finish() { operation_handle_ = 0; }
+    keymaster_error_t Abort();
+
+    keymaster_error_t GetError(EVP_PKEY* ecdsa_key);
+
+  protected:
+    keymaster_purpose_t purpose_;
+    keymaster_operation_handle_t operation_handle_;
+    const Keymaster1Engine* engine_;
+};
+
+template <typename BaseOperation> class EcdsaKeymaster1Operation : public BaseOperation {
+    typedef BaseOperation super;
+
+  public:
+    EcdsaKeymaster1Operation(keymaster_digest_t digest, EVP_PKEY* key,
+                             const Keymaster1Engine* engine)
+        : BaseOperation(digest, key), wrapped_operation_(super::purpose(), engine) {
+        // Shouldn't be instantiated for public key operations.
+        assert(super::purpose() != KM_PURPOSE_VERIFY);
+        assert(super::purpose() != KM_PURPOSE_ENCRYPT);
+    }
+
+    keymaster_error_t Begin(const AuthorizationSet& input_params,
+                            AuthorizationSet* output_params) override {
+        keymaster_error_t error = wrapped_operation_.Begin(super::ecdsa_key_, input_params);
+        if (error != KM_ERROR_OK)
+            return error;
+        return super::Begin(input_params, output_params);
+    }
+
+    keymaster_error_t Finish(const AuthorizationSet& input_params, const Buffer& input,
+                             const Buffer& signature, AuthorizationSet* output_params,
+                             Buffer* output) override {
+        keymaster_error_t error = wrapped_operation_.PrepareFinish(super::ecdsa_key_, input_params);
+        if (error != KM_ERROR_OK)
+            return error;
+        error = super::Finish(input_params, input, signature, output_params, output);
+        if (wrapped_operation_.GetError(super::ecdsa_key_) != KM_ERROR_OK)
+            error = wrapped_operation_.GetError(super::ecdsa_key_);
+        if (error == KM_ERROR_OK)
+            wrapped_operation_.Finish();
+        return error;
+    }
+
+    keymaster_error_t Abort() override {
+        keymaster_error_t error = wrapped_operation_.Abort();
+        if (error != KM_ERROR_OK)
+            return error;
+        return super::Abort();
+    }
+
+  private:
+    EcdsaKeymaster1WrappedOperation wrapped_operation_;
+};
+
+/**
+ * Factory that produces EcdsaKeymaster1Operations.  This is instantiated and
+ * provided by EcdsaKeymaster1KeyFactory.
+ */
+class EcdsaKeymaster1OperationFactory : public OperationFactory {
+  public:
+    EcdsaKeymaster1OperationFactory(keymaster_purpose_t purpose, const Keymaster1Engine* engine)
+        : purpose_(purpose), engine_(engine) {}
+    KeyType registry_key() const override { return KeyType(KM_ALGORITHM_EC, purpose_); }
+
+    Operation* CreateOperation(const Key& key, const AuthorizationSet& begin_params,
+                               keymaster_error_t* error) override;
+
+    const keymaster_digest_t* SupportedDigests(size_t* digest_count) const override;
+    const keymaster_padding_t* SupportedPaddingModes(size_t* padding_mode_count) const override;
+
+  private:
+    keymaster_purpose_t purpose_;
+    const Keymaster1Engine* engine_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_ECDSA_KEYMASTER1_OPERATION_H_
diff --git a/keymaster/ecdsa_operation.cpp b/keymaster/ecdsa_operation.cpp
new file mode 100644
index 0000000..405dcb5
--- /dev/null
+++ b/keymaster/ecdsa_operation.cpp
@@ -0,0 +1,230 @@
+/*
+ * 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 "ecdsa_operation.h"
+
+#include <openssl/ecdsa.h>
+
+#include "ec_key.h"
+#include "openssl_err.h"
+#include "openssl_utils.h"
+
+namespace keymaster {
+
+static const keymaster_digest_t supported_digests[] = {KM_DIGEST_NONE,      KM_DIGEST_SHA1,
+                                                       KM_DIGEST_SHA_2_224, KM_DIGEST_SHA_2_256,
+                                                       KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512};
+
+Operation* EcdsaOperationFactory::CreateOperation(const Key& key,
+                                                  const AuthorizationSet& begin_params,
+                                                  keymaster_error_t* error) {
+    const EcKey* ecdsa_key = static_cast<const EcKey*>(&key);
+    if (!ecdsa_key) {
+        *error = KM_ERROR_UNKNOWN_ERROR;
+        return nullptr;
+    }
+
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
+    if (!ecdsa_key->InternalToEvp(pkey.get())) {
+        *error = KM_ERROR_UNKNOWN_ERROR;
+        return nullptr;
+    }
+
+    keymaster_digest_t digest;
+    if (!GetAndValidateDigest(begin_params, key, &digest, error))
+        return nullptr;
+
+    *error = KM_ERROR_OK;
+    Operation* op = InstantiateOperation(digest, pkey.release());
+    if (!op)
+        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    return op;
+}
+
+const keymaster_digest_t* EcdsaOperationFactory::SupportedDigests(size_t* digest_count) const {
+    *digest_count = array_length(supported_digests);
+    return supported_digests;
+}
+
+EcdsaOperation::~EcdsaOperation() {
+    if (ecdsa_key_ != NULL)
+        EVP_PKEY_free(ecdsa_key_);
+    EVP_MD_CTX_cleanup(&digest_ctx_);
+}
+
+keymaster_error_t EcdsaOperation::InitDigest() {
+    switch (digest_) {
+    case KM_DIGEST_NONE:
+        return KM_ERROR_OK;
+    case KM_DIGEST_MD5:
+        return KM_ERROR_UNSUPPORTED_DIGEST;
+    case KM_DIGEST_SHA1:
+        digest_algorithm_ = EVP_sha1();
+        return KM_ERROR_OK;
+    case KM_DIGEST_SHA_2_224:
+        digest_algorithm_ = EVP_sha224();
+        return KM_ERROR_OK;
+    case KM_DIGEST_SHA_2_256:
+        digest_algorithm_ = EVP_sha256();
+        return KM_ERROR_OK;
+    case KM_DIGEST_SHA_2_384:
+        digest_algorithm_ = EVP_sha384();
+        return KM_ERROR_OK;
+    case KM_DIGEST_SHA_2_512:
+        digest_algorithm_ = EVP_sha512();
+        return KM_ERROR_OK;
+    default:
+        return KM_ERROR_UNSUPPORTED_DIGEST;
+    }
+}
+
+inline size_t min(size_t a, size_t b) {
+    return (a < b) ? a : b;
+}
+
+keymaster_error_t EcdsaOperation::StoreData(const Buffer& input, size_t* input_consumed) {
+    if (!data_.reserve((EVP_PKEY_bits(ecdsa_key_) + 7) / 8))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    if (!data_.write(input.peek_read(), min(data_.available_write(), input.available_read())))
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    *input_consumed = input.available_read();
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t EcdsaSignOperation::Begin(const AuthorizationSet& /* input_params */,
+                                            AuthorizationSet* /* output_params */) {
+    keymaster_error_t error = InitDigest();
+    if (error != KM_ERROR_OK)
+        return error;
+
+    if (digest_ == KM_DIGEST_NONE)
+        return KM_ERROR_OK;
+
+    EVP_PKEY_CTX* pkey_ctx;
+    if (EVP_DigestSignInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, nullptr /* engine */,
+                           ecdsa_key_) != 1)
+        return TranslateLastOpenSslError();
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t EcdsaSignOperation::Update(const AuthorizationSet& /* additional_params */,
+                                             const Buffer& input,
+                                             AuthorizationSet* /* output_params */,
+                                             Buffer* /* output */, size_t* input_consumed) {
+    if (digest_ == KM_DIGEST_NONE)
+        return StoreData(input, input_consumed);
+
+    if (EVP_DigestSignUpdate(&digest_ctx_, input.peek_read(), input.available_read()) != 1)
+        return TranslateLastOpenSslError();
+    *input_consumed = input.available_read();
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t EcdsaSignOperation::Finish(const AuthorizationSet& additional_params,
+                                             const Buffer& input, const Buffer& /* signature */,
+                                             AuthorizationSet* /* output_params */,
+                                             Buffer* output) {
+    if (!output)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    keymaster_error_t error = UpdateForFinish(additional_params, input);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    size_t siglen;
+    if (digest_ == KM_DIGEST_NONE) {
+        UniquePtr<EC_KEY, EC_KEY_Delete> ecdsa(EVP_PKEY_get1_EC_KEY(ecdsa_key_));
+        if (!ecdsa.get())
+            return TranslateLastOpenSslError();
+
+        output->Reinitialize(ECDSA_size(ecdsa.get()));
+        unsigned int siglen_tmp;
+        if (!ECDSA_sign(0 /* type -- ignored */, data_.peek_read(), data_.available_read(),
+                        output->peek_write(), &siglen_tmp, ecdsa.get()))
+            return TranslateLastOpenSslError();
+        siglen = siglen_tmp;
+    } else {
+        if (EVP_DigestSignFinal(&digest_ctx_, nullptr /* signature */, &siglen) != 1)
+            return TranslateLastOpenSslError();
+        if (!output->Reinitialize(siglen))
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        if (EVP_DigestSignFinal(&digest_ctx_, output->peek_write(), &siglen) <= 0)
+            return TranslateLastOpenSslError();
+    }
+    if (!output->advance_write(siglen))
+        return KM_ERROR_UNKNOWN_ERROR;
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t EcdsaVerifyOperation::Begin(const AuthorizationSet& /* input_params */,
+                                              AuthorizationSet* /* output_params */) {
+    keymaster_error_t error = InitDigest();
+    if (error != KM_ERROR_OK)
+        return error;
+
+    if (digest_ == KM_DIGEST_NONE)
+        return KM_ERROR_OK;
+
+    EVP_PKEY_CTX* pkey_ctx;
+    if (EVP_DigestVerifyInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, nullptr /* engine */,
+                             ecdsa_key_) != 1)
+        return TranslateLastOpenSslError();
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t EcdsaVerifyOperation::Update(const AuthorizationSet& /* additional_params */,
+                                               const Buffer& input,
+                                               AuthorizationSet* /* output_params */,
+                                               Buffer* /* output */, size_t* input_consumed) {
+    if (digest_ == KM_DIGEST_NONE)
+        return StoreData(input, input_consumed);
+
+    if (EVP_DigestVerifyUpdate(&digest_ctx_, input.peek_read(), input.available_read()) != 1)
+        return TranslateLastOpenSslError();
+    *input_consumed = input.available_read();
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t EcdsaVerifyOperation::Finish(const AuthorizationSet& additional_params,
+                                               const Buffer& input, const Buffer& signature,
+                                               AuthorizationSet* /* output_params */,
+                                               Buffer* /* output */) {
+    keymaster_error_t error = UpdateForFinish(additional_params, input);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    if (digest_ == KM_DIGEST_NONE) {
+        UniquePtr<EC_KEY, EC_KEY_Delete> ecdsa(EVP_PKEY_get1_EC_KEY(ecdsa_key_));
+        if (!ecdsa.get())
+            return TranslateLastOpenSslError();
+
+        int result =
+            ECDSA_verify(0 /* type -- ignored */, data_.peek_read(), data_.available_read(),
+                         signature.peek_read(), signature.available_read(), ecdsa.get());
+        if (result < 0)
+            return TranslateLastOpenSslError();
+        else if (result == 0)
+            return KM_ERROR_VERIFICATION_FAILED;
+    } else if (!EVP_DigestVerifyFinal(&digest_ctx_, signature.peek_read(),
+                                      signature.available_read()))
+        return KM_ERROR_VERIFICATION_FAILED;
+
+    return KM_ERROR_OK;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/ecdsa_operation.h b/keymaster/ecdsa_operation.h
new file mode 100644
index 0000000..4b95dc9
--- /dev/null
+++ b/keymaster/ecdsa_operation.h
@@ -0,0 +1,107 @@
+/*
+ * 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_ECDSA_OPERATION_H_
+#define SYSTEM_KEYMASTER_ECDSA_OPERATION_H_
+
+#include <openssl/ec.h>
+#include <openssl/evp.h>
+
+#include <UniquePtr.h>
+
+#include "operation.h"
+
+namespace keymaster {
+
+class EcdsaOperation : public Operation {
+  public:
+    EcdsaOperation(keymaster_purpose_t purpose, keymaster_digest_t digest, EVP_PKEY* key)
+        : Operation(purpose), digest_(digest), ecdsa_key_(key) {
+        EVP_MD_CTX_init(&digest_ctx_);
+    }
+    ~EcdsaOperation();
+
+    keymaster_error_t Abort() override { return KM_ERROR_OK; }
+
+  protected:
+    keymaster_error_t StoreData(const Buffer& input, size_t* input_consumed);
+    keymaster_error_t InitDigest();
+
+    keymaster_digest_t digest_;
+    const EVP_MD* digest_algorithm_;
+    EVP_PKEY* ecdsa_key_;
+    EVP_MD_CTX digest_ctx_;
+    Buffer data_;
+};
+
+class EcdsaSignOperation : public EcdsaOperation {
+  public:
+    EcdsaSignOperation(keymaster_digest_t digest, EVP_PKEY* key)
+        : EcdsaOperation(KM_PURPOSE_SIGN, digest, key) {}
+    keymaster_error_t Begin(const AuthorizationSet& input_params,
+                            AuthorizationSet* output_params) override;
+    keymaster_error_t Update(const AuthorizationSet& additional_params, const Buffer& input,
+                             AuthorizationSet* output_params, Buffer* output,
+                             size_t* input_consumed) override;
+    keymaster_error_t Finish(const AuthorizationSet& additional_params, const Buffer& input,
+                             const Buffer& signature, AuthorizationSet* output_params,
+                             Buffer* output) override;
+};
+
+class EcdsaVerifyOperation : public EcdsaOperation {
+  public:
+    EcdsaVerifyOperation(keymaster_digest_t digest, EVP_PKEY* key)
+        : EcdsaOperation(KM_PURPOSE_VERIFY, digest, key) {}
+    keymaster_error_t Begin(const AuthorizationSet& input_params,
+                            AuthorizationSet* output_params) override;
+    keymaster_error_t Update(const AuthorizationSet& additional_params, const Buffer& input,
+                             AuthorizationSet* output_params, Buffer* output,
+                             size_t* input_consumed) override;
+    keymaster_error_t Finish(const AuthorizationSet& additional_params, const Buffer& input,
+                             const Buffer& signature, AuthorizationSet* output_params,
+                             Buffer* output) override;
+};
+
+class EcdsaOperationFactory : public OperationFactory {
+  private:
+    KeyType registry_key() const override { return KeyType(KM_ALGORITHM_EC, purpose()); }
+    Operation* CreateOperation(const Key& key, const AuthorizationSet& begin_params,
+                               keymaster_error_t* error) override;
+    const keymaster_digest_t* SupportedDigests(size_t* digest_count) const override;
+
+    virtual keymaster_purpose_t purpose() const = 0;
+    virtual Operation* InstantiateOperation(keymaster_digest_t digest, EVP_PKEY* key) = 0;
+};
+
+class EcdsaSignOperationFactory : public EcdsaOperationFactory {
+  private:
+    keymaster_purpose_t purpose() const override { return KM_PURPOSE_SIGN; }
+    Operation* InstantiateOperation(keymaster_digest_t digest, EVP_PKEY* key) {
+        return new (std::nothrow) EcdsaSignOperation(digest, key);
+    }
+};
+
+class EcdsaVerifyOperationFactory : public EcdsaOperationFactory {
+  public:
+    keymaster_purpose_t purpose() const override { return KM_PURPOSE_VERIFY; }
+    Operation* InstantiateOperation(keymaster_digest_t digest, EVP_PKEY* key) {
+        return new (std::nothrow) EcdsaVerifyOperation(digest, key);
+    }
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_ECDSA_OPERATION_H_
diff --git a/keymaster/ecies_kem.cpp b/keymaster/ecies_kem.cpp
new file mode 100644
index 0000000..2e31573
--- /dev/null
+++ b/keymaster/ecies_kem.cpp
@@ -0,0 +1,185 @@
+/*
+ * 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 "ecies_kem.h"
+
+#include "nist_curve_key_exchange.h"
+#include "openssl_err.h"
+
+namespace keymaster {
+
+EciesKem::EciesKem(const AuthorizationSet& kem_description, keymaster_error_t* error) {
+    const AuthorizationSet& authorizations(kem_description);
+
+    if (!authorizations.GetTagValue(TAG_EC_CURVE, &curve_)) {
+        LOG_E("%s", "EciesKem: no curve specified");
+        *error = KM_ERROR_INVALID_ARGUMENT;
+        return;
+    }
+
+    switch (curve_) {
+    case KM_EC_CURVE_P_224:
+    case KM_EC_CURVE_P_256:
+    case KM_EC_CURVE_P_384:
+    case KM_EC_CURVE_P_521:
+        break;
+    default:
+        LOG_E("EciesKem: curve %d is unsupported", curve_);
+        *error = KM_ERROR_UNSUPPORTED_EC_CURVE;
+        return;
+    }
+
+    keymaster_kdf_t kdf;
+    if (!authorizations.GetTagValue(TAG_KDF, &kdf)) {
+        LOG_E("EciesKem: No KDF specified", 0);
+        *error = KM_ERROR_UNSUPPORTED_KDF;
+        return;
+    }
+    switch (kdf) {
+    case KM_KDF_RFC5869_SHA256:
+        kdf_.reset(new Rfc5869Sha256Kdf());
+        break;
+    default:
+        LOG_E("Kdf %d is unsupported", kdf);
+        *error = KM_ERROR_UNSUPPORTED_KDF;
+        return;
+    }
+    if (!kdf_.get()) {
+        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        return;
+    }
+
+    if (!authorizations.GetTagValue(TAG_KEY_SIZE, &key_bytes_to_generate_)) {
+        LOG_E("%s", "EciesKem: no key length specified");
+        *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
+        return;
+    }
+
+    single_hash_mode_ = authorizations.GetTagValue(TAG_ECIES_SINGLE_HASH_MODE);
+    *error = KM_ERROR_OK;
+}
+
+bool EciesKem::Encrypt(const Buffer& peer_public_value, Buffer* output_clear_key,
+                       Buffer* output_encrypted_key) {
+    return Encrypt(peer_public_value.peek_read(), peer_public_value.available_read(),
+                   output_clear_key, output_encrypted_key);
+}
+
+// http://www.shoup.net/iso/std6.pdf, section 10.2.3.
+bool EciesKem::Encrypt(const uint8_t* peer_public_value, size_t peer_public_value_len,
+                       Buffer* output_clear_key, Buffer* output_encrypted_key) {
+
+    key_exchange_.reset(NistCurveKeyExchange::GenerateKeyExchange(curve_));
+    if (!key_exchange_.get()) {
+        return false;
+    }
+
+    Buffer shared_secret;
+    if (!key_exchange_->CalculateSharedKey(peer_public_value, peer_public_value_len,
+                                           &shared_secret)) {
+        LOG_E("EciesKem: ECDH failed, can't obtain shared secret", 0);
+        return false;
+    }
+    if (!key_exchange_->public_value(output_encrypted_key)) {
+        LOG_E("EciesKem: Can't obtain public value", 0);
+        return false;
+    }
+
+    Buffer z;
+    if (single_hash_mode_) {
+        // z is empty.
+    } else {
+        // z = C0
+        z.Reinitialize(output_encrypted_key->peek_read(), output_encrypted_key->available_read());
+    }
+
+    Buffer actual_secret(z.available_read() + shared_secret.available_read());
+    actual_secret.write(z.peek_read(), z.available_read());
+    actual_secret.write(shared_secret.peek_read(), shared_secret.available_read());
+
+    if (!kdf_->Init(actual_secret.peek_read(), actual_secret.available_read(), nullptr /* salt */,
+                    0 /* salt_len */)) {
+        LOG_E("EciesKem: KDF failed, can't derived keys", 0);
+        return false;
+    }
+    output_clear_key->Reinitialize(key_bytes_to_generate_);
+    if (!kdf_->GenerateKey(nullptr /* info */, 0 /* info length */, output_clear_key->peek_write(),
+                           key_bytes_to_generate_)) {
+        LOG_E("EciesKem: KDF failed, can't derived keys", 0);
+        return false;
+    }
+    output_clear_key->advance_write(key_bytes_to_generate_);
+
+    return true;
+}
+
+bool EciesKem::Decrypt(EC_KEY* private_key, const Buffer& encrypted_key, Buffer* output_key) {
+    return Decrypt(private_key, encrypted_key.peek_read(), encrypted_key.available_read(),
+                   output_key);
+}
+
+// http://www.shoup.net/iso/std6.pdf, section 10.2.4.
+bool EciesKem::Decrypt(EC_KEY* private_key, const uint8_t* encrypted_key, size_t encrypted_key_len,
+                       Buffer* output_key) {
+
+    keymaster_error_t error;
+    key_exchange_.reset(new NistCurveKeyExchange(private_key, &error));
+    if (!key_exchange_.get() || error != KM_ERROR_OK) {
+        return false;
+    }
+
+    Buffer shared_secret;
+    if (!key_exchange_->CalculateSharedKey(encrypted_key, encrypted_key_len, &shared_secret)) {
+        LOG_E("EciesKem: ECDH failed, can't obtain shared secret", 0);
+        return false;
+    }
+
+    Buffer public_value;
+    if (!key_exchange_->public_value(&public_value)) {
+        LOG_E("%s", "EciesKem: Can't obtain public value");
+        return false;
+    }
+
+    Buffer z;
+    if (single_hash_mode_) {
+        // z is empty.
+    } else {
+        // z = C0
+        z.Reinitialize(public_value.peek_read(), public_value.available_read());
+    }
+
+    Buffer actual_secret(z.available_read() + shared_secret.available_read());
+    actual_secret.write(z.peek_read(), z.available_read());
+    actual_secret.write(shared_secret.peek_read(), shared_secret.available_read());
+
+    if (!kdf_->Init(actual_secret.peek_read(), actual_secret.available_read(), nullptr /* salt */,
+                    0 /* salt_len */)) {
+        LOG_E("%s", "EciesKem: KDF failed, can't derived keys");
+        return false;
+    }
+
+    output_key->Reinitialize(key_bytes_to_generate_);
+    if (!kdf_->GenerateKey(nullptr /* info */, 0 /* info_len */, output_key->peek_write(),
+                           key_bytes_to_generate_)) {
+        LOG_E("%s", "EciesKem: KDF failed, can't derived keys");
+        return false;
+    }
+    output_key->advance_write(key_bytes_to_generate_);
+
+    return true;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/ecies_kem.h b/keymaster/ecies_kem.h
new file mode 100644
index 0000000..8c1b330
--- /dev/null
+++ b/keymaster/ecies_kem.h
@@ -0,0 +1,61 @@
+/*
+ * 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_ECIES_KEM_H_
+#define SYSTEM_KEYMASTER_ECIES_KEM_H_
+
+#include "kem.h"
+
+#include <UniquePtr.h>
+#include <openssl/ec.h>
+
+#include <keymaster/authorization_set.h>
+
+#include "hkdf.h"
+#include "key_exchange.h"
+
+namespace keymaster {
+
+/**
+ * EciesKem is an implementation of the key encapsulation mechanism ECIES-KEM described in
+ * ISO 18033-2 (http://www.shoup.net/iso/std6.pdf, http://www.shoup.net/papers/iso-2_1.pdf).
+ */
+class EciesKem : public Kem {
+  public:
+    virtual ~EciesKem() override {}
+    EciesKem(const AuthorizationSet& kem_description, keymaster_error_t* error);
+
+    /* Kem interface. */
+    bool Encrypt(const Buffer& peer_public_value, Buffer* output_clear_key,
+                 Buffer* output_encrypted_key) override;
+    bool Encrypt(const uint8_t* peer_public_value, size_t peer_public_value_len,
+                 Buffer* output_clear_key, Buffer* output_encrypted_key) override;
+
+    bool Decrypt(EC_KEY* private_key, const Buffer& encrypted_key, Buffer* output_key) override;
+    bool Decrypt(EC_KEY* private_key, const uint8_t* encrypted_key, size_t encrypted_key_len,
+                 Buffer* output_key) override;
+
+  private:
+    UniquePtr<KeyExchange> key_exchange_;
+    UniquePtr<Rfc5869Sha256Kdf> kdf_;
+    bool single_hash_mode_;
+    uint32_t key_bytes_to_generate_;
+    keymaster_ec_curve_t curve_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_ECIES_KEM_H_
diff --git a/keymaster/ecies_kem_test.cpp b/keymaster/ecies_kem_test.cpp
new file mode 100644
index 0000000..f653dc0
--- /dev/null
+++ b/keymaster/ecies_kem_test.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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 "ecies_kem.h"
+
+#include <gtest/gtest.h>
+#include <openssl/evp.h>
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/android_keymaster_utils.h>
+
+#include "android_keymaster_test_utils.h"
+#include "nist_curve_key_exchange.h"
+
+using std::string;
+
+namespace keymaster {
+namespace test {
+
+StdoutLogger logger;
+
+static const keymaster_ec_curve_t kEcCurves[] = {KM_EC_CURVE_P_224, KM_EC_CURVE_P_256,
+                                                 KM_EC_CURVE_P_384, KM_EC_CURVE_P_521};
+
+/**
+ * TestConsistency just tests that the basic key encapsulation hold.
+ */
+TEST(EciesKem, TestConsistency) {
+    static const uint32_t kKeyLen = 32;
+    for (auto& curve : kEcCurves) {
+        AuthorizationSet kem_description(AuthorizationSetBuilder()
+                                             .Authorization(TAG_EC_CURVE, curve)
+                                             .Authorization(TAG_KDF, KM_KDF_RFC5869_SHA256)
+                                             .Authorization(TAG_ECIES_SINGLE_HASH_MODE)
+                                             .Authorization(TAG_KEY_SIZE, kKeyLen));
+        keymaster_error_t error;
+        EciesKem* kem = new EciesKem(kem_description, &error);
+        ASSERT_EQ(KM_ERROR_OK, error);
+
+        NistCurveKeyExchange* key_exchange = NistCurveKeyExchange::GenerateKeyExchange(curve);
+        Buffer peer_public_value;
+        ASSERT_TRUE(key_exchange->public_value(&peer_public_value));
+
+        Buffer output_clear_key;
+        Buffer output_encrypted_key;
+        ASSERT_TRUE(kem->Encrypt(peer_public_value, &output_clear_key, &output_encrypted_key));
+        ASSERT_EQ(kKeyLen, output_clear_key.available_read());
+        ASSERT_EQ(peer_public_value.available_read(), output_encrypted_key.available_read());
+
+        Buffer decrypted_clear_key;
+        ASSERT_TRUE(
+            kem->Decrypt(key_exchange->private_key(), output_encrypted_key, &decrypted_clear_key));
+        ASSERT_EQ(kKeyLen, decrypted_clear_key.available_read());
+        EXPECT_EQ(0, memcmp(output_clear_key.peek_read(), decrypted_clear_key.peek_read(),
+                            output_clear_key.available_read()));
+    }
+}
+
+}  // namespace test
+}  // namespace keymaster
diff --git a/keymaster/gtest_main.cpp b/keymaster/gtest_main.cpp
new file mode 100644
index 0000000..6072749
--- /dev/null
+++ b/keymaster/gtest_main.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 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 <gtest/gtest.h>
+
+#include <openssl/engine.h>
+
+int main(int argc, char** argv) {
+#if !defined(OPENSSL_IS_BORINGSSL)
+    ERR_load_crypto_strings();
+#endif // not OPENSSL_IS_BORINGSSL
+    ::testing::InitGoogleTest(&argc, argv);
+    int result = RUN_ALL_TESTS();
+#if !defined(OPENSSL_IS_BORINGSSL)
+    // Clean up stuff OpenSSL leaves around, so Valgrind doesn't complain.
+    CRYPTO_cleanup_all_ex_data();
+    ERR_remove_thread_state(NULL);
+    ERR_free_strings();
+#endif // not OPENSSL_IS_BORINGSSL
+    return result;
+}
diff --git a/keymaster/hkdf.cpp b/keymaster/hkdf.cpp
new file mode 100644
index 0000000..9727375
--- /dev/null
+++ b/keymaster/hkdf.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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 "hkdf.h"
+
+#include <new>
+
+#include <keymaster/android_keymaster_utils.h>
+
+#include "hmac.h"
+
+namespace keymaster {
+
+bool Rfc5869Sha256Kdf::GenerateKey(const uint8_t* info, size_t info_len, uint8_t* output,
+                                   size_t output_len) {
+    if (!is_initialized_ || output == nullptr)
+        return false;
+    /**
+     * Step 1. Extract: PRK = HMAC-SHA256(actual_salt, secret)
+     * https://tools.ietf.org/html/rfc5869#section-2.2
+     */
+    HmacSha256 prk_hmac;
+    bool result;
+    if (salt_.get() != nullptr && salt_len_ > 0) {
+        result = prk_hmac.Init(salt_.get(), salt_len_);
+    } else {
+        UniquePtr<uint8_t[]> zeros(new uint8_t[digest_size_]);
+        if (zeros.get() == nullptr)
+            return false;
+        /* If salt is not given, digest size of zeros are used. */
+        memset(zeros.get(), 0, digest_size_);
+        result = prk_hmac.Init(zeros.get(), digest_size_);
+    }
+    if (!result)
+        return false;
+
+    UniquePtr<uint8_t[]> pseudo_random_key(new uint8_t[digest_size_]);
+    if (pseudo_random_key.get() == nullptr || digest_size_ != prk_hmac.DigestLength())
+        return false;
+    result =
+        prk_hmac.Sign(secret_key_.get(), secret_key_len_, pseudo_random_key.get(), digest_size_);
+    if (!result)
+        return false;
+
+    /**
+     * Step 2. Expand: OUTPUT = HKDF-Expand(PRK, info)
+     * https://tools.ietf.org/html/rfc5869#section-2.3
+     */
+    const size_t num_blocks = (output_len + digest_size_ - 1) / digest_size_;
+    if (num_blocks >= 256u)
+        return false;
+
+    UniquePtr<uint8_t[]> buf(new uint8_t[digest_size_ + info_len + 1]);
+    UniquePtr<uint8_t[]> digest(new uint8_t[digest_size_]);
+    if (buf.get() == nullptr || digest.get() == nullptr)
+        return false;
+    HmacSha256 hmac;
+    result = hmac.Init(pseudo_random_key.get(), digest_size_);
+    if (!result)
+        return false;
+
+    for (size_t i = 0; i < num_blocks; i++) {
+        size_t block_input_len = 0;
+        if (i != 0) {
+            memcpy(buf.get(), digest.get(), digest_size_);
+            block_input_len = digest_size_;
+        }
+        if (info != nullptr && info_len > 0)
+            memcpy(buf.get() + block_input_len, info, info_len);
+        block_input_len += info_len;
+        *(buf.get() + block_input_len++) = static_cast<uint8_t>(i + 1);
+        result = hmac.Sign(buf.get(), block_input_len, digest.get(), digest_size_);
+        if (!result)
+            return false;
+        size_t block_output_len = digest_size_ < output_len - i * digest_size_
+                                      ? digest_size_
+                                      : output_len - i * digest_size_;
+        memcpy(output + i * digest_size_, digest.get(), block_output_len);
+    }
+    return true;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/hkdf.h b/keymaster/hkdf.h
new file mode 100644
index 0000000..9de39bf
--- /dev/null
+++ b/keymaster/hkdf.h
@@ -0,0 +1,50 @@
+/*
+ * 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_HKDF_H_
+#define SYSTEM_KEYMASTER_HKDF_H_
+
+#include "kdf.h"
+
+#include <keymaster/serializable.h>
+
+#include <UniquePtr.h>
+
+namespace keymaster {
+
+/**
+ * Rfc5869Sha256Kdf implements the key derivation function specified in RFC 5869 (using SHA256) and
+ * outputs key material, as needed by ECIES. See https://tools.ietf.org/html/rfc5869 for details.
+ */
+class Rfc5869Sha256Kdf : public Kdf {
+  public:
+    ~Rfc5869Sha256Kdf() {}
+    bool Init(Buffer& secret, Buffer& salt) {
+        return Init(secret.peek_read(), secret.available_read(), salt.peek_read(),
+                    salt.available_read());
+    }
+
+    bool Init(const uint8_t* secret, size_t secret_len, const uint8_t* salt, size_t salt_len) {
+        return Kdf::Init(KM_DIGEST_SHA_2_256, secret, secret_len, salt, salt_len);
+    }
+
+    bool GenerateKey(const uint8_t* info, size_t info_len, uint8_t* output,
+                     size_t output_len) override;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_HKDF_H_
diff --git a/keymaster/hkdf_test.cpp b/keymaster/hkdf_test.cpp
new file mode 100644
index 0000000..3d3f092
--- /dev/null
+++ b/keymaster/hkdf_test.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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 "hkdf.h"
+
+#include <gtest/gtest.h>
+#include <string.h>
+
+#include "android_keymaster_test_utils.h"
+
+using std::string;
+
+namespace keymaster {
+namespace test {
+
+struct HkdfTest {
+    const char* key_hex;
+    const char* salt_hex;
+    const char* info_hex;
+    const char* output_hex;
+};
+
+// These test cases are taken from
+// https://tools.ietf.org/html/rfc5869#appendix-A.
+static const HkdfTest kHkdfTests[] = {
+    {
+        "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c",
+        "f0f1f2f3f4f5f6f7f8f9",
+        "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865",
+    },
+    {
+        "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c"
+        "2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f",
+        "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c"
+        "8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
+        "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdc"
+        "dddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+        "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e"
+        "590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87",
+    },
+    {
+        "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "", "",
+        "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8",
+    },
+};
+
+TEST(HkdfTest, Hkdf) {
+    for (auto& test : kHkdfTests) {
+        const string key = hex2str(test.key_hex);
+        const string salt = hex2str(test.salt_hex);
+        const string info = hex2str(test.info_hex);
+        const string expected = hex2str(test.output_hex);
+        size_t output_len = expected.size();
+        uint8_t output[output_len];
+        Rfc5869Sha256Kdf hkdf;
+        ASSERT_TRUE(hkdf.Init(reinterpret_cast<const uint8_t*>(key.data()), key.size(),
+                              reinterpret_cast<const uint8_t*>(salt.data()), salt.size()));
+        ASSERT_TRUE(hkdf.GenerateKey(reinterpret_cast<const uint8_t*>(info.data()), info.size(),
+                                     output, output_len));
+        EXPECT_EQ(0, memcmp(output, expected.data(), output_len));
+    }
+}
+
+}  // namespace test
+}  // namespace keymaster
diff --git a/keymaster/hmac.cpp b/keymaster/hmac.cpp
new file mode 100644
index 0000000..02f739c
--- /dev/null
+++ b/keymaster/hmac.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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 "hmac.h"
+
+#include <assert.h>
+
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/mem.h>
+#include <openssl/sha.h>
+
+#include <keymaster/android_keymaster_utils.h>
+
+namespace keymaster {
+
+size_t HmacSha256::DigestLength() const {
+    return SHA256_DIGEST_LENGTH;
+}
+
+bool HmacSha256::Init(const Buffer& key) {
+    return Init(key.peek_read(), key.available_read());
+}
+
+bool HmacSha256::Init(const uint8_t* key, size_t key_len) {
+    if (!key)
+        return false;
+
+    key_len_ = key_len;
+    key_.reset(dup_buffer(key, key_len));
+    if (!key_.get()) {
+        return false;
+    }
+    return true;
+}
+
+bool HmacSha256::Sign(const Buffer& data, uint8_t* out_digest, size_t digest_len) const {
+    return Sign(data.peek_read(), data.available_read(), out_digest, digest_len);
+}
+
+bool HmacSha256::Sign(const uint8_t* data, size_t data_len, uint8_t* out_digest,
+                      size_t digest_len) const {
+    assert(digest_len);
+
+    uint8_t tmp[SHA256_DIGEST_LENGTH];
+    uint8_t* digest = tmp;
+    if (digest_len >= SHA256_DIGEST_LENGTH)
+        digest = out_digest;
+
+    if (nullptr == ::HMAC(EVP_sha256(), key_.get(), key_len_, data, data_len, digest, nullptr)) {
+        return false;
+    }
+    if (digest_len < SHA256_DIGEST_LENGTH)
+        memcpy(out_digest, tmp, digest_len);
+
+    return true;
+}
+
+bool HmacSha256::Verify(const Buffer& data, const Buffer& digest) const {
+    return Verify(data.peek_read(), data.available_read(), digest.peek_read(),
+                  digest.available_read());
+}
+
+bool HmacSha256::Verify(const uint8_t* data, size_t data_len, const uint8_t* digest,
+                        size_t digest_len) const {
+    if (digest_len != SHA256_DIGEST_LENGTH)
+        return false;
+
+    uint8_t computed_digest[SHA256_DIGEST_LENGTH];
+    if (!Sign(data, data_len, computed_digest, sizeof(computed_digest)))
+        return false;
+
+    return 0 == CRYPTO_memcmp(digest, computed_digest, SHA256_DIGEST_LENGTH);
+}
+
+}  // namespace keymaster
diff --git a/keymaster/hmac.h b/keymaster/hmac.h
new file mode 100644
index 0000000..ebd5b70
--- /dev/null
+++ b/keymaster/hmac.h
@@ -0,0 +1,60 @@
+/*
+ * 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_HMAC_H_
+#define SYSTEM_KEYMASTER_HMAC_H_
+
+#include <keymaster/serializable.h>
+
+namespace keymaster {
+
+// Only HMAC-SHA256 is supported.
+class HmacSha256 {
+  public:
+    HmacSha256(){};
+
+    // DigestLength returns the length, in bytes, of the resulting digest.
+    size_t DigestLength() const;
+
+    // Initializes this instance using |key|. Call Init only once. It returns
+    // false on the second of later calls.
+    bool Init(const uint8_t* key, size_t key_length);
+    bool Init(const Buffer& key);
+
+    // Sign calculates the HMAC of |data| with the key supplied to the Init
+    // method. At most |digest_len| bytes of the resulting digest are written
+    // to |digest|.
+    bool Sign(const Buffer& data, uint8_t* digest, size_t digest_len) const;
+    bool Sign(const uint8_t* data, size_t data_len, uint8_t* digest, size_t digest_len) const;
+
+    // Verify returns true if |digest| is a valid HMAC of |data| using the key
+    // supplied to Init. |digest| must be exactly |DigestLength()| bytes long.
+    // Use of this method is strongly recommended over using Sign() with a manual
+    // comparison (such as memcmp), as such comparisons may result in
+    // side-channel disclosures, such as timing, that undermine the cryptographic
+    // integrity.
+    bool Verify(const Buffer& data, const Buffer& digest) const;
+    bool Verify(const uint8_t* data, size_t data_len, const uint8_t* digest,
+                size_t digest_len) const;
+
+  private:
+    UniquePtr<uint8_t[]> key_;
+    size_t key_len_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_HMAC_H_
diff --git a/keymaster/hmac_key.cpp b/keymaster/hmac_key.cpp
new file mode 100644
index 0000000..40a8906
--- /dev/null
+++ b/keymaster/hmac_key.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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 "hmac_key.h"
+
+#include <new>
+
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+#include "hmac_operation.h"
+
+namespace keymaster {
+
+static HmacSignOperationFactory sign_factory;
+static HmacVerifyOperationFactory verify_factory;
+
+OperationFactory* HmacKeyFactory::GetOperationFactory(keymaster_purpose_t purpose) const {
+    switch (purpose) {
+    case KM_PURPOSE_SIGN:
+        return &sign_factory;
+    case KM_PURPOSE_VERIFY:
+        return &verify_factory;
+    default:
+        return nullptr;
+    }
+}
+
+keymaster_error_t HmacKeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+                                          const AuthorizationSet& /* additional_params */,
+                                          const AuthorizationSet& hw_enforced,
+                                          const AuthorizationSet& sw_enforced,
+                                          UniquePtr<Key>* key) const {
+    if (!key)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    uint32_t min_mac_length;
+    if (!hw_enforced.GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length) &&
+        !sw_enforced.GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length)) {
+        LOG_E("HMAC key must have KM_TAG_MIN_MAC_LENGTH", 0);
+        return KM_ERROR_INVALID_KEY_BLOB;
+    }
+
+    keymaster_error_t error;
+    key->reset(new (std::nothrow) HmacKey(key_material, hw_enforced, sw_enforced, &error));
+    if (!key->get())
+        error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    return error;
+}
+
+keymaster_error_t HmacKeyFactory::validate_algorithm_specific_new_key_params(
+    const AuthorizationSet& key_description) const {
+    uint32_t min_mac_length_bits;
+    if (!key_description.GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length_bits))
+        return KM_ERROR_MISSING_MIN_MAC_LENGTH;
+
+    keymaster_digest_t digest;
+    if (!key_description.GetTagValue(TAG_DIGEST, &digest)) {
+        LOG_E("%d digests specified for HMAC key", key_description.GetTagCount(TAG_DIGEST));
+        return KM_ERROR_UNSUPPORTED_DIGEST;
+    }
+
+    size_t hash_size_bits = 0;
+    switch (digest) {
+    case KM_DIGEST_NONE:
+        return KM_ERROR_UNSUPPORTED_DIGEST;
+    case KM_DIGEST_MD5:
+        hash_size_bits = 128;
+        break;
+    case KM_DIGEST_SHA1:
+        hash_size_bits = 160;
+        break;
+    case KM_DIGEST_SHA_2_224:
+        hash_size_bits = 224;
+        break;
+    case KM_DIGEST_SHA_2_256:
+        hash_size_bits = 256;
+        break;
+    case KM_DIGEST_SHA_2_384:
+        hash_size_bits = 384;
+        break;
+    case KM_DIGEST_SHA_2_512:
+        hash_size_bits = 512;
+        break;
+    };
+
+    if (hash_size_bits == 0) {
+        // digest was not matched
+        return KM_ERROR_UNSUPPORTED_DIGEST;
+    }
+
+    if (min_mac_length_bits % 8 != 0 || min_mac_length_bits > hash_size_bits)
+        return KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH;
+
+    if (min_mac_length_bits < kMinHmacLengthBits)
+        return KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH;
+
+    return KM_ERROR_OK;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/hmac_key.h b/keymaster/hmac_key.h
new file mode 100644
index 0000000..c05e6a3
--- /dev/null
+++ b/keymaster/hmac_key.h
@@ -0,0 +1,56 @@
+/*
+ * 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_HMAC_KEY_H_
+#define SYSTEM_KEYMASTER_HMAC_KEY_H_
+
+#include "symmetric_key.h"
+
+namespace keymaster {
+
+const size_t kMinHmacLengthBits = 64;
+
+class HmacKeyFactory : public SymmetricKeyFactory {
+  public:
+    explicit HmacKeyFactory(const KeymasterContext* context) : SymmetricKeyFactory(context) {}
+
+    keymaster_error_t LoadKey(const KeymasterKeyBlob& key_material,
+                              const AuthorizationSet& additional_params,
+                              const AuthorizationSet& hw_enforced,
+                              const AuthorizationSet& sw_enforced,
+                              UniquePtr<Key>* key) const override;
+
+    OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const 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 */;
+    }
+    keymaster_error_t validate_algorithm_specific_new_key_params(
+        const AuthorizationSet& key_description) const override;
+};
+
+class HmacKey : public SymmetricKey {
+  public:
+    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
+
+#endif  // SYSTEM_KEYMASTER_HMAC_KEY_H_
diff --git a/keymaster/hmac_operation.cpp b/keymaster/hmac_operation.cpp
new file mode 100644
index 0000000..7f21393
--- /dev/null
+++ b/keymaster/hmac_operation.cpp
@@ -0,0 +1,197 @@
+/*
+ * 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 "hmac_operation.h"
+
+#include <new>
+
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+
+#include "hmac_key.h"
+#include "openssl_err.h"
+
+#if defined(OPENSSL_IS_BORINGSSL)
+#include <openssl/mem.h>
+typedef size_t openssl_size_t;
+#else
+typedef int openssl_size_t;
+#endif
+
+namespace keymaster {
+
+Operation* HmacOperationFactory::CreateOperation(const Key& key,
+                                                 const AuthorizationSet& begin_params,
+                                                 keymaster_error_t* error) {
+    uint32_t min_mac_length_bits;
+    if (!key.authorizations().GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length_bits)) {
+        LOG_E("HMAC key must have KM_TAG_MIN_MAC_LENGTH", 0);
+        *error = KM_ERROR_INVALID_KEY_BLOB;
+        return nullptr;
+    }
+
+    uint32_t mac_length_bits = UINT32_MAX;
+    if (begin_params.GetTagValue(TAG_MAC_LENGTH, &mac_length_bits)) {
+        if (purpose() == KM_PURPOSE_VERIFY) {
+            LOG_E("MAC length may not be specified for verify", 0);
+            *error = KM_ERROR_INVALID_ARGUMENT;
+            return nullptr;
+        }
+    } else {
+        if (purpose() == KM_PURPOSE_SIGN) {
+            *error = KM_ERROR_MISSING_MAC_LENGTH;
+            return nullptr;
+        }
+    }
+
+    keymaster_digest_t digest;
+    if (!key.authorizations().GetTagValue(TAG_DIGEST, &digest)) {
+        LOG_E("%d digests found in HMAC key authorizations; must be exactly 1",
+              begin_params.GetTagCount(TAG_DIGEST));
+        *error = KM_ERROR_INVALID_KEY_BLOB;
+        return nullptr;
+    }
+
+    const SymmetricKey* symmetric_key = static_cast<const SymmetricKey*>(&key);
+    UniquePtr<HmacOperation> op(new (std::nothrow) HmacOperation(
+        purpose(), symmetric_key->key_data(), symmetric_key->key_data_size(), digest,
+        mac_length_bits / 8, min_mac_length_bits / 8));
+    if (!op.get())
+        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    else
+        *error = op->error();
+
+    if (*error != KM_ERROR_OK)
+        return nullptr;
+
+    return op.release();
+}
+
+static keymaster_digest_t supported_digests[] = {KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224,
+                                                 KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384,
+                                                 KM_DIGEST_SHA_2_512};
+const keymaster_digest_t* HmacOperationFactory::SupportedDigests(size_t* digest_count) const {
+    *digest_count = array_length(supported_digests);
+    return supported_digests;
+}
+
+HmacOperation::HmacOperation(keymaster_purpose_t purpose, const uint8_t* key_data,
+                             size_t key_data_size, keymaster_digest_t digest, size_t mac_length,
+                             size_t min_mac_length)
+    : Operation(purpose), error_(KM_ERROR_OK), mac_length_(mac_length),
+      min_mac_length_(min_mac_length) {
+    // Initialize CTX first, so dtor won't crash even if we error out later.
+    HMAC_CTX_init(&ctx_);
+
+    const EVP_MD* md = nullptr;
+    switch (digest) {
+    case KM_DIGEST_NONE:
+    case KM_DIGEST_MD5:
+        error_ = KM_ERROR_UNSUPPORTED_DIGEST;
+        break;
+    case KM_DIGEST_SHA1:
+        md = EVP_sha1();
+        break;
+    case KM_DIGEST_SHA_2_224:
+        md = EVP_sha224();
+        break;
+    case KM_DIGEST_SHA_2_256:
+        md = EVP_sha256();
+        break;
+    case KM_DIGEST_SHA_2_384:
+        md = EVP_sha384();
+        break;
+    case KM_DIGEST_SHA_2_512:
+        md = EVP_sha512();
+        break;
+    }
+
+    if (md == nullptr) {
+        error_ = KM_ERROR_UNSUPPORTED_DIGEST;
+        return;
+    }
+
+    if (purpose == KM_PURPOSE_SIGN) {
+        if (mac_length > EVP_MD_size(md) || mac_length < kMinHmacLengthBits / 8) {
+            error_ = KM_ERROR_UNSUPPORTED_MAC_LENGTH;
+            return;
+        }
+        if (mac_length < min_mac_length) {
+            error_ = KM_ERROR_INVALID_MAC_LENGTH;
+            return;
+        }
+    }
+
+    HMAC_Init_ex(&ctx_, key_data, key_data_size, md, NULL /* engine */);
+}
+
+HmacOperation::~HmacOperation() {
+    HMAC_CTX_cleanup(&ctx_);
+}
+
+keymaster_error_t HmacOperation::Begin(const AuthorizationSet& /* input_params */,
+                                       AuthorizationSet* /* output_params */) {
+    return error_;
+}
+
+keymaster_error_t HmacOperation::Update(const AuthorizationSet& /* additional_params */,
+                                        const Buffer& input, AuthorizationSet* /* output_params */,
+                                        Buffer* /* output */, size_t* input_consumed) {
+    if (!HMAC_Update(&ctx_, input.peek_read(), input.available_read()))
+        return TranslateLastOpenSslError();
+    *input_consumed = input.available_read();
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t HmacOperation::Abort() {
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t HmacOperation::Finish(const AuthorizationSet& additional_params,
+                                        const Buffer& input, const Buffer& signature,
+                                        AuthorizationSet* /* output_params */, Buffer* output) {
+    keymaster_error_t error = UpdateForFinish(additional_params, input);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    uint8_t digest[EVP_MAX_MD_SIZE];
+    unsigned int digest_len;
+    if (!HMAC_Final(&ctx_, digest, &digest_len))
+        return TranslateLastOpenSslError();
+
+    switch (purpose()) {
+    case KM_PURPOSE_SIGN:
+        if (mac_length_ > digest_len)
+            return KM_ERROR_UNSUPPORTED_MAC_LENGTH;
+        if (!output->reserve(mac_length_) || !output->write(digest, mac_length_))
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        return KM_ERROR_OK;
+    case KM_PURPOSE_VERIFY: {
+        size_t siglen = signature.available_read();
+        if (siglen > digest_len || siglen < kMinHmacLengthBits / 8)
+            return KM_ERROR_UNSUPPORTED_MAC_LENGTH;
+        if (siglen < min_mac_length_)
+            return KM_ERROR_INVALID_MAC_LENGTH;
+        if (CRYPTO_memcmp(signature.peek_read(), digest, siglen) != 0)
+            return KM_ERROR_VERIFICATION_FAILED;
+        return KM_ERROR_OK;
+    }
+    default:
+        return KM_ERROR_UNSUPPORTED_PURPOSE;
+    }
+}
+
+}  // namespace keymaster
diff --git a/keymaster/hmac_operation.h b/keymaster/hmac_operation.h
new file mode 100644
index 0000000..83f2e09
--- /dev/null
+++ b/keymaster/hmac_operation.h
@@ -0,0 +1,77 @@
+/*
+ * 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_HMAC_OPERATION_H_
+#define SYSTEM_KEYMASTER_HMAC_OPERATION_H_
+
+#include "operation.h"
+
+#include <openssl/hmac.h>
+
+namespace keymaster {
+
+class HmacOperation : public Operation {
+  public:
+    HmacOperation(keymaster_purpose_t purpose, const uint8_t* key_data, size_t key_data_size,
+                  keymaster_digest_t digest, size_t mac_length, size_t min_mac_length);
+    ~HmacOperation();
+
+    virtual keymaster_error_t Begin(const AuthorizationSet& input_params,
+                                    AuthorizationSet* output_params);
+    virtual keymaster_error_t Update(const AuthorizationSet& additional_params, const Buffer& input,
+                                     AuthorizationSet* output_params, Buffer* output,
+                                     size_t* input_consumed);
+    virtual keymaster_error_t Abort();
+    virtual keymaster_error_t Finish(const AuthorizationSet& additional_params, const Buffer& input,
+                                     const Buffer& signature, AuthorizationSet* output_params,
+                                     Buffer* output);
+
+    keymaster_error_t error() { return error_; }
+
+  private:
+    HMAC_CTX ctx_;
+    keymaster_error_t error_;
+    const size_t mac_length_;
+    const size_t min_mac_length_;
+};
+
+/**
+ * Abstract base for HMAC operation factories.  This class does all of the work to create
+ * HMAC operations.
+ */
+class HmacOperationFactory : public OperationFactory {
+  public:
+    virtual KeyType registry_key() const { return KeyType(KM_ALGORITHM_HMAC, purpose()); }
+
+    virtual Operation* CreateOperation(const Key& key, const AuthorizationSet& begin_params,
+                                       keymaster_error_t* error);
+
+    virtual const keymaster_digest_t* SupportedDigests(size_t* digest_count) const;
+
+    virtual keymaster_purpose_t purpose() const = 0;
+};
+
+class HmacSignOperationFactory : public HmacOperationFactory {
+    keymaster_purpose_t purpose() const { return KM_PURPOSE_SIGN; }
+};
+
+class HmacVerifyOperationFactory : public HmacOperationFactory {
+    keymaster_purpose_t purpose() const { return KM_PURPOSE_VERIFY; }
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_HMAC_OPERATION_H_
diff --git a/keymaster/hmac_test.cpp b/keymaster/hmac_test.cpp
new file mode 100644
index 0000000..04f9356
--- /dev/null
+++ b/keymaster/hmac_test.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 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 "hmac.h"
+
+#include <gtest/gtest.h>
+#include <string.h>
+
+#include "android_keymaster_test_utils.h"
+
+using std::string;
+
+namespace keymaster {
+
+namespace test {
+
+struct HmacTest {
+    const char* data;
+    const char* key;
+    uint8_t digest[32];
+};
+
+static const HmacTest kHmacTests[] = {
+    {
+        "Test Using Larger Than Block-Size Key - Hash Key First",
+        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+        {
+            0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5,
+            0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f,
+            0x0e, 0xe3, 0x7f, 0x54,
+        },
+    },
+    {
+        "The test message for the MD2, MD5, and SHA-1 hashing algorithms.",
+        "46697265666f7820616e64205468756e64657242697264206172652061776573"
+        "6f6d652100",
+        {
+            0x05, 0x75, 0x9a, 0x9e, 0x70, 0x5e, 0xe7, 0x44, 0xe2, 0x46, 0x4b, 0x92, 0x22, 0x14,
+            0x22, 0xe0, 0x1b, 0x92, 0x8a, 0x0c, 0xfe, 0xf5, 0x49, 0xe9, 0xa7, 0x1b, 0x56, 0x7d,
+            0x1d, 0x29, 0x40, 0x48,
+        },
+    },
+};
+
+TEST(HmacTest, SHA256) {
+    for (size_t i = 0; i < 2; i++) {
+        const HmacTest& test(kHmacTests[i]);
+
+        HmacSha256 hmac;
+        const string key = hex2str(test.key);
+        Buffer key_buffer(key.data(), key.size());
+        ASSERT_TRUE(hmac.Init(key_buffer));
+
+        uint8_t digest_copy[sizeof(test.digest)];
+        memcpy(digest_copy, test.digest, sizeof(test.digest));
+        Buffer digest_buffer(reinterpret_cast<uint8_t*>(digest_copy), sizeof(digest_copy));
+
+        Buffer data_buffer(test.data, strlen(test.data));
+        EXPECT_TRUE(hmac.Verify(data_buffer, digest_buffer));
+
+        digest_copy[16] ^= 0x80;
+        digest_buffer.Reinitialize(reinterpret_cast<uint8_t*>(digest_copy), sizeof(digest_copy));
+        EXPECT_FALSE(hmac.Verify(data_buffer, digest_buffer));
+    }
+}
+
+}  // namespace test
+}  // namespace keymaster
diff --git a/keymaster/include/keymaster/android_keymaster.h b/keymaster/include/keymaster/android_keymaster.h
new file mode 100644
index 0000000..c7ecfad
--- /dev/null
+++ b/keymaster/include/keymaster/android_keymaster.h
@@ -0,0 +1,95 @@
+/*
+ * 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_KEYMASTER_H_
+#define SYSTEM_KEYMASTER_ANDROID_KEYMASTER_H_
+
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/authorization_set.h>
+
+namespace keymaster {
+
+class Key;
+class KeyFactory;
+class KeymasterContext;
+class OperationTable;
+
+/**
+ * This is the reference implementation of Keymaster.  In addition to acting as a reference for
+ * other Keymaster implementers to check their assumptions against, it is used by Keystore as the
+ * default implementation when no secure implementation is available, and may be installed and
+ * executed in secure hardware as a secure implementation.
+ *
+ * Note that this class doesn't actually implement the Keymaster HAL interface, instead it
+ * implements an alternative API which is similar to and based upon the HAL, but uses C++ "message"
+ * classes which support serialization.
+ *
+ * For non-secure, pure software implementation there is a HAL translation layer that converts the
+ * HAL's parameters to and from the message representations, which are then passed in to this
+ * API.
+ *
+ * For secure implementation there is another HAL translation layer that serializes the messages to
+ * the TEE. In the TEE implementation there's another component which deserializes the messages,
+ * extracts the relevant parameters and calls this API.
+ */
+class AndroidKeymaster {
+  public:
+    AndroidKeymaster(KeymasterContext* context, size_t operation_table_size);
+    virtual ~AndroidKeymaster();
+
+    void GetVersion(const GetVersionRequest& request, GetVersionResponse* response);
+    void SupportedAlgorithms(const SupportedAlgorithmsRequest& request,
+                             SupportedAlgorithmsResponse* response);
+    void SupportedBlockModes(const SupportedBlockModesRequest& request,
+                             SupportedBlockModesResponse* response);
+    void SupportedPaddingModes(const SupportedPaddingModesRequest& request,
+                               SupportedPaddingModesResponse* response);
+    void SupportedDigests(const SupportedDigestsRequest& request,
+                          SupportedDigestsResponse* response);
+    void SupportedImportFormats(const SupportedImportFormatsRequest& request,
+                                SupportedImportFormatsResponse* response);
+    void SupportedExportFormats(const SupportedExportFormatsRequest& request,
+                                SupportedExportFormatsResponse* response);
+
+    void AddRngEntropy(const AddEntropyRequest& request, AddEntropyResponse* response);
+    void GenerateKey(const GenerateKeyRequest& request, GenerateKeyResponse* response);
+    void GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
+                               GetKeyCharacteristicsResponse* response);
+    void ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response);
+    void ExportKey(const ExportKeyRequest& request, ExportKeyResponse* response);
+    void AttestKey(const AttestKeyRequest& request, AttestKeyResponse* response);
+    void DeleteKey(const DeleteKeyRequest& request, DeleteKeyResponse* response);
+    void DeleteAllKeys(const DeleteAllKeysRequest& request, DeleteAllKeysResponse* response);
+    void BeginOperation(const BeginOperationRequest& request, BeginOperationResponse* response);
+    void UpdateOperation(const UpdateOperationRequest& request, UpdateOperationResponse* response);
+    void FinishOperation(const FinishOperationRequest& request, FinishOperationResponse* response);
+    void AbortOperation(const AbortOperationRequest& request, AbortOperationResponse* response);
+
+    bool has_operation(keymaster_operation_handle_t op_handle) const;
+
+  private:
+    keymaster_error_t LoadKey(const keymaster_key_blob_t& key_blob,
+                              const AuthorizationSet& additional_params,
+                              AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced,
+                              const KeyFactory** factory, UniquePtr<Key>* key);
+
+    UniquePtr<KeymasterContext> context_;
+    UniquePtr<OperationTable> operation_table_;
+};
+
+}  // namespace keymaster
+
+#endif  //  SYSTEM_KEYMASTER_ANDROID_KEYMASTER_H_
diff --git a/keymaster/include/keymaster/android_keymaster_messages.h b/keymaster/include/keymaster/android_keymaster_messages.h
new file mode 100644
index 0000000..30d3fb7
--- /dev/null
+++ b/keymaster/include/keymaster/android_keymaster_messages.h
@@ -0,0 +1,627 @@
+/*
+ * 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_KEYMASTER_MESSAGES_H_
+#define SYSTEM_KEYMASTER_ANDROID_KEYMASTER_MESSAGES_H_
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
+
+namespace keymaster {
+
+// Commands
+enum AndroidKeymasterCommand {
+    GENERATE_KEY = 0,
+    BEGIN_OPERATION = 1,
+    UPDATE_OPERATION = 2,
+    FINISH_OPERATION = 3,
+    ABORT_OPERATION = 4,
+    IMPORT_KEY = 5,
+    EXPORT_KEY = 6,
+    GET_VERSION = 7,
+    ADD_RNG_ENTROPY = 8,
+    GET_SUPPORTED_ALGORITHMS = 9,
+    GET_SUPPORTED_BLOCK_MODES = 10,
+    GET_SUPPORTED_PADDING_MODES = 11,
+    GET_SUPPORTED_DIGESTS = 12,
+    GET_SUPPORTED_IMPORT_FORMATS = 13,
+    GET_SUPPORTED_EXPORT_FORMATS = 14,
+    GET_KEY_CHARACTERISTICS = 15,
+    ATTEST_KEY = 16,
+};
+
+/**
+ * Keymaster message versions are tied to keymaster versions.  We map the keymaster
+ * major.minor.subminor version to a sequential "message version".
+ *
+ * Rather than encoding a version number into each message we rely on the client -- who initiates
+ * all requests -- to check the version of the keymaster implementation with the GET_VERSION command
+ * and to send only requests that the implementation can understand.  This means that only the
+ * client side needs to manage version compatibility; the implementation can always expect/produce
+ * messages of its format.
+ *
+ * Because message version selection is purely a client-side issue, all messages default to using
+ * the latest version (MAX_MESSAGE_VERSION).  Client code must take care to check versions and pass
+ * correct version values to message constructors.  The AndroidKeymaster implementation always uses
+ * the default, latest.
+ *
+ * Note that this approach implies that GetVersionRequest and GetVersionResponse cannot be
+ * versioned.
+ */
+const int32_t MAX_MESSAGE_VERSION = 3;
+inline int32_t MessageVersion(uint8_t major_ver, uint8_t minor_ver, uint8_t /* subminor_ver */) {
+    int32_t message_version = -1;
+    switch (major_ver) {
+    case 0:
+        // For the moment we still support version 0, though in general the plan is not to support
+        // non-matching major versions.
+        message_version = 0;
+        break;
+    case 1:
+        switch (minor_ver) {
+        case 0:
+            message_version = 1;
+            break;
+        case 1:
+            message_version = 2;
+            break;
+        }
+        break;
+    case 2:
+        message_version = 3;
+        break;
+    };
+    return message_version;
+}
+
+struct KeymasterMessage : public Serializable {
+    explicit KeymasterMessage(int32_t ver) : message_version(ver) { assert(ver >= 0); }
+    uint32_t message_version;
+};
+
+/**
+ * All responses include an error value, and if the error is not KM_ERROR_OK, return no additional
+ * data.  This abstract class factors out the common serialization functionality for all of the
+ * responses, so we only have to implement it once.  Inheritance for reuse is generally not a great
+ * structure, but in this case it's the cleanest option.
+ */
+struct KeymasterResponse : public KeymasterMessage {
+    explicit KeymasterResponse(int32_t ver)
+        : KeymasterMessage(ver), error(KM_ERROR_UNKNOWN_ERROR) {}
+
+    size_t SerializedSize() const override;
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    virtual size_t NonErrorSerializedSize() const = 0;
+    virtual uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const = 0;
+    virtual bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) = 0;
+
+    keymaster_error_t error;
+};
+
+struct SupportedAlgorithmsRequest : public KeymasterMessage {
+    explicit SupportedAlgorithmsRequest(int32_t ver = MAX_MESSAGE_VERSION)
+        : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override { return 0; };
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* /* end */) const override { return buf; }
+    bool Deserialize(const uint8_t** /* buf_ptr */, const uint8_t* /* end */) override {
+        return true;
+    }
+};
+
+struct SupportedByAlgorithmRequest : public KeymasterMessage {
+    explicit SupportedByAlgorithmRequest(int32_t ver = MAX_MESSAGE_VERSION)
+        : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override { return sizeof(uint32_t); };
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+        return append_uint32_to_buf(buf, end, algorithm);
+    }
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        return copy_uint32_from_buf(buf_ptr, end, &algorithm);
+    }
+
+    keymaster_algorithm_t algorithm;
+};
+
+struct SupportedImportFormatsRequest : public SupportedByAlgorithmRequest {
+    explicit SupportedImportFormatsRequest(int32_t ver = MAX_MESSAGE_VERSION)
+        : SupportedByAlgorithmRequest(ver) {}
+};
+
+struct SupportedExportFormatsRequest : public SupportedByAlgorithmRequest {
+    explicit SupportedExportFormatsRequest(int32_t ver = MAX_MESSAGE_VERSION)
+        : SupportedByAlgorithmRequest(ver) {}
+};
+
+struct SupportedByAlgorithmAndPurposeRequest : public KeymasterMessage {
+    explicit SupportedByAlgorithmAndPurposeRequest(int32_t ver = MAX_MESSAGE_VERSION)
+        : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override { return sizeof(uint32_t) * 2; };
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+        buf = append_uint32_to_buf(buf, end, algorithm);
+        return append_uint32_to_buf(buf, end, purpose);
+    }
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        return copy_uint32_from_buf(buf_ptr, end, &algorithm) &&
+               copy_uint32_from_buf(buf_ptr, end, &purpose);
+    }
+
+    keymaster_algorithm_t algorithm;
+    keymaster_purpose_t purpose;
+};
+
+struct SupportedBlockModesRequest : public SupportedByAlgorithmAndPurposeRequest {
+    explicit SupportedBlockModesRequest(int32_t ver = MAX_MESSAGE_VERSION)
+        : SupportedByAlgorithmAndPurposeRequest(ver) {}
+};
+
+struct SupportedPaddingModesRequest : public SupportedByAlgorithmAndPurposeRequest {
+    explicit SupportedPaddingModesRequest(int32_t ver = MAX_MESSAGE_VERSION)
+        : SupportedByAlgorithmAndPurposeRequest(ver) {}
+};
+
+struct SupportedDigestsRequest : public SupportedByAlgorithmAndPurposeRequest {
+    explicit SupportedDigestsRequest(int32_t ver = MAX_MESSAGE_VERSION)
+        : SupportedByAlgorithmAndPurposeRequest(ver) {}
+};
+
+template <typename T> struct SupportedResponse : public KeymasterResponse {
+    explicit SupportedResponse(int32_t ver = MAX_MESSAGE_VERSION)
+        : KeymasterResponse(ver), results(nullptr), results_length(0) {}
+    ~SupportedResponse() { delete[] results; }
+
+    template <size_t N> void SetResults(const T (&arr)[N]) { SetResults(arr, N); }
+
+    void SetResults(const T* arr, size_t n) {
+        delete[] results;
+        results_length = 0;
+        results = dup_array(arr, n);
+        if (results == nullptr) {
+            error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        } else {
+            results_length = n;
+            error = KM_ERROR_OK;
+        }
+    }
+
+    size_t NonErrorSerializedSize() const override {
+        return sizeof(uint32_t) + results_length * sizeof(uint32_t);
+    }
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override {
+        return append_uint32_array_to_buf(buf, end, results, results_length);
+    }
+    bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        delete[] results;
+        results = nullptr;
+        UniquePtr<T[]> tmp;
+        if (!copy_uint32_array_from_buf(buf_ptr, end, &tmp, &results_length))
+            return false;
+        results = tmp.release();
+        return true;
+    }
+
+    T* results;
+    size_t results_length;
+};
+
+struct SupportedAlgorithmsResponse : public SupportedResponse<keymaster_algorithm_t> {
+    explicit SupportedAlgorithmsResponse(int32_t ver = MAX_MESSAGE_VERSION)
+        : SupportedResponse<keymaster_algorithm_t>(ver) {}
+};
+
+struct SupportedBlockModesResponse : public SupportedResponse<keymaster_block_mode_t> {
+    explicit SupportedBlockModesResponse(int32_t ver = MAX_MESSAGE_VERSION)
+        : SupportedResponse<keymaster_block_mode_t>(ver) {}
+};
+
+struct SupportedPaddingModesResponse : public SupportedResponse<keymaster_padding_t> {
+    explicit SupportedPaddingModesResponse(int32_t ver = MAX_MESSAGE_VERSION)
+        : SupportedResponse<keymaster_padding_t>(ver) {}
+};
+
+struct SupportedDigestsResponse : public SupportedResponse<keymaster_digest_t> {
+    explicit SupportedDigestsResponse(int32_t ver = MAX_MESSAGE_VERSION)
+        : SupportedResponse<keymaster_digest_t>(ver) {}
+};
+
+struct SupportedImportFormatsResponse : public SupportedResponse<keymaster_key_format_t> {
+    explicit SupportedImportFormatsResponse(int32_t ver = MAX_MESSAGE_VERSION)
+        : SupportedResponse<keymaster_key_format_t>(ver) {}
+};
+
+struct SupportedExportFormatsResponse : public SupportedResponse<keymaster_key_format_t> {
+    explicit SupportedExportFormatsResponse(int32_t ver = MAX_MESSAGE_VERSION)
+        : SupportedResponse<keymaster_key_format_t>(ver) {}
+};
+
+struct GenerateKeyRequest : public KeymasterMessage {
+    explicit GenerateKeyRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override { return key_description.SerializedSize(); }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+        return key_description.Serialize(buf, end);
+    }
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        return key_description.Deserialize(buf_ptr, end);
+    }
+
+    AuthorizationSet key_description;
+};
+
+struct GenerateKeyResponse : public KeymasterResponse {
+    explicit GenerateKeyResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {
+        key_blob.key_material = nullptr;
+        key_blob.key_material_size = 0;
+    }
+    ~GenerateKeyResponse();
+
+    size_t NonErrorSerializedSize() const override;
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override;
+    bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    keymaster_key_blob_t key_blob;
+    AuthorizationSet enforced;
+    AuthorizationSet unenforced;
+};
+
+struct GetKeyCharacteristicsRequest : public KeymasterMessage {
+    explicit GetKeyCharacteristicsRequest(int32_t ver = MAX_MESSAGE_VERSION)
+        : KeymasterMessage(ver) {
+        key_blob.key_material = nullptr;
+        key_blob.key_material_size = 0;
+    }
+    ~GetKeyCharacteristicsRequest();
+
+    void SetKeyMaterial(const void* key_material, size_t length);
+    void SetKeyMaterial(const keymaster_key_blob_t& blob) {
+        SetKeyMaterial(blob.key_material, blob.key_material_size);
+    }
+
+    size_t SerializedSize() const override;
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    keymaster_key_blob_t key_blob;
+    AuthorizationSet additional_params;
+};
+
+struct GetKeyCharacteristicsResponse : public KeymasterResponse {
+    explicit GetKeyCharacteristicsResponse(int32_t ver = MAX_MESSAGE_VERSION)
+        : KeymasterResponse(ver) {}
+    size_t NonErrorSerializedSize() const override;
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override;
+    bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    AuthorizationSet enforced;
+    AuthorizationSet unenforced;
+};
+
+struct BeginOperationRequest : public KeymasterMessage {
+    explicit BeginOperationRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {
+        key_blob.key_material = nullptr;
+        key_blob.key_material_size = 0;
+    }
+    ~BeginOperationRequest() { delete[] key_blob.key_material; }
+
+    void SetKeyMaterial(const void* key_material, size_t length);
+    void SetKeyMaterial(const keymaster_key_blob_t& blob) {
+        SetKeyMaterial(blob.key_material, blob.key_material_size);
+    }
+
+    size_t SerializedSize() const;
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    keymaster_purpose_t purpose;
+    keymaster_key_blob_t key_blob;
+    AuthorizationSet additional_params;
+};
+
+struct BeginOperationResponse : public KeymasterResponse {
+    explicit BeginOperationResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {}
+
+    size_t NonErrorSerializedSize() const override;
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override;
+    bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    keymaster_operation_handle_t op_handle;
+    AuthorizationSet output_params;
+};
+
+struct UpdateOperationRequest : public KeymasterMessage {
+    explicit UpdateOperationRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override;
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    keymaster_operation_handle_t op_handle;
+    Buffer input;
+    AuthorizationSet additional_params;
+};
+
+struct UpdateOperationResponse : public KeymasterResponse {
+    explicit UpdateOperationResponse(int32_t ver = MAX_MESSAGE_VERSION)
+        : KeymasterResponse(ver), input_consumed(0) {}
+
+    size_t NonErrorSerializedSize() const override;
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override;
+    bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    Buffer output;
+    size_t input_consumed;
+    AuthorizationSet output_params;
+};
+
+struct FinishOperationRequest : public KeymasterMessage {
+    explicit FinishOperationRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override;
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    keymaster_operation_handle_t op_handle;
+    Buffer input;
+    Buffer signature;
+    AuthorizationSet additional_params;
+};
+
+struct FinishOperationResponse : public KeymasterResponse {
+    explicit FinishOperationResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {}
+
+    size_t NonErrorSerializedSize() const override;
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override;
+    bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    Buffer output;
+    AuthorizationSet output_params;
+};
+
+struct AbortOperationRequest : public KeymasterMessage {
+    explicit AbortOperationRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override { return sizeof(uint64_t); }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+        return append_uint64_to_buf(buf, end, op_handle);
+    }
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        return copy_uint64_from_buf(buf_ptr, end, &op_handle);
+    }
+
+    keymaster_operation_handle_t op_handle;
+};
+
+struct AbortOperationResponse : public KeymasterResponse {
+    explicit AbortOperationResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {}
+
+    size_t NonErrorSerializedSize() const override { return 0; }
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t*) const override { return buf; }
+    bool NonErrorDeserialize(const uint8_t**, const uint8_t*) override { return true; }
+};
+
+struct AddEntropyRequest : public KeymasterMessage {
+    explicit AddEntropyRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override;
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    Buffer random_data;
+};
+
+struct AddEntropyResponse : public KeymasterResponse {
+    explicit AddEntropyResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {}
+
+    size_t NonErrorSerializedSize() const override { return 0; }
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* /* end */) const override {
+        return buf;
+    }
+    bool NonErrorDeserialize(const uint8_t** /* buf_ptr */, const uint8_t* /* end */) override {
+        return true;
+    }
+};
+
+struct ImportKeyRequest : public KeymasterMessage {
+    explicit ImportKeyRequest(int32_t ver = MAX_MESSAGE_VERSION)
+        : KeymasterMessage(ver), key_data(nullptr) {}
+    ~ImportKeyRequest() { delete[] key_data; }
+
+    void SetKeyMaterial(const void* key_material, size_t length);
+    void SetKeyMaterial(const keymaster_key_blob_t& blob) {
+        SetKeyMaterial(blob.key_material, blob.key_material_size);
+    }
+
+    size_t SerializedSize() const override;
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    AuthorizationSet key_description;
+    keymaster_key_format_t key_format;
+    uint8_t* key_data;
+    size_t key_data_length;
+};
+
+struct ImportKeyResponse : public KeymasterResponse {
+    explicit ImportKeyResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {
+        key_blob.key_material = nullptr;
+        key_blob.key_material_size = 0;
+    }
+    ~ImportKeyResponse() { delete[] key_blob.key_material; }
+
+    void SetKeyMaterial(const void* key_material, size_t length);
+    void SetKeyMaterial(const keymaster_key_blob_t& blob) {
+        SetKeyMaterial(blob.key_material, blob.key_material_size);
+    }
+
+    size_t NonErrorSerializedSize() const override;
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override;
+    bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    keymaster_key_blob_t key_blob;
+    AuthorizationSet enforced;
+    AuthorizationSet unenforced;
+};
+
+struct ExportKeyRequest : public KeymasterMessage {
+    explicit ExportKeyRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {
+        key_blob.key_material = nullptr;
+        key_blob.key_material_size = 0;
+    }
+    ~ExportKeyRequest() { delete[] key_blob.key_material; }
+
+    void SetKeyMaterial(const void* key_material, size_t length);
+    void SetKeyMaterial(const keymaster_key_blob_t& blob) {
+        SetKeyMaterial(blob.key_material, blob.key_material_size);
+    }
+
+    size_t SerializedSize() const override;
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    AuthorizationSet additional_params;
+    keymaster_key_format_t key_format;
+    keymaster_key_blob_t key_blob;
+};
+
+struct ExportKeyResponse : public KeymasterResponse {
+    explicit ExportKeyResponse(int32_t ver = MAX_MESSAGE_VERSION)
+        : KeymasterResponse(ver), key_data(nullptr) {}
+    ~ExportKeyResponse() { delete[] key_data; }
+
+    void SetKeyMaterial(const void* key_material, size_t length);
+    void SetKeyMaterial(const keymaster_key_blob_t& blob) {
+        SetKeyMaterial(blob.key_material, blob.key_material_size);
+    }
+
+    size_t NonErrorSerializedSize() const override;
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override;
+    bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    uint8_t* key_data;
+    size_t key_data_length;
+};
+
+struct DeleteKeyRequest : public KeymasterMessage {
+    explicit DeleteKeyRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {
+        key_blob.key_material = nullptr;
+        key_blob.key_material_size = 0;
+    }
+    ~DeleteKeyRequest() { delete[] key_blob.key_material; }
+
+    void SetKeyMaterial(const void* key_material, size_t length);
+    void SetKeyMaterial(const keymaster_key_blob_t& blob) {
+        SetKeyMaterial(blob.key_material, blob.key_material_size);
+    }
+
+    size_t SerializedSize() const override;
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    keymaster_key_blob_t key_blob;
+};
+
+struct DeleteKeyResponse : public KeymasterResponse {
+    explicit DeleteKeyResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {}
+
+    size_t NonErrorSerializedSize() const override { return 0; }
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t*) const override { return buf; }
+    bool NonErrorDeserialize(const uint8_t**, const uint8_t*) override { return true; }
+};
+
+struct DeleteAllKeysRequest : public KeymasterMessage {
+    explicit DeleteAllKeysRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override { return 0; }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t*) const override { return buf; }
+    bool Deserialize(const uint8_t**, const uint8_t*) override { return true; };
+};
+
+struct DeleteAllKeysResponse : public KeymasterResponse {
+    explicit DeleteAllKeysResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {}
+
+    size_t NonErrorSerializedSize() const override { return 0; }
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t*) const override { return buf; }
+    bool NonErrorDeserialize(const uint8_t**, const uint8_t*) override { return true; }
+};
+
+struct GetVersionRequest : public KeymasterMessage {
+    GetVersionRequest() : KeymasterMessage(0 /* not versionable */) {}
+
+    size_t SerializedSize() const override { return 0; }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t*) const override { return buf; }
+    bool Deserialize(const uint8_t**, const uint8_t*) override { return true; };
+};
+
+struct GetVersionResponse : public KeymasterResponse {
+    GetVersionResponse()
+        : KeymasterResponse(0 /* not versionable */), major_ver(0), minor_ver(0), subminor_ver(0) {}
+
+    size_t NonErrorSerializedSize() const override;
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override;
+    bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    uint8_t major_ver;
+    uint8_t minor_ver;
+    uint8_t subminor_ver;
+};
+
+struct AttestKeyRequest : public KeymasterMessage {
+    explicit AttestKeyRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {
+        key_blob.key_material = nullptr;
+        key_blob.key_material_size = 0;
+    }
+    ~AttestKeyRequest();
+
+    void SetKeyMaterial(const void* key_material, size_t length);
+    void SetKeyMaterial(const keymaster_key_blob_t& blob) {
+        SetKeyMaterial(blob.key_material, blob.key_material_size);
+    }
+
+    size_t SerializedSize() const override;
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    keymaster_key_blob_t key_blob;
+    AuthorizationSet attest_params;
+};
+
+struct AttestKeyResponse : public KeymasterResponse {
+    explicit AttestKeyResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {
+        certificate_chain.entry_count = 0;
+        certificate_chain.entries = nullptr;
+    }
+    ~AttestKeyResponse();
+
+    bool AllocateChain(size_t entry_count);
+
+    size_t NonErrorSerializedSize() const override;
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override;
+    bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    keymaster_cert_chain_t certificate_chain;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_MESSAGES_H_
diff --git a/keymaster/include/keymaster/android_keymaster_utils.h b/keymaster/include/keymaster/android_keymaster_utils.h
new file mode 100644
index 0000000..c190e04
--- /dev/null
+++ b/keymaster/include/keymaster/android_keymaster_utils.h
@@ -0,0 +1,330 @@
+/*
+ * 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_KEYMASTER_UTILS_H_
+#define SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_
+
+#include <stdint.h>
+#include <string.h>
+#include <time.h>  // for time_t.
+
+#include <UniquePtr.h>
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/serializable.h>
+
+namespace keymaster {
+
+/**
+ * Convert the specified time value into "Java time", which is a signed 64-bit integer representing
+ * elapsed milliseconds since Jan 1, 1970.
+ */
+inline int64_t java_time(time_t time) {
+    // The exact meaning of a time_t value is implementation-dependent.  If this code is ported to a
+    // platform that doesn't define it as "seconds since Jan 1, 1970 UTC", this function will have
+    // to be revised.
+    return time * 1000;
+}
+
+/*
+ * Array Manipulation functions.  This set of templated inline functions provides some nice tools
+ * for operating on c-style arrays.  C-style arrays actually do have a defined size associated with
+ * them, as long as they are not allowed to decay to a pointer.  These template methods exploit this
+ * to allow size-based array operations without explicitly specifying the size.  If passed a pointer
+ * rather than an array, they'll fail to compile.
+ */
+
+/**
+ * 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]) {
+    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]) {
+    return N;
+}
+
+/**
+ * Duplicate the array \p a.  The memory for the new array is allocated and the caller takes
+ * responsibility.
+ */
+template <typename T> inline T* dup_array(const T* a, size_t n) {
+    T* dup = new (std::nothrow) T[n];
+    if (dup)
+        for (size_t i = 0; i < n; ++i)
+            dup[i] = a[i];
+    return dup;
+}
+
+/**
+ * Duplicate the array \p a.  The memory for the new array is allocated and the caller takes
+ * 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]) {
+    return dup_array(a, N);
+}
+
+/**
+ * Duplicate the buffer \p buf.  The memory for the new buffer is allocated and the caller takes
+ * responsibility.
+ */
+uint8_t* dup_buffer(const void* buf, size_t size);
+
+/**
+ * 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) {
+    for (size_t i = 0; i < N; ++i)
+        dest[i] = arr[i];
+}
+
+/**
+ * Search array \p a for value \p val, returning true if found.  Note that this function is
+ * 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) {
+    for (size_t i = 0; i < N; ++i) {
+        if (a[i] == val) {
+            return true;
+        }
+    }
+    return false;
+}
+
+/**
+ * Variant of memset() that uses GCC-specific pragmas to disable optimizations, so effect is not
+ * optimized away.  This is important because we often need to wipe blocks of sensitive data from
+ * memory.  As an additional convenience, this implementation avoids writing to NULL pointers.
+ */
+#ifdef __clang__
+#define OPTNONE __attribute__((optnone))
+#else  // not __clang__
+#define OPTNONE __attribute__((optimize("O0")))
+#endif  // not __clang__
+inline OPTNONE void* memset_s(void* s, int c, size_t n) {
+    if (!s)
+        return s;
+    return memset(s, c, n);
+}
+#undef OPTNONE
+
+/**
+ * Variant of memcmp that has the same runtime regardless of whether the data matches (i.e. doesn't
+ * short-circuit).  Not an exact equivalent to memcmp because it doesn't return <0 if p1 < p2, just
+ * 0 for match and non-zero for non-match.
+ */
+int memcmp_s(const void* p1, const void* p2, size_t length);
+
+/**
+ * Eraser clears buffers.  Construct it with a buffer or object and the destructor will ensure that
+ * it is zeroed.
+ */
+class Eraser {
+  public:
+    /* Not implemented.  If this gets used, we want a link error. */
+    template <typename T> explicit Eraser(T* t);
+
+    template <typename T>
+    explicit Eraser(T& t) : buf_(reinterpret_cast<uint8_t*>(&t)), size_(sizeof(t)) {}
+
+    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_); }
+
+  private:
+    Eraser(const Eraser&);
+    void operator=(const Eraser&);
+
+    uint8_t* buf_;
+    size_t size_;
+};
+
+/**
+ * ArrayWrapper is a trivial wrapper around a C-style array that provides begin() and end()
+ * methods. This is primarily to facilitate range-based iteration on arrays.  It does not copy, nor
+ * does it take ownership; it just holds pointers.
+ */
+template <typename T> class ArrayWrapper {
+  public:
+    ArrayWrapper(T* array, size_t size) : begin_(array), end_(array + size) {}
+
+    T* begin() { return begin_; }
+    T* end() { return end_; }
+
+  private:
+    T* begin_;
+    T* end_;
+};
+template <typename T> ArrayWrapper<T> array_range(T* begin, size_t length) {
+    return ArrayWrapper<T>(begin, length);
+}
+
+/**
+ * Convert any unsigned integer from network to host order.  We implement this here rather than
+ * using the functions from arpa/inet.h because the TEE doesn't have inet.h.  This isn't the most
+ * efficient implementation, but the compiler should unroll the loop and tighten it up.
+ */
+template <typename T> T ntoh(T t) {
+    const uint8_t* byte_ptr = reinterpret_cast<const uint8_t*>(&t);
+    T retval = 0;
+    for (size_t i = 0; i < sizeof(t); ++i) {
+        retval <<= 8;
+        retval |= byte_ptr[i];
+    }
+    return retval;
+}
+
+/**
+ * Convert any unsigned integer from host to network order.  We implement this here rather than
+ * using the functions from arpa/inet.h because the TEE doesn't have inet.h.  This isn't the most
+ * efficient implementation, but the compiler should unroll the loop and tighten it up.
+ */
+template <typename T> T hton(T t) {
+    T retval;
+    uint8_t* byte_ptr = reinterpret_cast<uint8_t*>(&retval);
+    for (size_t i = sizeof(t); i > 0; --i) {
+        byte_ptr[i - 1] = t & 0xFF;
+        t >>= 8;
+    }
+    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_size = 0;
+        key_material = dup_buffer(data, size);
+        if (key_material)
+            key_material_size = size;
+    }
+
+    explicit KeymasterKeyBlob(size_t size) {
+        key_material_size = 0;
+        key_material = new (std::nothrow) uint8_t[size];
+        if (key_material)
+            key_material_size = size;
+    }
+
+    explicit KeymasterKeyBlob(const keymaster_key_blob_t& blob) {
+        key_material_size = 0;
+        key_material = dup_buffer(blob.key_material, blob.key_material_size);
+        if (key_material)
+            key_material_size = blob.key_material_size;
+    }
+
+    KeymasterKeyBlob(const KeymasterKeyBlob& blob) {
+        key_material_size = 0;
+        key_material = dup_buffer(blob.key_material, blob.key_material_size);
+        if (key_material)
+            key_material_size = blob.key_material_size;
+    }
+
+    void operator=(const KeymasterKeyBlob& blob) {
+        Clear();
+        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 (std::nothrow) uint8_t[new_size];
+        if (key_material)
+            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;
+    }
+};
+
+struct Characteristics_Delete {
+    void operator()(keymaster_key_characteristics_t* p) {
+        keymaster_free_characteristics(p);
+        free(p);
+    }
+};
+
+struct Malloc_Delete {
+    void operator()(void* p) { free(p); }
+};
+
+struct CertificateChainDelete {
+    void operator()(keymaster_cert_chain_t* p) {
+        if (!p)
+            return;
+        for (size_t i = 0; i < p->entry_count; ++i)
+            delete[] p->entries[i].data;
+        delete[] p->entries;
+        delete p;
+    }
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_
diff --git a/keymaster/include/keymaster/asymmetric_key_factory.h b/keymaster/include/keymaster/asymmetric_key_factory.h
new file mode 100644
index 0000000..afcfc1c
--- /dev/null
+++ b/keymaster/include/keymaster/asymmetric_key_factory.h
@@ -0,0 +1,51 @@
+/*
+ * 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_ASYMMETRIC_KEY_FACTORY_H_
+#define SYSTEM_KEYMASTER_ASYMMETRIC_KEY_FACTORY_H_
+
+#include <keymaster/key_factory.h>
+
+namespace keymaster {
+
+/**
+ * Abstract base for KeyFactories that handle asymmetric keys.
+ */
+class AsymmetricKey;
+class AsymmetricKeyFactory : public KeyFactory {
+  public:
+    explicit AsymmetricKeyFactory(const KeymasterContext* context) : KeyFactory(context) {}
+
+    keymaster_error_t LoadKey(const KeymasterKeyBlob& key_material,
+                              const AuthorizationSet& additional_params,
+                              const AuthorizationSet& hw_enforced,
+                              const AuthorizationSet& sw_enforced,
+                              UniquePtr<Key>* key) const override;
+
+    virtual keymaster_error_t CreateEmptyKey(const AuthorizationSet& hw_enforced,
+                                             const AuthorizationSet& sw_enforced,
+                                             UniquePtr<AsymmetricKey>* key) const = 0;
+
+    virtual keymaster_algorithm_t keymaster_key_type() const = 0;
+    virtual int evp_key_type() const = 0;
+
+    virtual const keymaster_key_format_t* SupportedImportFormats(size_t* format_count) const;
+    virtual const keymaster_key_format_t* SupportedExportFormats(size_t* format_count) const;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_ASYMMETRIC_KEY_FACTORY_H_
diff --git a/keymaster/include/keymaster/authorization_set.h b/keymaster/include/keymaster/authorization_set.h
new file mode 100644
index 0000000..74daa8d
--- /dev/null
+++ b/keymaster/include/keymaster/authorization_set.h
@@ -0,0 +1,570 @@
+/*
+ * 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_AUTHORIZATION_SET_H_
+#define SYSTEM_KEYMASTER_AUTHORIZATION_SET_H_
+
+#include <UniquePtr.h>
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/keymaster_tags.h>
+#include <keymaster/serializable.h>
+
+namespace keymaster {
+
+class AuthorizationSetBuilder;
+
+/**
+ * An extension of the keymaster_key_param_set_t struct, which provides serialization memory
+ * management and methods for easy manipulation and construction.
+ */
+class AuthorizationSet : public Serializable, public keymaster_key_param_set_t {
+  public:
+    /**
+     * Construct an empty, dynamically-allocated, growable AuthorizationSet.  Does not actually
+     * allocate any storage until elements are added, so there is no cost to creating an
+     * AuthorizationSet with this constructor and then reinitializing it to point at pre-allocated
+     * buffers, with \p Reinitialize.
+     */
+    AuthorizationSet()
+        : elems_capacity_(0), indirect_data_(NULL), indirect_data_size_(0),
+          indirect_data_capacity_(0), error_(OK) {
+        elems_ = nullptr;
+        elems_size_ = 0;
+    }
+
+    /**
+     * Construct an AuthorizationSet from the provided array.  The AuthorizationSet copies the data
+     * from the provided array (and the data referenced by its embedded pointers, if any) into
+     * dynamically-allocated storage.  If allocation of the needed storage fails, \p is_valid() will
+     * return ALLOCATION_FAILURE. It is the responsibility of the caller to check before using the
+     * set, if allocations might fail.
+     */
+    AuthorizationSet(const keymaster_key_param_t* elems, size_t count) : indirect_data_(nullptr) {
+        elems_ = nullptr;
+        Reinitialize(elems, count);
+    }
+
+    explicit AuthorizationSet(const keymaster_key_param_set_t& set) : indirect_data_(nullptr) {
+        elems_ = nullptr;
+        Reinitialize(set.params, set.length);
+    }
+
+    explicit AuthorizationSet(const uint8_t* serialized_set, size_t serialized_size)
+        : indirect_data_(nullptr) {
+        elems_ = nullptr;
+        Deserialize(&serialized_set, serialized_set + serialized_size);
+    }
+
+    /**
+     * Construct an AuthorizationSet from the provided builder.  This extracts the data from the
+     * builder, rather than copying it, so after this call the builder is empty.
+     */
+    explicit AuthorizationSet(/* NOT const */ AuthorizationSetBuilder& builder);
+
+    // Copy constructor.
+    AuthorizationSet(const AuthorizationSet& set) : Serializable(), indirect_data_(nullptr) {
+        elems_ = nullptr;
+        Reinitialize(set.elems_, set.elems_size_);
+    }
+
+    /**
+     * Clear existing authorization set data
+     */
+    void Clear();
+
+    /**
+     * Reinitialize an AuthorizationSet as a dynamically-allocated, growable copy of the data in the
+     * provided array (and the data referenced by its embedded pointers, if any).  If the allocation
+     * of the needed storage fails this method will return false and \p is_valid() will return
+     * ALLOCATION_FAILURE.
+     */
+    bool Reinitialize(const keymaster_key_param_t* elems, size_t count);
+
+    bool Reinitialize(const AuthorizationSet& set) {
+        return Reinitialize(set.elems_, set.elems_size_);
+    }
+
+    bool Reinitialize(const keymaster_key_param_set_t& set) {
+        return Reinitialize(set.params, set.length);
+    }
+
+    ~AuthorizationSet();
+
+    enum Error {
+        OK,
+        ALLOCATION_FAILURE,
+        MALFORMED_DATA,
+    };
+
+    Error is_valid() const { return error_; }
+
+    /**
+     * Returns the size of the set.
+     */
+    size_t size() const { return elems_size_; }
+
+    /**
+     * Returns true if the set is empty.
+     */
+    bool empty() const { return size() == 0; }
+
+    /**
+     * Returns the total size of all indirect data referenced by set elements.
+     */
+    size_t indirect_size() const { return indirect_data_size_; }
+
+    /**
+     * Returns the data in the set, directly. Be careful with this.
+     */
+    const keymaster_key_param_t* data() const { return elems_; }
+
+    /**
+     * Sorts the set
+     */
+    void Sort();
+
+    /**
+     * Sorts the set and removes duplicates (inadvertently duplicating tags is easy to do with the
+     * AuthorizationSetBuilder).
+     */
+    void Deduplicate();
+
+    /**
+     * Returns the data in a keymaster_key_param_set_t, suitable for returning to C code.  For C
+     * compatibility, the contents are malloced, not new'ed, and so must be freed with free(), or
+     * better yet with keymaster_free_param_set, not delete.  The caller takes ownership.
+     */
+    void CopyToParamSet(keymaster_key_param_set_t* set) const;
+
+    /**
+     * Returns the offset of the next entry that matches \p tag, starting from the element after \p
+     * begin.  If not found, returns -1.
+     */
+    int find(keymaster_tag_t tag, int begin = -1) const;
+
+    /**
+     * Removes the entry at the specified index. Returns true if successful, false if the index was
+     * out of bounds.
+     */
+    bool erase(size_t index);
+
+    /**
+     * Returns iterator (pointer) to beginning of elems array, to enable STL-style iteration
+     */
+    const keymaster_key_param_t* begin() const { return elems_; }
+
+    /**
+     * Returns iterator (pointer) one past end of elems array, to enable STL-style iteration
+     */
+    const keymaster_key_param_t* end() const { return elems_ + elems_size_; }
+
+    /**
+     * Returns the nth element of the set.
+     */
+    keymaster_key_param_t& operator[](int n);
+
+    /**
+     * Returns the nth element of the set.
+     */
+    keymaster_key_param_t operator[](int n) const;
+
+    /**
+     * Returns the number of \p tag entries.
+     */
+    size_t GetTagCount(keymaster_tag_t tag) const;
+
+    /**
+     * Returns true if the set contains the specified tag and value.
+     */
+    template <keymaster_tag_t Tag, typename T>
+    bool Contains(TypedEnumTag<KM_ENUM_REP, Tag, T> tag, T val) const {
+        return ContainsEnumValue(tag, val);
+    }
+
+    /**
+     * Returns true if the set contains the specified tag and value.
+     */
+    template <keymaster_tag_t Tag, typename T>
+    bool Contains(TypedEnumTag<KM_ENUM, Tag, T> tag, T val) const {
+        return ContainsEnumValue(tag, val);
+    }
+
+    /**
+     * If the specified integer-typed \p tag exists, places its value in \p val and returns true.
+     * If \p tag is not present, leaves \p val unmodified and returns false.
+     */
+    template <keymaster_tag_t T>
+    inline bool GetTagValue(TypedTag<KM_UINT, T> tag, uint32_t* val) const {
+        return GetTagValueInt(tag, val);
+    }
+
+    /**
+     * If the specified instance of the specified integer-typed \p tag exists, places its value
+     * in \p val and returns true.  If \p tag is not present, leaves \p val unmodified and returns
+     * false.
+     */
+    template <keymaster_tag_t Tag>
+    bool GetTagValue(TypedTag<KM_UINT_REP, Tag> tag, size_t instance, uint32_t* val) const {
+        return GetTagValueIntRep(tag, instance, val);
+    }
+
+    /**
+     * If the specified long-typed \p tag exists, places its value in \p val and returns true.
+     * If \p tag is not present, leaves \p val unmodified and returns false.
+     */
+    template <keymaster_tag_t T>
+    inline bool GetTagValue(TypedTag<KM_ULONG, T> tag, uint64_t* val) const {
+        return GetTagValueLong(tag, val);
+    }
+
+    /**
+     * If the specified instance of the specified integer-typed \p tag exists, places its value
+     * in \p val and returns true.  If \p tag is not present, leaves \p val unmodified and returns
+     * false.
+     */
+    template <keymaster_tag_t Tag>
+    bool GetTagValue(TypedTag<KM_ULONG_REP, Tag> tag, size_t instance, uint64_t* val) const {
+        return GetTagValueLongRep(tag, instance, val);
+    }
+
+    /**
+     * If the specified enumeration-typed \p tag exists, places its value in \p val and returns
+     * true.  If \p tag is not present, leaves \p val unmodified and returns false.
+     */
+    template <keymaster_tag_t Tag, typename T>
+    bool GetTagValue(TypedEnumTag<KM_ENUM, Tag, T> tag, T* val) const {
+        return GetTagValueEnum(tag, reinterpret_cast<uint32_t*>(val));
+    }
+
+    /**
+     * If the specified instance of the specified enumeration-typed \p tag exists, places its value
+     * in \p val and returns true.  If \p tag is not present, leaves \p val unmodified and returns
+     * false.
+     */
+    template <keymaster_tag_t Tag, typename T>
+    bool GetTagValue(TypedEnumTag<KM_ENUM_REP, Tag, T> tag, size_t instance, T* val) const {
+        return GetTagValueEnumRep(tag, instance, reinterpret_cast<uint32_t*>(val));
+    }
+
+    /**
+     * If exactly one instance of the specified enumeration-typed \p tag exists, places its value in
+     * \p val and returns true.  If \p tag is not present or if multiple copies are present, leaves
+     * \p val unmodified and returns false.
+     */
+    template <keymaster_tag_t Tag, typename T>
+    bool GetTagValue(TypedEnumTag<KM_ENUM_REP, Tag, T> tag, T* val) const {
+        if (GetTagCount(tag) != 1)
+            return false;
+        return GetTagValueEnumRep(tag, 0, reinterpret_cast<uint32_t*>(val));
+    }
+
+    /**
+     * If the specified date-typed \p tag exists, places its value in \p val and returns
+     * true.  If \p tag is not present, leaves \p val unmodified and returns false.
+     */
+    template <keymaster_tag_t Tag>
+    bool GetTagValue(TypedTag<KM_UINT_REP, Tag> tag, size_t instance,
+                     typename TypedTag<KM_UINT_REP, Tag>::value_type* val) const {
+        return GetTagValueIntRep(tag, instance, val);
+    }
+
+    /**
+     * If the specified bytes-typed \p tag exists, places its value in \p val and returns
+     * true.  If \p tag is not present, leaves \p val unmodified and returns false.
+     */
+    template <keymaster_tag_t Tag>
+    bool GetTagValue(TypedTag<KM_BYTES, Tag> tag, keymaster_blob_t* val) const {
+        return GetTagValueBlob(tag, val);
+    }
+
+    /**
+     * If the specified bignum-typed \p tag exists, places its value in \p val and returns
+     * true.  If \p tag is not present, leaves \p val unmodified and returns false.
+     */
+    template <keymaster_tag_t Tag>
+    bool GetTagValue(TypedTag<KM_BIGNUM, Tag> tag, keymaster_blob_t* val) const {
+        return GetTagValueBlob(tag, val);
+    }
+
+    /**
+     * Returns true if the specified tag is present, and therefore has the value 'true'.
+     */
+    template <keymaster_tag_t Tag> bool GetTagValue(TypedTag<KM_BOOL, Tag> tag) const {
+        return GetTagValueBool(tag);
+    }
+
+    /**
+     * If the specified \p tag exists, places its value in \p val and returns true.  If \p tag is
+     * not present, leaves \p val unmodified and returns false.
+     */
+    template <keymaster_tag_t Tag, keymaster_tag_type_t Type>
+    bool GetTagValue(TypedTag<Type, Tag> tag, typename TagValueType<Type>::value_type* val) const {
+        return GetTagValueLong(tag, val);
+    }
+
+    bool push_back(keymaster_key_param_t elem);
+
+    /**
+     * Grow the elements array to ensure it can contain \p count entries.  Preserves any existing
+     * entries.
+     */
+    bool reserve_elems(size_t count);
+
+    /**
+     * Grow the indirect data array to ensure it can contain \p length bytes.  Preserves any
+     * existing indirect data.
+     */
+    bool reserve_indirect(size_t length);
+
+    bool push_back(const keymaster_key_param_set_t& set);
+
+    /**
+     * Append the tag and enumerated value to the set.
+     */
+    template <keymaster_tag_t Tag, keymaster_tag_type_t Type, typename KeymasterEnum>
+    bool push_back(TypedEnumTag<Type, Tag, KeymasterEnum> tag, KeymasterEnum val) {
+        return push_back(Authorization(tag, val));
+    }
+
+    /**
+     * Append the boolean tag (value "true") to the set.
+     */
+    template <keymaster_tag_t Tag> bool push_back(TypedTag<KM_BOOL, Tag> tag) {
+        return push_back(Authorization(tag));
+    }
+
+    /**
+     * Append the tag and byte array to the set.  Copies the array into internal storage; does not
+     * take ownership of the passed-in array.
+     */
+    template <keymaster_tag_t Tag>
+    bool push_back(TypedTag<KM_BYTES, Tag> tag, const void* bytes, size_t bytes_len) {
+        return push_back(keymaster_param_blob(tag, static_cast<const uint8_t*>(bytes), bytes_len));
+    }
+
+    /**
+     * Append the tag and blob to the set.  Copies the blob contents into internal storage; does not
+     * take ownership of the blob's data.
+     */
+    template <keymaster_tag_t Tag>
+    bool push_back(TypedTag<KM_BYTES, Tag> tag, const keymaster_blob_t& blob) {
+        return push_back(tag, blob.data, blob.data_length);
+    }
+
+    /**
+     * Append the tag and bignum array to the set.  Copies the array into internal storage; does not
+     * take ownership of the passed-in array.
+     */
+    template <keymaster_tag_t Tag>
+    bool push_back(TypedTag<KM_BIGNUM, Tag> tag, const void* bytes, size_t bytes_len) {
+        return push_back(keymaster_param_blob(tag, static_cast<const uint8_t*>(bytes), bytes_len));
+    }
+
+    template <keymaster_tag_t Tag, keymaster_tag_type_t Type>
+    bool push_back(TypedTag<Type, Tag> tag, typename TypedTag<Type, Tag>::value_type val) {
+        return push_back(Authorization(tag, val));
+    }
+
+    template <keymaster_tag_t Tag, keymaster_tag_type_t Type>
+    bool push_back(TypedTag<Type, Tag> tag, const void* bytes, size_t bytes_len) {
+        return push_back(Authorization(tag, bytes, bytes_len));
+    }
+
+    /* Virtual methods from Serializable */
+    size_t SerializedSize() const;
+    uint8_t* Serialize(uint8_t* serialized_set, const uint8_t* end) const;
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end);
+
+    size_t SerializedSizeOfElements() const;
+
+  private:
+    // Disallow assignment
+    void operator=(const AuthorizationSet&);
+
+    void FreeData();
+    void set_invalid(Error err);
+
+    static size_t ComputeIndirectDataSize(const keymaster_key_param_t* elems, size_t count);
+    void CopyIndirectData();
+    bool CheckIndirectData();
+
+    bool DeserializeIndirectData(const uint8_t** buf_ptr, const uint8_t* end);
+    bool DeserializeElementsData(const uint8_t** buf_ptr, const uint8_t* end);
+
+    bool GetTagValueEnum(keymaster_tag_t tag, uint32_t* val) const;
+    bool GetTagValueEnumRep(keymaster_tag_t tag, size_t instance, uint32_t* val) const;
+    bool GetTagValueInt(keymaster_tag_t tag, uint32_t* val) const;
+    bool GetTagValueIntRep(keymaster_tag_t tag, size_t instance, uint32_t* val) const;
+    bool GetTagValueLong(keymaster_tag_t tag, uint64_t* val) const;
+    bool GetTagValueLongRep(keymaster_tag_t tag, size_t instance, uint64_t* val) const;
+    bool GetTagValueDate(keymaster_tag_t tag, uint64_t* val) const;
+    bool GetTagValueBlob(keymaster_tag_t tag, keymaster_blob_t* val) const;
+    bool GetTagValueBool(keymaster_tag_t tag) const;
+
+    bool ContainsEnumValue(keymaster_tag_t tag, uint32_t val) const;
+
+    // Define elems_ and elems_size_ as aliases to params and length, respectivley.  This is to
+    // avoid using the variables without the trailing underscore in the implementation.
+    keymaster_key_param_t*& elems_ = keymaster_key_param_set_t::params;
+    size_t& elems_size_ = keymaster_key_param_set_t::length;
+
+    size_t elems_capacity_;
+    uint8_t* indirect_data_;
+    size_t indirect_data_size_;
+    size_t indirect_data_capacity_;
+    Error error_;
+};
+
+class AuthorizationSetBuilder {
+  public:
+    template <typename TagType, typename ValueType>
+    AuthorizationSetBuilder& Authorization(TagType tag, ValueType value) {
+        set.push_back(tag, value);
+        return *this;
+    }
+
+    template <keymaster_tag_t Tag>
+    AuthorizationSetBuilder& Authorization(TypedTag<KM_BOOL, Tag> tag) {
+        set.push_back(tag);
+        return *this;
+    }
+
+    template <keymaster_tag_t Tag>
+    AuthorizationSetBuilder& Authorization(TypedTag<KM_INVALID, Tag> tag) {
+        keymaster_key_param_t param;
+        param.tag = tag;
+        set.push_back(param);
+        return *this;
+    }
+
+    template <keymaster_tag_t Tag>
+    AuthorizationSetBuilder& Authorization(TypedTag<KM_BYTES, Tag> tag, const uint8_t* data,
+                                           size_t data_length) {
+        set.push_back(tag, data, data_length);
+        return *this;
+    }
+
+    template <keymaster_tag_t Tag>
+    AuthorizationSetBuilder& Authorization(TypedTag<KM_BYTES, Tag> tag, const char* data,
+                                           size_t data_length) {
+        return Authorization(tag, reinterpret_cast<const uint8_t*>(data), data_length);
+    }
+
+    AuthorizationSetBuilder& RsaKey(uint32_t key_size, uint64_t public_exponent);
+    AuthorizationSetBuilder& EcdsaKey(uint32_t key_size);
+    AuthorizationSetBuilder& AesKey(uint32_t key_size);
+    AuthorizationSetBuilder& HmacKey(uint32_t key_size);
+
+    AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent);
+    AuthorizationSetBuilder& RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent);
+    AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size);
+    AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size);
+
+    AuthorizationSetBuilder& SigningKey();
+    AuthorizationSetBuilder& EncryptionKey();
+    AuthorizationSetBuilder& NoDigestOrPadding();
+    AuthorizationSetBuilder& EcbMode();
+
+    AuthorizationSetBuilder& Digest(keymaster_digest_t digest) {
+        return Authorization(TAG_DIGEST, digest);
+    }
+
+    AuthorizationSetBuilder& Padding(keymaster_padding_t padding) {
+        return Authorization(TAG_PADDING, padding);
+    }
+
+    AuthorizationSetBuilder& Deduplicate() {
+        set.Deduplicate();
+        return *this;
+    }
+
+    AuthorizationSet build() const { return set; }
+
+  private:
+    friend AuthorizationSet;
+    AuthorizationSet set;
+};
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaKey(uint32_t key_size,
+                                                                uint64_t public_exponent) {
+    Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA);
+    Authorization(TAG_KEY_SIZE, key_size);
+    Authorization(TAG_RSA_PUBLIC_EXPONENT, public_exponent);
+    return *this;
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(uint32_t key_size) {
+    Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC);
+    Authorization(TAG_KEY_SIZE, key_size);
+    return *this;
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesKey(uint32_t key_size) {
+    Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES);
+    return Authorization(TAG_KEY_SIZE, key_size);
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::HmacKey(uint32_t key_size) {
+    Authorization(TAG_ALGORITHM, KM_ALGORITHM_HMAC);
+    Authorization(TAG_KEY_SIZE, key_size);
+    return SigningKey();
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaSigningKey(uint32_t key_size,
+                                                                       uint64_t public_exponent) {
+    RsaKey(key_size, public_exponent);
+    return SigningKey();
+}
+
+inline AuthorizationSetBuilder&
+AuthorizationSetBuilder::RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent) {
+    RsaKey(key_size, public_exponent);
+    return EncryptionKey();
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(uint32_t key_size) {
+    EcdsaKey(key_size);
+    return SigningKey();
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesEncryptionKey(uint32_t key_size) {
+    AesKey(key_size);
+    return EncryptionKey();
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::SigningKey() {
+    Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN);
+    return Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY);
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::EncryptionKey() {
+    Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT);
+    return Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT);
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() {
+    Authorization(TAG_DIGEST, KM_DIGEST_NONE);
+    return Authorization(TAG_PADDING, KM_PAD_NONE);
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcbMode() {
+    return Authorization(TAG_BLOCK_MODE, KM_MODE_ECB);
+}
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_KEY_AUTHORIZATION_SET_H_
diff --git a/keymaster/include/keymaster/ec_key_factory.h b/keymaster/include/keymaster/ec_key_factory.h
new file mode 100644
index 0000000..aaeb548
--- /dev/null
+++ b/keymaster/include/keymaster/ec_key_factory.h
@@ -0,0 +1,60 @@
+/*
+ * 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_EC_KEY_FACTORY_H_
+#define SYSTEM_KEYMASTER_EC_KEY_FACTORY_H_
+
+#include <openssl/ec.h>
+#include <openssl/evp.h>
+
+#include <keymaster/asymmetric_key_factory.h>
+
+namespace keymaster {
+
+class EcKeyFactory : public AsymmetricKeyFactory {
+  public:
+    explicit EcKeyFactory(const KeymasterContext* context) : AsymmetricKeyFactory(context) {}
+
+    keymaster_algorithm_t keymaster_key_type() const override { return KM_ALGORITHM_EC; }
+    int evp_key_type() const override { return EVP_PKEY_EC; }
+
+    keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+                                  KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
+                                  AuthorizationSet* sw_enforced) const 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) const override;
+
+    keymaster_error_t CreateEmptyKey(const AuthorizationSet& hw_enforced,
+                                     const AuthorizationSet& sw_enforced,
+                                     UniquePtr<AsymmetricKey>* key) const override;
+
+    keymaster_error_t UpdateImportKeyDescription(const AuthorizationSet& key_description,
+                                                 keymaster_key_format_t key_format,
+                                                 const KeymasterKeyBlob& key_material,
+                                                 AuthorizationSet* updated_description,
+                                                 uint32_t* key_size) const;
+
+    OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const override;
+
+    static EC_GROUP* choose_group(size_t key_size_bits);
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_EC_KEY_FACTORY_H_
diff --git a/keymaster/include/keymaster/key_factory.h b/keymaster/include/keymaster/key_factory.h
new file mode 100644
index 0000000..18f69c4
--- /dev/null
+++ b/keymaster/include/keymaster/key_factory.h
@@ -0,0 +1,69 @@
+/*
+ * 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_KEY_FACTORY_H_
+#define SYSTEM_KEYMASTER_KEY_FACTORY_H_
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/authorization_set.h>
+
+namespace keymaster {
+
+class Key;
+class KeymasterContext;
+class OperationFactory;
+struct KeymasterKeyBlob;
+
+/**
+ * KeyFactory is a abstraction that encapsulats the knowledge of how to build and parse a specifiec
+ * subclass of Key.
+ */
+class KeyFactory {
+  public:
+    explicit KeyFactory(const KeymasterContext* context) : context_(context) {}
+    virtual ~KeyFactory() {}
+
+    // Factory methods.
+    virtual keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+                                          KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
+                                          AuthorizationSet* sw_enforced) const = 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) const = 0;
+
+    virtual keymaster_error_t LoadKey(const KeymasterKeyBlob& key_material,
+                                      const AuthorizationSet& additional_params,
+                                      const AuthorizationSet& hw_enforced,
+                                      const AuthorizationSet& sw_enforced,
+                                      UniquePtr<Key>* key) const = 0;
+
+    virtual OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const = 0;
+
+    // Informational methods.
+    virtual const keymaster_key_format_t* SupportedImportFormats(size_t* format_count) const = 0;
+    virtual const keymaster_key_format_t* SupportedExportFormats(size_t* format_count) const = 0;
+
+  protected:
+    const KeymasterContext* context_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_KEY_FACTORY_H_
diff --git a/keymaster/include/keymaster/keymaster_context.h b/keymaster/include/keymaster/keymaster_context.h
new file mode 100644
index 0000000..c9802e4
--- /dev/null
+++ b/keymaster/include/keymaster/keymaster_context.h
@@ -0,0 +1,154 @@
+/*
+ * 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 <openssl/evp.h>
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/keymaster_enforcement.h>
+
+namespace keymaster {
+
+class AuthorizationSet;
+class KeyFactory;
+class OperationFactory;
+struct KeymasterKeyBlob;
+
+/**
+ * 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(){};
+
+    virtual KeyFactory* GetKeyFactory(keymaster_algorithm_t algorithm) const = 0;
+    virtual OperationFactory* GetOperationFactory(keymaster_algorithm_t algorithm,
+                                                  keymaster_purpose_t purpose) const = 0;
+    virtual keymaster_algorithm_t* GetSupportedAlgorithms(size_t* algorithms_count) const = 0;
+
+    /**
+     * 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;
+
+    /**
+     * Take whatever environment-specific action is appropriate (if any) to delete the specified
+     * key.
+     */
+    virtual keymaster_error_t DeleteKey(const KeymasterKeyBlob& /* blob */) const {
+        return KM_ERROR_OK;
+    }
+
+    /**
+     * Take whatever environment-specific action is appropriate to delete all keys.
+     */
+    virtual keymaster_error_t DeleteAllKeys() const { return KM_ERROR_OK; }
+
+    /**
+     * 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;
+
+    /**
+     * Return the enforcement policy for this context, or null if no enforcement should be done.
+     */
+    virtual KeymasterEnforcement* enforcement_policy() = 0;
+
+    /**
+     * Return the attestation signing key of the specified algorithm (KM_ALGORITHM_RSA or
+     * KM_ALGORITHM_EC).
+     */
+    virtual EVP_PKEY* AttestationKey(keymaster_algorithm_t algorithm,
+                                     keymaster_error_t* error) const = 0;
+
+    /**
+     * Return the certificate chain of the attestation signing key of the specified algorithm
+     * (KM_ALGORITHM_RSA or KM_ALGORITHM_EC).
+     */
+    virtual keymaster_cert_chain_t* AttestationChain(keymaster_algorithm_t algorithm,
+                                                     keymaster_error_t* error) const = 0;
+
+  private:
+    // Uncopyable.
+    KeymasterContext(const KeymasterContext&);
+    void operator=(const KeymasterContext&);
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_KEYMASTER_CONTEXT_H_
diff --git a/keymaster/include/keymaster/keymaster_enforcement.h b/keymaster/include/keymaster/keymaster_enforcement.h
new file mode 100644
index 0000000..69ef5e3
--- /dev/null
+++ b/keymaster/include/keymaster/keymaster_enforcement.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 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 ANDROID_LIBRARY_KEYMASTER_ENFORCEMENT_H
+#define ANDROID_LIBRARY_KEYMASTER_ENFORCEMENT_H
+
+#include <stdio.h>
+
+#include <keymaster/authorization_set.h>
+
+namespace keymaster {
+
+typedef uint64_t km_id_t;
+
+class KeymasterEnforcementContext {
+  public:
+    virtual ~KeymasterEnforcementContext() {}
+    /*
+     * Get current time.
+     */
+};
+
+class AccessTimeMap;
+class AccessCountMap;
+
+class KeymasterEnforcement {
+  public:
+    /**
+     * Construct a KeymasterEnforcement.
+     */
+    KeymasterEnforcement(uint32_t max_access_time_map_size, uint32_t max_access_count_map_size);
+    virtual ~KeymasterEnforcement();
+
+    /**
+     * Iterates through the authorization set and returns the corresponding keymaster error. Will
+     * return KM_ERROR_OK if all criteria is met for the given purpose in the authorization set with
+     * the given operation params and handle. Used for encrypt, decrypt sign, and verify.
+     */
+    keymaster_error_t AuthorizeOperation(const keymaster_purpose_t purpose, const km_id_t keyid,
+                                         const AuthorizationSet& auth_set,
+                                         const AuthorizationSet& operation_params,
+                                         keymaster_operation_handle_t op_handle,
+                                         bool is_begin_operation);
+
+    /**
+     * Iterates through the authorization set and returns the corresponding keymaster error. Will
+     * return KM_ERROR_OK if all criteria is met for the given purpose in the authorization set with
+     * the given operation params. Used for encrypt, decrypt sign, and verify.
+     */
+    keymaster_error_t AuthorizeBegin(const keymaster_purpose_t purpose, const km_id_t keyid,
+                                     const AuthorizationSet& auth_set,
+                                     const AuthorizationSet& operation_params);
+
+    /**
+     * Iterates through the authorization set and returns the corresponding keymaster error. Will
+     * return KM_ERROR_OK if all criteria is met for the given purpose in the authorization set with
+     * the given operation params and handle. Used for encrypt, decrypt sign, and verify.
+     */
+    keymaster_error_t AuthorizeUpdate(const AuthorizationSet& auth_set,
+                                      const AuthorizationSet& operation_params,
+                                      keymaster_operation_handle_t op_handle) {
+        return AuthorizeUpdateOrFinish(auth_set, operation_params, op_handle);
+    }
+
+    /**
+     * Iterates through the authorization set and returns the corresponding keymaster error. Will
+     * return KM_ERROR_OK if all criteria is met for the given purpose in the authorization set with
+     * the given operation params and handle. Used for encrypt, decrypt sign, and verify.
+     */
+    keymaster_error_t AuthorizeFinish(const AuthorizationSet& auth_set,
+                                      const AuthorizationSet& operation_params,
+                                      keymaster_operation_handle_t op_handle) {
+        return AuthorizeUpdateOrFinish(auth_set, operation_params, op_handle);
+    }
+
+    /**
+     * Creates a key ID for use in subsequent calls to AuthorizeOperation.  Clients needn't use this
+     * method of creating key IDs, as long as they use something consistent and unique.  This method
+     * hashes the key blob.
+     *
+     * Returns false if an error in the crypto library prevents creation of an ID.
+     */
+    static bool CreateKeyId(const keymaster_key_blob_t& key_blob, km_id_t* keyid);
+
+    //
+    // Methods that must be implemented by subclasses
+    //
+    // The time-related methods address the fact that different enforcement contexts may have
+    // different time-related capabilities.  In particular:
+    //
+    // - They may or may not be able to check dates against real-world clocks.
+    //
+    // - They may or may not be able to check timestampls against authentication trustlets (minters
+    //   of hw_auth_token_t structs).
+    //
+    // - They must have some time source for relative times, but may not be able to provide more
+    //   than reliability and monotonicity.
+
+    /*
+     * Returns true if the specified activation date has passed, or if activation cannot be
+     * enforced.
+     */
+    virtual bool activation_date_valid(uint64_t activation_date) const = 0;
+
+    /*
+     * Returns true if the specified expiration date has passed.  Returns false if it has not, or if
+     * expiration cannot be enforced.
+     */
+    virtual bool expiration_date_passed(uint64_t expiration_date) const = 0;
+
+    /*
+     * Returns true if the specified auth_token is older than the specified timeout.
+     */
+    virtual bool auth_token_timed_out(const hw_auth_token_t& token, uint32_t timeout) const = 0;
+
+    /*
+     * Get current time in seconds from some starting point.  This value is used to compute relative
+     * times between events.  It must be monotonically increasing, and must not skip or lag.  It
+     * need not have any relation to any external time standard (other than the duration of
+     * "second").
+     *
+     * On POSIX systems, it's recommented to use clock_gettime(CLOCK_MONOTONIC, ...) to implement
+     * this method.
+     */
+    virtual uint32_t get_current_time() const = 0;
+
+    /*
+     * Returns true if the specified auth_token has a valid signature, or if signature validation is
+     * not available.
+     */
+    virtual bool ValidateTokenSignature(const hw_auth_token_t& token) const = 0;
+
+  private:
+    keymaster_error_t AuthorizeUpdateOrFinish(const AuthorizationSet& auth_set,
+                                              const AuthorizationSet& operation_params,
+                                              keymaster_operation_handle_t op_handle);
+
+    bool MinTimeBetweenOpsPassed(uint32_t min_time_between, const km_id_t keyid);
+    bool MaxUsesPerBootNotExceeded(const km_id_t keyid, uint32_t max_uses);
+    bool AuthTokenMatches(const AuthorizationSet& auth_set,
+                          const AuthorizationSet& operation_params, const uint64_t user_secure_id,
+                          const int auth_type_index, const int auth_timeout_index,
+                          const keymaster_operation_handle_t op_handle,
+                          bool is_begin_operation) const;
+
+    AccessTimeMap* access_time_map_;
+    AccessCountMap* access_count_map_;
+};
+
+}; /* namespace keymaster */
+
+#endif  // ANDROID_LIBRARY_KEYMASTER_ENFORCEMENT_H
diff --git a/keymaster/include/keymaster/keymaster_tags.h b/keymaster/include/keymaster/keymaster_tags.h
new file mode 100644
index 0000000..dcaf0da
--- /dev/null
+++ b/keymaster/include/keymaster/keymaster_tags.h
@@ -0,0 +1,258 @@
+/*
+ * 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_KEYMASTER_TAGS_H_
+#define SYSTEM_KEYMASTER_KEYMASTER_TAGS_H_
+
+/**
+ * This header contains various definitions that make working with keymaster tags safer and easier.
+ * It makes use of a fair amount of template metaprogramming, which is genarally a bad idea for
+ * maintainability, but in this case all of the metaprogramming serves the purpose of making it
+ * impossible to make certain classes of mistakes when operating on keymaster authorizations.  For
+ * example, it's an error to create a keymaster_param_t with tag == KM_TAG_PURPOSE and then to
+ * assign KM_ALGORITHM_RSA to the enumerated element of its union, but because "enumerated" is a
+ * uint32_t, there's no way for the compiler, ordinarily, to diagnose it.  Also, generic functions
+ * to manipulate authorizations of multiple types can't be written, because they need to know which
+ * union parameter to modify.
+ *
+ * The machinery in this header solves these problems.  The core elements are two templated classes,
+ * TypedTag and TypedEnumTag.  These classes are templated on a tag type and a tag value, and in the
+ * case of TypedEnumTag, an enumeration type as well.  Specializations are created for each
+ * keymaster tag, associating the tag type with the tag, and an instance of each specialization is
+ * created, and named the same as the keymaster tag, but with the KM_ prefix omitted.  Because the
+ * classes include a conversion operator to keymaster_tag_t, they can be used anywhere a
+ * keymaster_tag_t is expected.
+ *
+ * They also define a "value_type" typedef, which specifies the type of values associated with that
+ * particular tag.  This enables template functions to be written that check that the correct
+ * parameter type is used for a given tag, and that use the correct union entry for the tag type.  A
+ * very useful example is the overloaded "Authorization" function defined below, which takes tag and
+ * value arguments and correctly constructs a keyamster_param_t struct.
+ *
+ * Because the classes have no data members and all of their methods are inline, they have ZERO
+ * run-time cost in and of themselves.  The one way in which they can create code bloat is when
+ * template functions using them are expanded multiple times.  The standard method of creating
+ * trivial, inlined template functions which call non-templated functions which are compact but not
+ * type-safe, allows the program to have both the type-safety of the templates and the compactness
+ * of the non-templated functions, at the same time.
+ */
+
+#include <hardware/hw_auth_token.h>
+#include <hardware/keymaster_defs.h>
+
+namespace keymaster {
+
+// The following create the numeric values that KM_TAG_PADDING and KM_TAG_DIGEST used to have.  We
+// need these old values to be able to support old keys that use them.
+static const keymaster_tag_t KM_TAG_DIGEST_OLD = static_cast<keymaster_tag_t>(KM_ENUM | 5);
+static const keymaster_tag_t KM_TAG_PADDING_OLD = static_cast<keymaster_tag_t>(KM_ENUM | 7);
+
+// Until we have C++11, fake std::static_assert.
+template <bool b> struct StaticAssert {};
+template <> struct StaticAssert<true> {
+    static void check() {}
+};
+
+// An unusable type that we can associate with tag types that don't have a simple value type.
+// That will prevent the associated type from being used inadvertently.
+class Void {
+    Void();
+    ~Void();
+};
+
+/**
+ * A template that defines the association between non-enumerated tag types and their value
+ * types.  For each tag type we define a specialized struct that contains a typedef "value_type".
+ */
+template <keymaster_tag_type_t tag_type> struct TagValueType {};
+template <> struct TagValueType<KM_ULONG> { typedef uint64_t value_type; };
+template <> struct TagValueType<KM_ULONG_REP> { typedef uint64_t value_type; };
+template <> struct TagValueType<KM_DATE> { typedef uint64_t value_type; };
+template <> struct TagValueType<KM_UINT> { typedef uint32_t value_type; };
+template <> struct TagValueType<KM_UINT_REP> { typedef uint32_t value_type; };
+template <> struct TagValueType<KM_INVALID> { typedef Void value_type; };
+template <> struct TagValueType<KM_BOOL> { typedef bool value_type; };
+template <> struct TagValueType<KM_BYTES> { typedef keymaster_blob_t value_type; };
+template <> struct TagValueType<KM_BIGNUM> { typedef keymaster_blob_t value_type; };
+
+/**
+ * TypedTag is a templatized version of keymaster_tag_t, which provides compile-time checking of
+ * keymaster tag types. Instances are convertible to keymaster_tag_t, so they can be used wherever
+ * keymaster_tag_t is expected, and because they encode the tag type it's possible to create
+ * function overloadings that only operate on tags with a particular type.
+ */
+template <keymaster_tag_type_t tag_type, keymaster_tag_t tag> class TypedTag {
+  public:
+    typedef typename TagValueType<tag_type>::value_type value_type;
+
+    inline TypedTag() {
+        // Ensure that it's impossible to create a TypedTag instance whose 'tag' doesn't have type
+        // 'tag_type'.  Attempting to instantiate a tag with the wrong type will result in a compile
+        // error (no match for template specialization StaticAssert<false>), with no run-time cost.
+        StaticAssert<(tag & tag_type) == tag_type>::check();
+        StaticAssert<(tag_type != KM_ENUM) && (tag_type != KM_ENUM_REP)>::check();
+    }
+    inline operator keymaster_tag_t() { return tag; }
+    inline long masked_tag() { return static_cast<long>(keymaster_tag_mask_type(tag)); }
+};
+
+template <keymaster_tag_type_t tag_type, keymaster_tag_t tag, typename KeymasterEnum>
+class TypedEnumTag {
+  public:
+    typedef KeymasterEnum value_type;
+
+    inline TypedEnumTag() {
+        // Ensure that it's impossible to create a TypedTag instance whose 'tag' doesn't have type
+        // 'tag_type'.  Attempting to instantiate a tag with the wrong type will result in a compile
+        // error (no match for template specialization StaticAssert<false>), with no run-time cost.
+        StaticAssert<(tag & tag_type) == tag_type>::check();
+        StaticAssert<(tag_type == KM_ENUM) || (tag_type == KM_ENUM_REP)>::check();
+    }
+    inline operator keymaster_tag_t() { return tag; }
+    inline long masked_tag() { return static_cast<long>(keymaster_tag_mask_type(tag)); }
+};
+
+#ifdef KEYMASTER_NAME_TAGS
+const char* StringifyTag(keymaster_tag_t tag);
+#endif
+
+// DECLARE_KEYMASTER_TAG is used to declare TypedTag instances for each non-enum keymaster tag.
+#define DECLARE_KEYMASTER_TAG(type, name) extern TypedTag<type, KM_##name> name
+
+DECLARE_KEYMASTER_TAG(KM_INVALID, TAG_INVALID);
+DECLARE_KEYMASTER_TAG(KM_UINT, TAG_KEY_SIZE);
+DECLARE_KEYMASTER_TAG(KM_UINT, TAG_MAC_LENGTH);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_CALLER_NONCE);
+DECLARE_KEYMASTER_TAG(KM_UINT, TAG_MIN_MAC_LENGTH);
+DECLARE_KEYMASTER_TAG(KM_ULONG, TAG_RSA_PUBLIC_EXPONENT);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_ECIES_SINGLE_HASH_MODE);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_INCLUDE_UNIQUE_ID);
+DECLARE_KEYMASTER_TAG(KM_DATE, TAG_ACTIVE_DATETIME);
+DECLARE_KEYMASTER_TAG(KM_DATE, TAG_ORIGINATION_EXPIRE_DATETIME);
+DECLARE_KEYMASTER_TAG(KM_DATE, TAG_USAGE_EXPIRE_DATETIME);
+DECLARE_KEYMASTER_TAG(KM_UINT, TAG_MIN_SECONDS_BETWEEN_OPS);
+DECLARE_KEYMASTER_TAG(KM_UINT, TAG_MAX_USES_PER_BOOT);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_ALL_USERS);
+DECLARE_KEYMASTER_TAG(KM_UINT, TAG_USER_ID);
+DECLARE_KEYMASTER_TAG(KM_ULONG_REP, TAG_USER_SECURE_ID);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_NO_AUTH_REQUIRED);
+DECLARE_KEYMASTER_TAG(KM_UINT, TAG_AUTH_TIMEOUT);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_ALLOW_WHILE_ON_BODY);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_ALL_APPLICATIONS);
+DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_APPLICATION_ID);
+DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_APPLICATION_DATA);
+DECLARE_KEYMASTER_TAG(KM_DATE, TAG_CREATION_DATETIME);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_ROLLBACK_RESISTANT);
+DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_ROOT_OF_TRUST);
+DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_ASSOCIATED_DATA);
+DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_NONCE);
+DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_AUTH_TOKEN);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_BOOTLOADER_ONLY);
+DECLARE_KEYMASTER_TAG(KM_UINT, TAG_OS_VERSION);
+DECLARE_KEYMASTER_TAG(KM_UINT, TAG_OS_PATCHLEVEL);
+DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_UNIQUE_ID);
+
+// DECLARE_KEYMASTER_ENUM_TAG is used to declare TypedEnumTag instances for each enum keymaster tag.
+#define DECLARE_KEYMASTER_ENUM_TAG(type, name, enumtype)                                           \
+    extern TypedEnumTag<type, KM_##name, enumtype> name
+
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_PURPOSE, keymaster_purpose_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_ALGORITHM, keymaster_algorithm_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_BLOCK_MODE, keymaster_block_mode_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_DIGEST, keymaster_digest_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_DIGEST_OLD, keymaster_digest_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_PADDING, keymaster_padding_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_PADDING_OLD, keymaster_padding_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_BLOB_USAGE_REQUIREMENTS,
+                           keymaster_key_blob_usage_requirements_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_ORIGIN, keymaster_key_origin_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_USER_AUTH_TYPE, hw_authenticator_type_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_KDF, keymaster_kdf_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_EC_CURVE, keymaster_ec_curve_t);
+
+//
+// Overloaded function "Authorization" to create keymaster_key_param_t objects for all of tags.
+//
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_BOOL, Tag> tag) {
+    return keymaster_param_bool(tag);
+}
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_UINT, Tag> tag, uint32_t value) {
+    return keymaster_param_int(tag, value);
+}
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_UINT_REP, Tag> tag, uint32_t value) {
+    return keymaster_param_int(tag, value);
+}
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_ULONG, Tag> tag, uint64_t value) {
+    return keymaster_param_long(tag, value);
+}
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_ULONG_REP, Tag> tag, uint64_t value) {
+    return keymaster_param_long(tag, value);
+}
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_DATE, Tag> tag, uint64_t value) {
+    return keymaster_param_date(tag, value);
+}
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_BYTES, Tag> tag, const void* bytes,
+                                           size_t bytes_len) {
+    return keymaster_param_blob(tag, reinterpret_cast<const uint8_t*>(bytes), bytes_len);
+}
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_BYTES, Tag> tag,
+                                           const keymaster_blob_t& blob) {
+    return keymaster_param_blob(tag, blob.data, blob.data_length);
+}
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_BIGNUM, Tag> tag, const void* bytes,
+                                           size_t bytes_len) {
+    return keymaster_param_blob(tag, reinterpret_cast<const uint8_t*>(bytes), bytes_len);
+}
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_BIGNUM, Tag> tag,
+                                           const keymaster_blob_t& blob) {
+    return keymaster_param_blob(tag, blob.data, blob.data_length);
+}
+
+template <keymaster_tag_t Tag, typename KeymasterEnum>
+inline keymaster_key_param_t Authorization(TypedEnumTag<KM_ENUM, Tag, KeymasterEnum> tag,
+                                           KeymasterEnum value) {
+    return keymaster_param_enum(tag, value);
+}
+
+template <keymaster_tag_t Tag, typename KeymasterEnum>
+inline keymaster_key_param_t Authorization(TypedEnumTag<KM_ENUM_REP, Tag, KeymasterEnum> tag,
+                                           KeymasterEnum value) {
+    return keymaster_param_enum(tag, value);
+}
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_KEYMASTER_TAGS_H_
diff --git a/keymaster/include/keymaster/logger.h b/keymaster/include/keymaster/logger.h
new file mode 100644
index 0000000..a4fdea3
--- /dev/null
+++ b/keymaster/include/keymaster/logger.h
@@ -0,0 +1,70 @@
+/*
+ * 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_LOGGER_H_
+#define SYSTEM_KEYMASTER_LOGGER_H_
+
+#include <stdarg.h>
+
+namespace keymaster {
+
+class Logger {
+  public:
+    Logger() {}
+    virtual ~Logger() {}
+
+    enum LogLevel {
+        DEBUG_LVL,    // Messages used only for debugging
+        INFO_LVL,     // Informational messages; something is unusual but not wrong
+        WARNING_LVL,  // There's an indication of trouble, but it may be okay.
+        ERROR_LVL,    // A problem has occurred, but processing can continue
+        SEVERE_LVL,   // A severe problem has occurred; likely indicates a defect.
+    };
+
+    virtual int log_msg(LogLevel level, const char* fmt, va_list args) const = 0;
+
+    static int Log(LogLevel level, const char* fmt, va_list args);
+    static int Log(LogLevel level, const char* fmt, ...);
+    static int Debug(const char* fmt, ...);
+    static int Info(const char* fmt, ...);
+    static int Warning(const char* fmt, ...);
+    static int Error(const char* fmt, ...);
+    static int Severe(const char* fmt, ...);
+
+  protected:
+    static void set_instance(Logger* logger) { instance_ = logger; }
+
+  private:
+    // Disallow copying.
+    Logger(const Logger&);
+    void operator=(const Logger&);
+
+    static Logger* instance_;
+};
+
+#define STR(x) #x
+#define STRINGIFY(x) STR(x)
+#define FILE_LINE __FILE__ ", Line " STRINGIFY(__LINE__) ": "
+
+#define LOG_D(fmt, ...) Logger::Debug(FILE_LINE fmt, __VA_ARGS__)
+#define LOG_I(fmt, ...) Logger::Info(FILE_LINE fmt, __VA_ARGS__)
+#define LOG_W(fmt, ...) Logger::Warning(FILE_LINE fmt, __VA_ARGS__)
+#define LOG_E(fmt, ...) Logger::Error(FILE_LINE fmt, __VA_ARGS__)
+#define LOG_S(fmt, ...) Logger::Severe(FILE_LINE fmt, __VA_ARGS__)
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_LOGGER_H_
diff --git a/keymaster/include/keymaster/rsa_key_factory.h b/keymaster/include/keymaster/rsa_key_factory.h
new file mode 100644
index 0000000..f651652
--- /dev/null
+++ b/keymaster/include/keymaster/rsa_key_factory.h
@@ -0,0 +1,60 @@
+/*
+ * 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_RSA_KEY_FACTORY_H_
+#define SYSTEM_KEYMASTER_RSA_KEY_FACTORY_H_
+
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+
+#include <keymaster/asymmetric_key_factory.h>
+
+namespace keymaster {
+
+class RsaKeyFactory : public AsymmetricKeyFactory {
+  public:
+    explicit RsaKeyFactory(const KeymasterContext* context) : AsymmetricKeyFactory(context) {}
+
+    keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+                                  KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
+                                  AuthorizationSet* sw_enforced) const 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) const override;
+
+    keymaster_error_t CreateEmptyKey(const AuthorizationSet& hw_enforced,
+                                     const AuthorizationSet& sw_enforced,
+                                     UniquePtr<AsymmetricKey>* key) const override;
+
+    OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const override;
+
+    keymaster_algorithm_t keymaster_key_type() const override { return KM_ALGORITHM_RSA; }
+    int evp_key_type() const override { return EVP_PKEY_RSA; }
+
+  protected:
+    keymaster_error_t UpdateImportKeyDescription(const AuthorizationSet& key_description,
+                                                 keymaster_key_format_t import_key_format,
+                                                 const KeymasterKeyBlob& import_key_material,
+                                                 AuthorizationSet* updated_description,
+                                                 uint64_t* public_exponent,
+                                                 uint32_t* key_size) const;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_RSA_KEY_FACTORY_H_
diff --git a/keymaster/include/keymaster/serializable.h b/keymaster/include/keymaster/serializable.h
new file mode 100644
index 0000000..8748c55
--- /dev/null
+++ b/keymaster/include/keymaster/serializable.h
@@ -0,0 +1,253 @@
+/*
+ * 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_SERIALIZABLE_H_
+#define SYSTEM_KEYMASTER_SERIALIZABLE_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cstddef>
+#include <new>
+
+#include <UniquePtr.h>
+
+namespace keymaster {
+
+class Serializable {
+  public:
+    Serializable() {}
+    virtual ~Serializable() {}
+
+    /**
+     * Return the size of the serialized representation of this object.
+     */
+    virtual size_t SerializedSize() const = 0;
+
+    /**
+     * Serialize this object into the provided buffer.  Returns a pointer to the byte after the last
+     * written.  Will not write past \p end, which should point to \p buf + size of the buffer
+     * (i.e. one past the end of the buffer).
+     */
+    virtual uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const = 0;
+
+    /**
+     * Deserialize from the provided buffer, copying the data into newly-allocated storage.  Returns
+     * true if successful, and advances *buf past the bytes read.
+     */
+    virtual bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) = 0;
+
+  private:
+    // Disallow copying and assignment.
+    Serializable(const Serializable&);
+    void operator=(const Serializable&);
+};
+
+/*
+ * Utility functions for writing Serialize() methods
+ */
+
+/**
+ * Append a byte array to a buffer.  Note that by itself this function isn't very useful, because it
+ * provides no indication in the serialized buffer of what the array size is.  For writing arrays,
+ * see \p append_size_and_data_to_buf().
+ *
+ * Returns a pointer to the first byte after the data written.
+ */
+uint8_t* append_to_buf(uint8_t* buf, const uint8_t* end, const void* data, size_t data_len);
+
+/**
+ * Append some type of value convertible to a uint32_t to a buffer.  This is primarily used for
+ * writing enumerated values, and uint32_ts.
+ *
+ * Returns a pointer to the first byte after the data written.
+ */
+template <typename T>
+inline uint8_t* append_uint32_to_buf(uint8_t* buf, const uint8_t* end, T value) {
+    uint32_t val = static_cast<uint32_t>(value);
+    return append_to_buf(buf, end, &val, sizeof(val));
+}
+
+/**
+ * Append a uint64_t to a buffer.  Returns a pointer to the first byte after the data written.
+ */
+inline uint8_t* append_uint64_to_buf(uint8_t* buf, const uint8_t* end, uint64_t value) {
+    return append_to_buf(buf, end, &value, sizeof(value));
+}
+
+/**
+ * Appends a byte array to a buffer, prefixing it with a 32-bit size field.  Returns a pointer to
+ * the first byte after the data written.
+ *
+ * See copy_size_and_data_from_buf().
+ */
+inline uint8_t* append_size_and_data_to_buf(uint8_t* buf, const uint8_t* end, const void* data,
+                                            size_t data_len) {
+    buf = append_uint32_to_buf(buf, end, data_len);
+    return append_to_buf(buf, end, data, data_len);
+}
+
+/**
+ * Appends an array of values that are convertible to uint32_t as uint32ts to a buffer, prefixing a
+ * count so deserialization knows how many values to read.
+ *
+ * See copy_uint32_array_from_buf().
+ */
+template <typename T>
+inline uint8_t* append_uint32_array_to_buf(uint8_t* buf, const uint8_t* end, const T* data,
+                                           size_t count) {
+    // Check for overflow
+    if (count >= (UINT32_MAX / sizeof(uint32_t)) || buf + count * sizeof(uint32_t) < buf)
+        return buf;
+    buf = append_uint32_to_buf(buf, end, count);
+    for (size_t i = 0; i < count; ++i)
+        buf = append_uint32_to_buf(buf, end, static_cast<uint32_t>(data[i]));
+    return buf;
+}
+
+/*
+ * Utility functions for writing Deserialize() methods.
+ */
+
+/**
+ * Copy \p size bytes from \p *buf_ptr into \p dest.  If there are fewer than \p size bytes to read,
+ * returns false.  Advances *buf_ptr to the next byte to be read.
+ */
+bool copy_from_buf(const uint8_t** buf_ptr, const uint8_t* end, void* dest, size_t size);
+
+/**
+ * Extracts a uint32_t size from *buf_ptr, placing it in \p *size, and then reads *size bytes from
+ * *buf_ptr, placing them in newly-allocated storage in *dest.  If there aren't enough bytes in
+ * *buf_ptr, returns false.  Advances \p *buf_ptr to the next byte to be read.
+ *
+ * See \p append_size_and_data_to_buf().
+ */
+bool copy_size_and_data_from_buf(const uint8_t** buf_ptr, const uint8_t* end, size_t* size,
+                                 UniquePtr<uint8_t[]>* dest);
+
+/**
+ * Copies a value convertible from uint32_t from \p *buf_ptr.  Returns false if there are less than
+ * four bytes remaining in \p *buf_ptr.  Advances \p *buf_ptr to the next byte to be read.
+ */
+template <typename T>
+inline bool copy_uint32_from_buf(const uint8_t** buf_ptr, const uint8_t* end, T* value) {
+    uint32_t val;
+    if (!copy_from_buf(buf_ptr, end, &val, sizeof(val)))
+        return false;
+    *value = static_cast<T>(val);
+    return true;
+}
+
+/**
+ * Copies a uint64_t from \p *buf_ptr.  Returns false if there are less than eight bytes remaining
+ * in \p *buf_ptr.  Advances \p *buf_ptr to the next byte to be read.
+ */
+inline bool copy_uint64_from_buf(const uint8_t** buf_ptr, const uint8_t* end, uint64_t* value) {
+    return copy_from_buf(buf_ptr, end, value, sizeof(*value));
+}
+
+/**
+ * Copies an array of values convertible to uint32_t from \p *buf_ptr, first reading a count of
+ * values to read. The count is returned in \p *count and the values returned in newly-allocated
+ * storage at *data.  Returns false if there are insufficient bytes at \p *buf_ptr.  Advances \p
+ * *buf_ptr to the next byte to be read.
+ */
+template <typename T>
+inline bool copy_uint32_array_from_buf(const uint8_t** buf_ptr, const uint8_t* end,
+                                       UniquePtr<T[]>* data, size_t* count) {
+    if (!copy_uint32_from_buf(buf_ptr, end, count))
+        return false;
+
+    const uint8_t* array_end = *buf_ptr + *count * sizeof(uint32_t);
+    if (*count >= UINT32_MAX / sizeof(uint32_t) || array_end < *buf_ptr || array_end > end)
+        return false;
+
+    data->reset(new (std::nothrow) T[*count]);
+    if (!data->get())
+        return false;
+    for (size_t i = 0; i < *count; ++i)
+        if (!copy_uint32_from_buf(buf_ptr, end, &(*data)[i]))
+            return false;
+    return true;
+}
+
+/**
+ * A simple buffer that supports reading and writing.  Manages its own memory.
+ */
+class Buffer : public Serializable {
+  public:
+    Buffer() : buffer_(NULL), buffer_size_(0), read_position_(0), write_position_(0) {}
+    explicit Buffer(size_t size) : buffer_(NULL) { Reinitialize(size); }
+    Buffer(const void* buf, size_t size) : buffer_(NULL) { Reinitialize(buf, size); }
+
+    // Grow the buffer so that at least \p size bytes can be written.
+    bool reserve(size_t size);
+
+    bool Reinitialize(size_t size);
+    bool Reinitialize(const void* buf, size_t size);
+
+    // Reinitialize with a copy of the provided buffer's readable data.
+    bool Reinitialize(const Buffer& buffer) {
+        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;
+    size_t available_read() const;
+    size_t buffer_size() const { return buffer_size_; }
+
+    bool write(const uint8_t* src, size_t write_length);
+    bool read(uint8_t* dest, size_t read_length);
+    const uint8_t* peek_read() const { return buffer_.get() + read_position_; }
+    bool advance_read(int distance) {
+        if (static_cast<size_t>(read_position_ + distance) <= write_position_) {
+            read_position_ += distance;
+            return true;
+        }
+        return false;
+    }
+    uint8_t* peek_write() { return buffer_.get() + write_position_; }
+    bool advance_write(int distance) {
+        if (static_cast<size_t>(write_position_ + distance) <= buffer_size_) {
+            write_position_ += distance;
+            return true;
+        }
+        return false;
+    }
+
+    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);
+
+  private:
+    // Disallow copy construction and assignment.
+    void operator=(const Buffer& other);
+    Buffer(const Buffer&);
+
+    UniquePtr<uint8_t[]> buffer_;
+    size_t buffer_size_;
+    size_t read_position_;
+    size_t write_position_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_SERIALIZABLE_H_
diff --git a/keymaster/include/keymaster/soft_keymaster_context.h b/keymaster/include/keymaster/soft_keymaster_context.h
new file mode 100644
index 0000000..2091d6f
--- /dev/null
+++ b/keymaster/include/keymaster/soft_keymaster_context.h
@@ -0,0 +1,115 @@
+/*
+ * 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 <string>
+
+#include <openssl/evp.h>
+
+#include <hardware/keymaster0.h>
+#include <hardware/keymaster1.h>
+#include <keymaster/keymaster_context.h>
+
+namespace keymaster {
+
+class SoftKeymasterKeyRegistrations;
+class Keymaster0Engine;
+class Keymaster1Engine;
+
+/**
+ * SoftKeymasterContext provides the context for a non-secure implementation of AndroidKeymaster.
+ */
+class SoftKeymasterContext : public KeymasterContext {
+  public:
+    explicit SoftKeymasterContext(const std::string& root_of_trust = "SW");
+    ~SoftKeymasterContext() override;
+
+    /**
+     * Use the specified HW keymaster0 device for the operations it supports.  Takes ownership of
+     * the specified device (will call keymaster0_device->common.close());
+     */
+    keymaster_error_t SetHardwareDevice(keymaster0_device_t* keymaster0_device);
+
+    /**
+     * Use the specified HW keymaster1 device for performing undigested RSA and EC operations after
+     * digesting has been done in software.  Takes ownership of the specified device (will call
+     * keymaster1_device->common.close());
+     */
+    keymaster_error_t SetHardwareDevice(keymaster1_device_t* keymaster1_device);
+
+    KeyFactory* GetKeyFactory(keymaster_algorithm_t algorithm) const override;
+    OperationFactory* GetOperationFactory(keymaster_algorithm_t algorithm,
+                                          keymaster_purpose_t purpose) const override;
+    keymaster_algorithm_t* GetSupportedAlgorithms(size_t* algorithms_count) const override;
+    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 DeleteKey(const KeymasterKeyBlob& blob) const override;
+    keymaster_error_t DeleteAllKeys() 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;
+
+    EVP_PKEY* AttestationKey(keymaster_algorithm_t algorithm,
+                             keymaster_error_t* error) const override;
+    keymaster_cert_chain_t* AttestationChain(keymaster_algorithm_t algorithm,
+                                             keymaster_error_t* error) const override;
+
+    KeymasterEnforcement* enforcement_policy() override {
+        // SoftKeymaster does no enforcement; it's all done by Keystore.
+        return nullptr;
+    }
+
+  private:
+    keymaster_error_t ParseOldSoftkeymasterBlob(const KeymasterKeyBlob& blob,
+                                                KeymasterKeyBlob* key_material,
+                                                AuthorizationSet* hw_enforced,
+                                                AuthorizationSet* sw_enforced) const;
+    keymaster_error_t ParseKeymaster1HwBlob(const KeymasterKeyBlob& blob,
+                                            const AuthorizationSet& additional_params,
+                                            KeymasterKeyBlob* key_material,
+                                            AuthorizationSet* hw_enforced,
+                                            AuthorizationSet* sw_enforced) const;
+    keymaster_error_t ParseKeymaster0HwBlob(const KeymasterKeyBlob& blob,
+                                            KeymasterKeyBlob* key_material,
+                                            AuthorizationSet* hw_enforced,
+                                            AuthorizationSet* sw_enforced) const;
+    keymaster_error_t FakeKeyAuthorizations(EVP_PKEY* pubkey, AuthorizationSet* hw_enforced,
+                                            AuthorizationSet* sw_enforced) const;
+    keymaster_error_t BuildHiddenAuthorizations(const AuthorizationSet& input_set,
+                                                AuthorizationSet* hidden) const;
+
+    std::unique_ptr<Keymaster0Engine> km0_engine_;
+    std::unique_ptr<Keymaster1Engine> km1_engine_;
+    std::unique_ptr<KeyFactory> rsa_factory_;
+    std::unique_ptr<KeyFactory> ec_factory_;
+    std::unique_ptr<KeyFactory> aes_factory_;
+    std::unique_ptr<KeyFactory> hmac_factory_;
+    keymaster1_device* km1_dev_;
+    const std::string root_of_trust_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_SOFT_KEYMASTER_CONTEXT_H_
diff --git a/keymaster/include/keymaster/soft_keymaster_device.h b/keymaster/include/keymaster/soft_keymaster_device.h
new file mode 100644
index 0000000..4a734f1
--- /dev/null
+++ b/keymaster/include/keymaster/soft_keymaster_device.h
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SYSTEM_KEYMASTER_SOFT_KEYMASTER_DEVICE_H_
+#define SYSTEM_KEYMASTER_SOFT_KEYMASTER_DEVICE_H_
+
+#include <cstdlib>
+#include <map>
+#include <vector>
+
+#include <hardware/keymaster0.h>
+#include <hardware/keymaster1.h>
+#include <hardware/keymaster2.h>
+
+#include <keymaster/android_keymaster.h>
+#include <keymaster/soft_keymaster_context.h>
+
+#include <UniquePtr.h>
+
+namespace keymaster {
+
+class AuthorizationSet;
+
+/**
+ * Keymaster1 device implementation.
+ *
+ * This is a hybrid software/hardware implementation which wraps a keymaster0_device_t, forwarding
+ * RSA operations to secure hardware and doing everything else in software.
+ *
+ * IMPORTANT MAINTAINER NOTE: Pointers to instances of this class must be castable to hw_device_t
+ * and keymaster_device. This means it must remain a standard layout class (no virtual functions and
+ * no data members which aren't standard layout), and device_ must be the first data member.
+ * Assertions in the constructor validate compliance with those constraints.
+ */
+class SoftKeymasterDevice {
+  public:
+    SoftKeymasterDevice();
+
+    // Public only for testing.
+    explicit SoftKeymasterDevice(SoftKeymasterContext* context);
+
+    /**
+     * Set SoftKeymasterDevice to wrap the speicified HW keymaster0 device.  Takes ownership of the
+     * specified device (will call keymaster0_device->common.close());
+     */
+    keymaster_error_t SetHardwareDevice(keymaster0_device_t* keymaster0_device);
+
+    /**
+     * Set SoftKeymasterDevice to wrap specified HW keymaster1 device.  Takes ownership of the
+     * specified device (will call keymaster1_device->common.close());
+     */
+    keymaster_error_t SetHardwareDevice(keymaster1_device_t* keymaster1_device);
+
+    /**
+     * Returns true if a keymaster1_device_t has been set as the hardware device, and if that
+     * hardware device should be used directly.
+     */
+    bool Keymaster1DeviceIsGood();
+
+    hw_device_t* hw_device();
+    keymaster1_device_t* keymaster_device();
+    keymaster2_device_t* keymaster2_device();
+
+    // Public only for testing
+    void GetVersion(const GetVersionRequest& req, GetVersionResponse* rsp) {
+        impl_->GetVersion(req, rsp);
+    }
+
+    typedef std::pair<keymaster_algorithm_t, keymaster_purpose_t> AlgPurposePair;
+    typedef std::map<AlgPurposePair, std::vector<keymaster_digest_t>> DigestMap;
+
+  private:
+    void initialize_device_struct(uint32_t flags);
+    bool FindUnsupportedDigest(keymaster_algorithm_t algorithm, keymaster_purpose_t purpose,
+                               const AuthorizationSet& params,
+                               keymaster_digest_t* unsupported) const;
+    bool RequiresSoftwareDigesting(keymaster_algorithm_t algorithm, keymaster_purpose_t purpose,
+                                   const AuthorizationSet& params) const;
+    bool KeyRequiresSoftwareDigesting(const AuthorizationSet& key_description) const;
+
+    static void StoreDefaultNewKeyParams(keymaster_algorithm_t algorithm,
+                                         AuthorizationSet* auth_set);
+    static keymaster_error_t GetPkcs8KeyAlgorithm(const uint8_t* key, size_t key_length,
+                                                  keymaster_algorithm_t* algorithm);
+
+    static int close_device(hw_device_t* dev);
+
+    /*
+     * These static methods are the functions referenced through the function pointers in
+     * keymaster_device.
+     */
+
+    // Keymaster1 methods
+    static keymaster_error_t get_supported_algorithms(const keymaster1_device_t* dev,
+                                                      keymaster_algorithm_t** algorithms,
+                                                      size_t* algorithms_length);
+    static keymaster_error_t get_supported_block_modes(const keymaster1_device_t* dev,
+                                                       keymaster_algorithm_t algorithm,
+                                                       keymaster_purpose_t purpose,
+                                                       keymaster_block_mode_t** modes,
+                                                       size_t* modes_length);
+    static keymaster_error_t get_supported_padding_modes(const keymaster1_device_t* dev,
+                                                         keymaster_algorithm_t algorithm,
+                                                         keymaster_purpose_t purpose,
+                                                         keymaster_padding_t** modes,
+                                                         size_t* modes_length);
+    static keymaster_error_t get_supported_digests(const keymaster1_device_t* dev,
+                                                   keymaster_algorithm_t algorithm,
+                                                   keymaster_purpose_t purpose,
+                                                   keymaster_digest_t** digests,
+                                                   size_t* digests_length);
+    static keymaster_error_t get_supported_import_formats(const keymaster1_device_t* dev,
+                                                          keymaster_algorithm_t algorithm,
+                                                          keymaster_key_format_t** formats,
+                                                          size_t* formats_length);
+    static keymaster_error_t get_supported_export_formats(const keymaster1_device_t* dev,
+                                                          keymaster_algorithm_t algorithm,
+                                                          keymaster_key_format_t** formats,
+                                                          size_t* formats_length);
+    static keymaster_error_t add_rng_entropy(const keymaster1_device_t* dev, const uint8_t* data,
+                                             size_t data_length);
+    static keymaster_error_t generate_key(const keymaster1_device_t* dev,
+                                          const keymaster_key_param_set_t* params,
+                                          keymaster_key_blob_t* key_blob,
+                                          keymaster_key_characteristics_t** characteristics);
+    static keymaster_error_t get_key_characteristics(const keymaster1_device_t* dev,
+                                                     const keymaster_key_blob_t* key_blob,
+                                                     const keymaster_blob_t* client_id,
+                                                     const keymaster_blob_t* app_data,
+                                                     keymaster_key_characteristics_t** character);
+    static keymaster_error_t import_key(const keymaster1_device_t* dev,  //
+                                        const keymaster_key_param_set_t* params,
+                                        keymaster_key_format_t key_format,
+                                        const keymaster_blob_t* key_data,
+                                        keymaster_key_blob_t* key_blob,
+                                        keymaster_key_characteristics_t** characteristics);
+    static keymaster_error_t export_key(const keymaster1_device_t* dev,  //
+                                        keymaster_key_format_t export_format,
+                                        const keymaster_key_blob_t* key_to_export,
+                                        const keymaster_blob_t* client_id,
+                                        const keymaster_blob_t* app_data,
+                                        keymaster_blob_t* export_data);
+    static keymaster_error_t delete_key(const keymaster1_device_t* dev,
+                                        const keymaster_key_blob_t* key);
+    static keymaster_error_t delete_all_keys(const keymaster1_device_t* dev);
+    static keymaster_error_t begin(const keymaster1_device_t* dev, keymaster_purpose_t purpose,
+                                   const keymaster_key_blob_t* key,
+                                   const keymaster_key_param_set_t* in_params,
+                                   keymaster_key_param_set_t* out_params,
+                                   keymaster_operation_handle_t* operation_handle);
+    static keymaster_error_t update(const keymaster1_device_t* dev,  //
+                                    keymaster_operation_handle_t operation_handle,
+                                    const keymaster_key_param_set_t* in_params,
+                                    const keymaster_blob_t* input, size_t* input_consumed,
+                                    keymaster_key_param_set_t* out_params,
+                                    keymaster_blob_t* output);
+    static keymaster_error_t finish(const keymaster1_device_t* dev,  //
+                                    keymaster_operation_handle_t operation_handle,
+                                    const keymaster_key_param_set_t* in_params,
+                                    const keymaster_blob_t* signature,
+                                    keymaster_key_param_set_t* out_params,
+                                    keymaster_blob_t* output);
+    static keymaster_error_t abort(const keymaster1_device_t* dev,
+                                   keymaster_operation_handle_t operation_handle);
+
+    // Keymaster2 methods
+    static keymaster_error_t add_rng_entropy(const keymaster2_device_t* dev, const uint8_t* data,
+                                             size_t data_length);
+    static keymaster_error_t generate_key(const keymaster2_device_t* dev,
+                                          const keymaster_key_param_set_t* params,
+                                          keymaster_key_blob_t* key_blob,
+                                          keymaster_key_characteristics_t* characteristics);
+    static keymaster_error_t get_key_characteristics(const keymaster2_device_t* dev,
+                                                     const keymaster_key_blob_t* key_blob,
+                                                     const keymaster_blob_t* client_id,
+                                                     const keymaster_blob_t* app_data,
+                                                     keymaster_key_characteristics_t* character);
+    static keymaster_error_t import_key(const keymaster2_device_t* dev,  //
+                                        const keymaster_key_param_set_t* params,
+                                        keymaster_key_format_t key_format,
+                                        const keymaster_blob_t* key_data,
+                                        keymaster_key_blob_t* key_blob,
+                                        keymaster_key_characteristics_t* characteristics);
+    static keymaster_error_t export_key(const keymaster2_device_t* dev,  //
+                                        keymaster_key_format_t export_format,
+                                        const keymaster_key_blob_t* key_to_export,
+                                        const keymaster_blob_t* client_id,
+                                        const keymaster_blob_t* app_data,
+                                        keymaster_blob_t* export_data);
+    static keymaster_error_t attest_key(const keymaster2_device_t* dev,
+                                        const keymaster_key_blob_t* key_to_attest,
+                                        const keymaster_key_param_set_t* attest_params,
+                                        keymaster_cert_chain_t* cert_chain);
+    static keymaster_error_t delete_key(const keymaster2_device_t* dev,
+                                        const keymaster_key_blob_t* key);
+    static keymaster_error_t delete_all_keys(const keymaster2_device_t* dev);
+    static keymaster_error_t begin(const keymaster2_device_t* dev, keymaster_purpose_t purpose,
+                                   const keymaster_key_blob_t* key,
+                                   const keymaster_key_param_set_t* in_params,
+                                   keymaster_key_param_set_t* out_params,
+                                   keymaster_operation_handle_t* operation_handle);
+    static keymaster_error_t update(const keymaster2_device_t* dev,  //
+                                    keymaster_operation_handle_t operation_handle,
+                                    const keymaster_key_param_set_t* in_params,
+                                    const keymaster_blob_t* input, size_t* input_consumed,
+                                    keymaster_key_param_set_t* out_params,
+                                    keymaster_blob_t* output);
+    static keymaster_error_t finish(const keymaster2_device_t* dev,  //
+                                    keymaster_operation_handle_t operation_handle,
+                                    const keymaster_key_param_set_t* in_params,
+                                    const keymaster_blob_t* input,
+                                    const keymaster_blob_t* signature,
+                                    keymaster_key_param_set_t* out_params,
+                                    keymaster_blob_t* output);
+    static keymaster_error_t abort(const keymaster2_device_t* dev,
+                                   keymaster_operation_handle_t operation_handle);
+
+    keymaster1_device_t km1_device_;
+    keymaster2_device_t km2_device_;
+
+    keymaster0_device_t* wrapped_km0_device_;
+    keymaster1_device_t* wrapped_km1_device_;
+    DigestMap km1_device_digests_;
+    SoftKeymasterContext* context_;
+    UniquePtr<AndroidKeymaster> impl_;
+    std::string module_name_;
+    hw_module_t updated_module_;
+};
+
+}  // namespace keymaster
+
+#endif  // EXTERNAL_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
diff --git a/keymaster/include/keymaster/soft_keymaster_logger.h b/keymaster/include/keymaster/soft_keymaster_logger.h
new file mode 100644
index 0000000..3be83b8
--- /dev/null
+++ b/keymaster/include/keymaster/soft_keymaster_logger.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SYSTEM_KEYMASTER_SOFT_KEYMASTER_LOGGER_H_
+#define SYSTEM_KEYMASTER_SOFT_KEYMASTER_LOGGER_H_
+
+#include <keymaster/logger.h>
+
+namespace keymaster {
+
+class SoftKeymasterLogger : public Logger
+{
+public:
+    SoftKeymasterLogger() { set_instance(this); }
+
+    virtual int log_msg(LogLevel level, const char* fmt, va_list args) const;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_SOFT_KEYMASTER_LOGGER_H_
diff --git a/keymaster/integrity_assured_key_blob.cpp b/keymaster/integrity_assured_key_blob.cpp
new file mode 100644
index 0000000..5c317a3
--- /dev/null
+++ b/keymaster/integrity_assured_key_blob.cpp
@@ -0,0 +1,149 @@
+/*
+ * 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 "integrity_assured_key_blob.h"
+
+#include <assert.h>
+
+#include <new>
+
+#include <openssl/hmac.h>
+#include <openssl/mem.h>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
+
+#include "openssl_err.h"
+
+namespace keymaster {
+
+static const uint8_t BLOB_VERSION = 0;
+static const size_t HMAC_SIZE = 8;
+static const char HMAC_KEY[] = "IntegrityAssuredBlob0";
+
+inline size_t min(size_t a, size_t b) {
+    if (a < b)
+        return a;
+    return b;
+}
+
+class HmacCleanup {
+  public:
+    explicit HmacCleanup(HMAC_CTX* ctx) : ctx_(ctx) {}
+    ~HmacCleanup() { HMAC_CTX_cleanup(ctx_); }
+
+  private:
+    HMAC_CTX* ctx_;
+};
+
+static keymaster_error_t ComputeHmac(const uint8_t* serialized_data, size_t serialized_data_size,
+                                     const AuthorizationSet& hidden, uint8_t hmac[HMAC_SIZE]) {
+    size_t hidden_bytes_size = hidden.SerializedSize();
+    UniquePtr<uint8_t[]> hidden_bytes(new (std::nothrow) uint8_t[hidden_bytes_size]);
+    if (!hidden_bytes.get())
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    hidden.Serialize(hidden_bytes.get(), hidden_bytes.get() + hidden_bytes_size);
+
+    HMAC_CTX ctx;
+    HMAC_CTX_init(&ctx);
+    const EVP_MD* md = EVP_sha256();
+    if (!HMAC_Init_ex(&ctx, HMAC_KEY, sizeof(HMAC_KEY), md, NULL /* engine */))
+        return TranslateLastOpenSslError();
+    HmacCleanup cleanup(&ctx);
+
+    uint8_t tmp[EVP_MAX_MD_SIZE];
+    unsigned tmp_len;
+    if (!HMAC_Update(&ctx, serialized_data, serialized_data_size) ||
+        !HMAC_Update(&ctx, hidden_bytes.get(), hidden_bytes_size) ||  //
+        !HMAC_Final(&ctx, tmp, &tmp_len))
+        return TranslateLastOpenSslError();
+
+    assert(tmp_len >= HMAC_SIZE);
+    memcpy(hmac, tmp, min(HMAC_SIZE, tmp_len));
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t SerializeIntegrityAssuredBlob(const KeymasterKeyBlob& key_material,
+                                                const AuthorizationSet& hidden,
+                                                const AuthorizationSet& hw_enforced,
+                                                const AuthorizationSet& sw_enforced,
+                                                KeymasterKeyBlob* key_blob) {
+    size_t size = 1 /* version */ +                //
+                  key_material.SerializedSize() +  //
+                  hw_enforced.SerializedSize() +   //
+                  sw_enforced.SerializedSize() +   //
+                  HMAC_SIZE;
+
+    if (!key_blob->Reset(size))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    uint8_t* p = key_blob->writable_data();
+    *p++ = BLOB_VERSION;
+    p = key_material.Serialize(p, key_blob->end());
+    p = hw_enforced.Serialize(p, key_blob->end());
+    p = sw_enforced.Serialize(p, key_blob->end());
+
+    return ComputeHmac(key_blob->key_material, p - key_blob->key_material, hidden, p);
+}
+
+keymaster_error_t DeserializeIntegrityAssuredBlob(const KeymasterKeyBlob& key_blob,
+                                                  const AuthorizationSet& hidden,
+                                                  KeymasterKeyBlob* key_material,
+                                                  AuthorizationSet* hw_enforced,
+                                                  AuthorizationSet* sw_enforced) {
+    const uint8_t* p = key_blob.begin();
+    const uint8_t* end = key_blob.end();
+
+    if (p > end || p + HMAC_SIZE > end)
+        return KM_ERROR_INVALID_KEY_BLOB;
+
+    uint8_t computed_hmac[HMAC_SIZE];
+    keymaster_error_t error = ComputeHmac(key_blob.begin(), key_blob.key_material_size - HMAC_SIZE,
+                                          hidden, computed_hmac);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    if (CRYPTO_memcmp(key_blob.end() - HMAC_SIZE, computed_hmac, HMAC_SIZE) != 0)
+        return KM_ERROR_INVALID_KEY_BLOB;
+
+    return DeserializeIntegrityAssuredBlob_NoHmacCheck(key_blob, key_material, hw_enforced,
+                                                       sw_enforced);
+}
+
+keymaster_error_t DeserializeIntegrityAssuredBlob_NoHmacCheck(const KeymasterKeyBlob& key_blob,
+                                                              KeymasterKeyBlob* key_material,
+                                                              AuthorizationSet* hw_enforced,
+                                                              AuthorizationSet* sw_enforced) {
+    const uint8_t* p = key_blob.begin();
+    const uint8_t* end = key_blob.end() - HMAC_SIZE;
+
+    if (p > end)
+        return KM_ERROR_INVALID_KEY_BLOB;
+
+    if (*p != BLOB_VERSION)
+        return KM_ERROR_INVALID_KEY_BLOB;
+    ++p;
+
+    if (!key_material->Deserialize(&p, end) ||  //
+        !hw_enforced->Deserialize(&p, end) ||   //
+        !sw_enforced->Deserialize(&p, end))
+        return KM_ERROR_INVALID_KEY_BLOB;
+
+    return KM_ERROR_OK;
+}
+
+}  // namespace keymaster;
diff --git a/keymaster/integrity_assured_key_blob.h b/keymaster/integrity_assured_key_blob.h
new file mode 100644
index 0000000..6239a8a
--- /dev/null
+++ b/keymaster/integrity_assured_key_blob.h
@@ -0,0 +1,47 @@
+/*
+ * 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_INTEGRITY_ASSURED_KEY_BLOB_
+#define SYSTEM_KEYMASTER_INTEGRITY_ASSURED_KEY_BLOB_
+
+#include <hardware/keymaster_defs.h>
+
+namespace keymaster {
+
+class AuthorizationSet;
+class Buffer;
+struct KeymasterKeyBlob;
+
+keymaster_error_t SerializeIntegrityAssuredBlob(const KeymasterKeyBlob& key_material,
+                                                const AuthorizationSet& hidden,
+                                                const AuthorizationSet& hw_enforced,
+                                                const AuthorizationSet& sw_enforced,
+                                                KeymasterKeyBlob* key_blob);
+
+keymaster_error_t DeserializeIntegrityAssuredBlob(const KeymasterKeyBlob& key_blob,
+                                                  const AuthorizationSet& hidden,
+                                                  KeymasterKeyBlob* key_material,
+                                                  AuthorizationSet* hw_enforced,
+                                                  AuthorizationSet* sw_enforced);
+
+keymaster_error_t DeserializeIntegrityAssuredBlob_NoHmacCheck(const KeymasterKeyBlob& key_blob,
+                                                              KeymasterKeyBlob* key_material,
+                                                              AuthorizationSet* hw_enforced,
+                                                              AuthorizationSet* sw_enforced);
+
+}  // namespace keymaster;
+
+#endif  // SYSTEM_KEYMASTER_INTEGRITY_ASSURED_KEY_BLOB_
diff --git a/keymaster/iso18033kdf.cpp b/keymaster/iso18033kdf.cpp
new file mode 100644
index 0000000..3de0fdf
--- /dev/null
+++ b/keymaster/iso18033kdf.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "iso18033kdf.h"
+#include "openssl_utils.h"
+
+#include <algorithm>
+
+#include <openssl/evp.h>
+
+namespace keymaster {
+
+inline size_t min(size_t a, size_t b) {
+    return (a < b) ? a : b;
+}
+
+bool Iso18033Kdf::GenerateKey(const uint8_t* info, size_t info_len, uint8_t* output,
+                              size_t output_len) {
+    if (!is_initialized_ || output == nullptr)
+        return false;
+
+    /* Check whether output length is too long as specified in ISO/IEC 18033-2. */
+    if ((0xFFFFFFFFULL + start_counter_) * digest_size_ < (uint64_t)output_len)
+        return false;
+
+    EVP_MD_CTX ctx;
+    EvpMdCtxCleaner ctxCleaner(&ctx);
+    EVP_MD_CTX_init(&ctx);
+
+    size_t num_blocks = (output_len + digest_size_ - 1) / digest_size_;
+    UniquePtr<uint8_t[]> counter(new uint8_t[4]);
+    UniquePtr<uint8_t[]> digest_result(new uint8_t[digest_size_]);
+    if (counter.get() == nullptr || digest_result.get() == nullptr)
+        return false;
+    for (size_t block = 0; block < num_blocks; block++) {
+        switch (digest_type_) {
+        case KM_DIGEST_SHA1:
+            if (!EVP_DigestInit_ex(&ctx, EVP_sha1(), nullptr /* default digest */))
+                return false;
+            break;
+        case KM_DIGEST_SHA_2_256:
+            if (!EVP_DigestInit_ex(&ctx, EVP_sha256(), nullptr /* default digest */))
+                return false;
+            break;
+        default:
+            return false;
+        }
+
+        if (!EVP_DigestUpdate(&ctx, secret_key_.get(), secret_key_len_) ||
+            !Uint32ToBigEndianByteArray(block + start_counter_, counter.get()) ||
+            !EVP_DigestUpdate(&ctx, counter.get(), 4))
+            return false;
+
+        if (info != nullptr && info_len > 0) {
+            if (!EVP_DigestUpdate(&ctx, info, info_len))
+                return false;
+        }
+
+        /* OpenSSL does not accept size_t parameter. */
+        uint32_t uint32_digest_size_ = digest_size_;
+        if (!EVP_DigestFinal_ex(&ctx, digest_result.get(), &uint32_digest_size_) ||
+            uint32_digest_size_ != digest_size_)
+            return false;
+
+        size_t block_start = digest_size_ * block;
+        size_t block_length = min(digest_size_, output_len - block_start);
+        memcpy(output + block_start, digest_result.get(), block_length);
+    }
+    return true;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/iso18033kdf.h b/keymaster/iso18033kdf.h
new file mode 100644
index 0000000..40fd2d6
--- /dev/null
+++ b/keymaster/iso18033kdf.h
@@ -0,0 +1,68 @@
+/*
+ * 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_ISO18033KDF_H_
+#define SYSTEM_KEYMASTER_ISO18033KDF_H_
+
+#include "kdf.h"
+
+#include <hardware/keymaster_defs.h>
+
+#include <keymaster/serializable.h>
+
+#include <UniquePtr.h>
+
+namespace keymaster {
+
+/**
+ * A light implementation of ISO18033KDF as defined by ISO-18033-2 (www.shoup.net/iso/std6.pdf) and
+ * its slightly different variant ANSI-X9-42.
+ */
+class Iso18033Kdf : public Kdf {
+  public:
+    ~Iso18033Kdf() {}
+
+    bool Init(keymaster_digest_t digest_type, const uint8_t* secret, size_t secret_len) {
+        return Kdf::Init(digest_type, secret, secret_len, nullptr /* salt */, 0 /* salt_len */);
+    }
+
+    /**
+     * Generates ISO18033's derived key, as defined in ISO-18033-2 and ANSI-X9-42. In ISO 18033-2,
+     * KDF takes a secret and outputs:
+     *
+     * hash(secret || start_counter) || hash(secret|| start_counter + 1) || ...
+     *
+     * In ANSI-X9-42, KDF takes a secret and additional info, and outputs:
+     *
+     * hash(secret || start_counter || info) || hash(secret || start_counter + 1 || info) || ...
+     *
+     * Note that the KDFs are the same if the info field is considered optional.  In both cases the
+     * length of the output is specified by the caller, and the counter is encoded as a 4-element
+     * byte array.
+     */
+    bool GenerateKey(const uint8_t* info, size_t info_len, uint8_t* output,
+                     size_t output_len) override;
+
+  protected:
+    explicit Iso18033Kdf(uint32_t start_counter) : start_counter_(start_counter) {}
+
+  private:
+    uint32_t start_counter_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_ISO18033KDF_H_
diff --git a/keymaster/kdf.cpp b/keymaster/kdf.cpp
new file mode 100644
index 0000000..e196a0c
--- /dev/null
+++ b/keymaster/kdf.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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 "kdf.h"
+
+namespace keymaster {
+
+Kdf::Kdf() : is_initialized_(false) {}
+
+bool Kdf::Init(keymaster_digest_t digest_type, const uint8_t* secret, size_t secret_len,
+               const uint8_t* salt, size_t salt_len) {
+    is_initialized_ = false;
+
+    switch (digest_type) {
+    case KM_DIGEST_SHA1:
+        digest_size_ = 20;
+        digest_type_ = digest_type;
+        break;
+    case KM_DIGEST_SHA_2_256:
+        digest_size_ = 32;
+        digest_type_ = digest_type;
+        break;
+    default:
+        return false;
+    }
+
+    if (!secret || secret_len == 0)
+        return false;
+
+    secret_key_len_ = secret_len;
+    secret_key_.reset(dup_buffer(secret, secret_len));
+    if (!secret_key_.get())
+        return false;
+
+    salt_len_ = salt_len;
+    if (salt && salt_len > 0) {
+        salt_.reset(dup_buffer(salt, salt_len));
+        if (!salt_.get())
+            return false;
+    } else {
+        salt_.reset();
+    }
+
+    is_initialized_ = true;
+    return true;
+}
+
+bool Kdf::Uint32ToBigEndianByteArray(uint32_t number, uint8_t* output) {
+    if (!output)
+        return false;
+
+    output[0] = (number >> 24) & 0xff;
+    output[1] = (number >> 16) & 0xff;
+    output[2] = (number >> 8) & 0xff;
+    output[3] = (number)&0xff;
+    return true;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/kdf.h b/keymaster/kdf.h
new file mode 100644
index 0000000..b90d2bc
--- /dev/null
+++ b/keymaster/kdf.h
@@ -0,0 +1,53 @@
+/*
+ * 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_KDF_H_
+#define SYSTEM_KEYMASTER_KDF_H_
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/serializable.h>
+
+#include <UniquePtr.h>
+
+namespace keymaster {
+
+/**
+ * A base class for wrapping different key derivation functions.
+ */
+class Kdf {
+  public:
+    virtual ~Kdf() { memset_s(secret_key_.get(), 0, secret_key_len_); };
+    Kdf();
+    bool Init(keymaster_digest_t digest_type, const uint8_t* secret, size_t secret_len,
+              const uint8_t* salt, size_t salt_len);
+    virtual bool GenerateKey(const uint8_t* info, size_t info_len, uint8_t* output,
+                             size_t output_len) = 0;
+
+  protected:
+    bool Uint32ToBigEndianByteArray(uint32_t number, uint8_t* output);
+    UniquePtr<uint8_t[]> secret_key_;
+    size_t secret_key_len_;
+    UniquePtr<uint8_t[]> salt_;
+    size_t salt_len_;
+    bool is_initialized_;
+    keymaster_digest_t digest_type_;
+    size_t digest_size_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_KDF_H_
diff --git a/keymaster/kdf1.h b/keymaster/kdf1.h
new file mode 100644
index 0000000..fab1ef7
--- /dev/null
+++ b/keymaster/kdf1.h
@@ -0,0 +1,40 @@
+/*
+ * 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_KDF1_H_
+#define SYSTEM_KEYMASTER_KDF1_H_
+
+#include "iso18033kdf.h"
+
+#include <hardware/keymaster_defs.h>
+
+#include <keymaster/serializable.h>
+
+#include <UniquePtr.h>
+
+namespace keymaster {
+
+/**
+ * Kdf1 is instance of Iso18033Kdf when the counter starts at 0.
+ */
+class Kdf1 : public Iso18033Kdf {
+  public:
+    Kdf1() : Iso18033Kdf(0) {}
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_KDF1_H_
diff --git a/keymaster/kdf1_test.cpp b/keymaster/kdf1_test.cpp
new file mode 100644
index 0000000..9c8b0d5
--- /dev/null
+++ b/keymaster/kdf1_test.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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 "kdf1.h"
+#include <gtest/gtest.h>
+#include <string.h>
+
+#include "android_keymaster_test_utils.h"
+
+using std::string;
+
+namespace keymaster {
+
+namespace test {
+
+struct Kdf1Test {
+    const char* key_hex;
+    const char* expected_output_hex;
+    keymaster_digest_t digest_type;
+};
+
+static const Kdf1Test kKdf1Tests[] = {
+    {"032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d764374152e0ac009e509e7ba30cd2f1778"
+     "e113b64e135cf4e2292c75efe5288edfda4",
+     "5f8de105b5e96b2e490ddecbd147dd1def7e3b8e0e6a26eb7b956ccb8b3bdc1ca975bc57c3989e8fbad31a224655d"
+     "800c46954840ff32052cdf0d640562bdfadfa263cfccf3c52b29f2af4a1869959bc77f854cf15bd7a25192985a842"
+     "dbff8e13efee5b7e7e55bbe4d389647c686a9a9ab3fb889b2d7767d3837eea4e0a2f04",
+     KM_DIGEST_SHA1}};
+
+TEST(Kdf1Test, Kdf1) {
+    for (auto& test : kKdf1Tests) {
+        const string key = hex2str(test.key_hex);
+        const string expected_output = hex2str(test.expected_output_hex);
+        size_t output_len = expected_output.size();
+        uint8_t output[output_len];
+
+        Kdf1 kdf1;
+        ASSERT_TRUE(
+            kdf1.Init(test.digest_type, reinterpret_cast<const uint8_t*>(key.data()), key.size()));
+        ASSERT_TRUE(kdf1.GenerateKey(nullptr, 0, output, output_len));
+        EXPECT_EQ(0, memcmp(output, expected_output.data(), output_len));
+    }
+}
+
+}  // namespace test
+
+}  // namespace keymaster
diff --git a/keymaster/kdf2.h b/keymaster/kdf2.h
new file mode 100644
index 0000000..1df97ef
--- /dev/null
+++ b/keymaster/kdf2.h
@@ -0,0 +1,40 @@
+/*
+ * 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_KDF2_H_
+#define SYSTEM_KEYMASTER_KDF2_H_
+
+#include "iso18033kdf.h"
+
+#include <hardware/keymaster_defs.h>
+
+#include <keymaster/serializable.h>
+
+#include <UniquePtr.h>
+
+namespace keymaster {
+
+/**
+ * Kdf2 is instance of Iso18033Kdf when the counter starts at 1.
+ */
+class Kdf2 : public Iso18033Kdf {
+  public:
+    Kdf2() : Iso18033Kdf(1) {}
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_KDF2_H_
diff --git a/keymaster/kdf2_test.cpp b/keymaster/kdf2_test.cpp
new file mode 100644
index 0000000..29ff40a
--- /dev/null
+++ b/keymaster/kdf2_test.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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 "kdf2.h"
+#include <gtest/gtest.h>
+#include <string.h>
+
+#include "android_keymaster_test_utils.h"
+
+using std::string;
+
+namespace keymaster {
+
+namespace test {
+
+struct Kdf2Test {
+    const char* key_hex;
+    const char* info_hex;
+    const char* expected_output_hex;
+    keymaster_digest_t digest_type;
+};
+
+static const Kdf2Test kKdf2Tests[] = {
+    {"032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d764374152e0ac009e509e7ba30cd2f1778"
+     "e113b64e135cf4e2292c75efe5288edfda4",
+     "",
+     "10a2403db42a8743cb989de86e668d168cbe6046e23ff26f741e87949a3bba1311ac179f819a3d18412e9eb45668f"
+     "2923c087c1299005f8d5fd42ca257bc93e8fee0c5a0d2a8aa70185401fbbd99379ec76c663e9a29d0b70f3fe261a5"
+     "9cdc24875a60b4aacb1319fa11c3365a8b79a44669f26fba933d012db213d7e3b16349",
+     KM_DIGEST_SHA_2_256},
+    {"032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d764374152e0ac009e509e7ba30cd2f1778"
+     "e113b64e135cf4e2292c75efe5288edfda4",
+     "",
+     "0e6a26eb7b956ccb8b3bdc1ca975bc57c3989e8fbad31a224655d800c46954840ff32052cdf0d640562bdfadfa263"
+     "cfccf3c52b29f2af4a1869959bc77f854cf15bd7a25192985a842dbff8e13efee5b7e7e55bbe4d389647c686a9a9a"
+     "b3fb889b2d7767d3837eea4e0a2f04b53ca8f50fb31225c1be2d0126c8c7a4753b0807",
+     KM_DIGEST_SHA1},
+    {"CA7C0F8C3FFA87A96E1B74AC8E6AF594347BB40A", "", "744AB703F5BC082E59185F6D049D2D367DB245C2",
+     KM_DIGEST_SHA1},
+    {"0499B502FC8B5BAFB0F4047E731D1F9FD8CD0D8881", "",
+     "03C62280C894E103C680B13CD4B4AE740A5EF0C72547292F82DC6B1777F47D63BA9D1EA73"
+     "2DBF386",
+     KM_DIGEST_SHA1},
+    {"5E10B967A95606853E528F04262AD18A4767C761163971391E17CB05A21668D4CE2B9F151617408042CE091958382"
+     "3FD346D1751FBE2341AF2EE0461B62F100FFAD4F723F70C18B38238ED183E9398C8CA517EE0CBBEFFF9C59471FE27"
+     "8093924089480DBC5A38E9A1A97D23038106847D0D22ECF85F49A861821199BAFCB0D74E6ACFFD7D142765EBF4C71"
+     "2414FE4B6AB957F4CB466B46601289BB82060428272842EE28F113CD11F39431CBFFD823254CE472E2105E49B3D7F"
+     "113B825076E6264585807BC46454665F27C5E4E1A4BD03470486322981FDC894CCA1E2930987C92C15A38BC42EB38"
+     "810E867C4432F07259EC00CDBBB0FB99E1727C706DA58DD",
+     "484D4143204B6579", "BC98EB018CB00EE26D1F97A15AE166912A7AC4C5", KM_DIGEST_SHA1},
+
+};
+
+TEST(Kdf2Test, Kdf2) {
+    for (auto& test : kKdf2Tests) {
+        const string key = hex2str(test.key_hex);
+        const string info = hex2str(test.info_hex);
+        const string expected_output = hex2str(test.expected_output_hex);
+        size_t output_len = expected_output.size();
+        uint8_t output[output_len];
+
+        Kdf2 kdf2;
+        ASSERT_TRUE(
+            kdf2.Init(test.digest_type, reinterpret_cast<const uint8_t*>(key.data()), key.size()));
+        ASSERT_TRUE(kdf2.GenerateKey(reinterpret_cast<const uint8_t*>(info.data()), info.size(),
+                                     output, output_len));
+        EXPECT_EQ(0, memcmp(output, expected_output.data(), output_len));
+    }
+}
+
+}  // namespace test
+
+}  // namespace keymaster
diff --git a/keymaster/kdf_test.cpp b/keymaster/kdf_test.cpp
new file mode 100644
index 0000000..f6f4a93
--- /dev/null
+++ b/keymaster/kdf_test.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 "kdf.h"
+#include <gtest/gtest.h>
+
+namespace keymaster {
+
+namespace test {
+
+class ForTestAbstractKdf : public Kdf {
+    bool GenerateKey(const uint8_t* /* info */, size_t /* info_len */, uint8_t* /* output */,
+                     size_t /* output_len */) {
+        return true;
+    }
+};
+
+TEST(KdfTest, Kdf) {
+    ForTestAbstractKdf kdf;
+    uint8_t key[128];
+    uint8_t salt[128];
+    ASSERT_TRUE(kdf.Init(KM_DIGEST_SHA1, key, 128, salt, 128));
+    ASSERT_TRUE(kdf.Init(KM_DIGEST_SHA_2_256, key, 128, salt, 128));
+    ASSERT_TRUE(kdf.Init(KM_DIGEST_SHA1, key, 128, nullptr, 0));
+    ASSERT_FALSE(kdf.Init(KM_DIGEST_MD5, key, 128, salt, 128));
+    ASSERT_FALSE(kdf.Init(KM_DIGEST_SHA1, nullptr, 0, salt, 128));
+    ASSERT_FALSE(kdf.Init(KM_DIGEST_SHA1, nullptr, 128, salt, 128));
+    ASSERT_FALSE(kdf.Init(KM_DIGEST_SHA1, key, 0, salt, 128));
+}
+
+}  // namespace test
+
+}  // namespace keymaster
diff --git a/keymaster/kem.h b/keymaster/kem.h
new file mode 100644
index 0000000..f2fa073
--- /dev/null
+++ b/keymaster/kem.h
@@ -0,0 +1,54 @@
+/*
+ * 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_KEM_H_
+#define SYSTEM_KEYMASTER_KEM_H_
+
+#include <keymaster/serializable.h>
+
+#include "openssl_utils.h"
+
+namespace keymaster {
+
+// Kem is an abstract class that provides an interface to a key encapsulation
+// mechansim primitive. A key encapsulation mechanism works just like a
+// public-key encryption scheme, except that the encryption algorithm takes no
+// input other than the recipient’s public key. Instead, the encryption algorithm
+// generates a pair (K, C0), where K is a bit string of some specified length,
+// and C0 is an encryption of K, that is, the decryption algorithm applied to C0
+// yields K.
+class Kem {
+  public:
+    virtual ~Kem(){};
+
+    // For a key encapsulation mechanism, the goal of encryption is to take the recipient's public
+    // key, and to generate a pair (K, C0), where K is a bit string of some specified length,
+    // and C0 is an encryption of K.
+    virtual bool Encrypt(const Buffer& peer_public_value, Buffer* output_clear_key,
+                         Buffer* output_encrypted_key) = 0;
+    virtual bool Encrypt(const uint8_t* peer_public_value, size_t peer_public_value_len,
+                         Buffer* output_clear_key, Buffer* output_encrypted_key) = 0;
+
+    // Decrypt takes an encrypted key, and outputs its clear text.
+    // Decrypt takes ownership of \p private_key.
+    virtual bool Decrypt(EC_KEY* private_key, const Buffer& encrypted_key, Buffer* output_key) = 0;
+    virtual bool Decrypt(EC_KEY* private_key, const uint8_t* encrypted_key,
+                         size_t encrypted_key_len, Buffer* output_key) = 0;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_KEM_H_
diff --git a/keymaster/key.cpp b/keymaster/key.cpp
new file mode 100644
index 0000000..eb828e1
--- /dev/null
+++ b/keymaster/key.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "key.h"
+
+#include <openssl/x509.h>
+
+#include "openssl_utils.h"
+
+namespace keymaster {
+
+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/keymaster/key.h b/keymaster/key.h
new file mode 100644
index 0000000..9fb4063
--- /dev/null
+++ b/keymaster/key.h
@@ -0,0 +1,63 @@
+/*
+ * 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_H_
+#define SYSTEM_KEYMASTER_KEY_H_
+
+#include <UniquePtr.h>
+
+#include <hardware/keymaster_defs.h>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/keymaster_context.h>
+
+namespace keymaster {
+
+class Key {
+  public:
+    virtual ~Key() {}
+
+    /**
+     * 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 = 0;
+
+    /**
+     * Generate an attestation certificate chain.
+     */
+    virtual keymaster_error_t GenerateAttestation(
+        const KeymasterContext& /* context */, const AuthorizationSet& /* attest_params */,
+        const AuthorizationSet& /* tee_enforced */, const AuthorizationSet& /* sw_enforced */,
+        keymaster_cert_chain_t* /* certificate_chain */) const {
+        return KM_ERROR_INCOMPATIBLE_ALGORITHM;
+    }
+
+    const AuthorizationSet& authorizations() const { return authorizations_; }
+
+  protected:
+    Key(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+        keymaster_error_t* error);
+
+  private:
+    AuthorizationSet authorizations_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_KEY_H_
diff --git a/keymaster/key_blob_test.cpp b/keymaster/key_blob_test.cpp
new file mode 100644
index 0000000..1e590f0
--- /dev/null
+++ b/keymaster/key_blob_test.cpp
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 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 <algorithm>
+
+#include <gtest/gtest.h>
+
+#include <openssl/engine.h>
+#include <openssl/rand.h>
+
+#include <keymaster/authorization_set.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/keymaster_tags.h>
+
+#include "android_keymaster_test_utils.h"
+#include "auth_encrypted_key_blob.h"
+#include "integrity_assured_key_blob.h"
+#include "ocb_utils.h"
+
+namespace keymaster {
+
+namespace test {
+
+const uint8_t master_key_data[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+const uint8_t key_data[5] = {21, 22, 23, 24, 25};
+
+class KeyBlobTest : public testing::Test {
+  protected:
+    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);
+
+        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);
+
+        hidden_.push_back(TAG_ROOT_OF_TRUST, "foo", 3);
+        hidden_.push_back(TAG_APPLICATION_ID, "my_app", 6);
+
+        nonce_.reserve(OCB_NONCE_LENGTH);
+        EXPECT_EQ(1, RAND_bytes(nonce_.peek_write(), OCB_NONCE_LENGTH));
+        nonce_.advance_write(OCB_NONCE_LENGTH);
+
+        tag_.reserve(OCB_TAG_LENGTH);
+    }
+
+    keymaster_error_t Encrypt() {
+        return OcbEncryptKey(hw_enforced_, sw_enforced_, hidden_, master_key_, key_material_,
+                             nonce_, &ciphertext_, &tag_);
+    }
+
+    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) {
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
+
+    // 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()));
+
+    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) {
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
+
+    // Modify the key length, shouldn't be able to parse.
+    serialized_blob_.writable_data()[1 /* version */ + 4 /* nonce len */ + 12 /* nonce */ + 3]++;
+
+    ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Deserialize());
+}
+
+TEST_F(KeyBlobTest, WrongNonce) {
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
+
+    // Find the nonce, then modify it.
+    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))++;
+
+    // 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) {
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
+
+    // Find the tag, them modify it.
+    auto 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))++;
+
+    // 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) {
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
+
+    // Find the ciphertext, them modify it.
+    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))++;
+
+    // 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) {
+    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.
+    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, WrongHwEnforced) {
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
+
+    // Find enforced serialization data and modify it.
+    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 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))++;
+
+    // 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, WrongSwEnforced) {
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
+
+    // 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 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))++;
+
+    // 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) {
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
+
+    AuthorizationSet wrong_hidden;
+
+    // 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) {
+    ASSERT_EQ(KM_ERROR_OK, Encrypt());
+    ASSERT_EQ(KM_ERROR_OK, Serialize());
+
+    AuthorizationSet wrong_hidden;
+    wrong_hidden.push_back(TAG_ROOT_OF_TRUST, "bar", 2);
+    wrong_hidden.push_back(TAG_APPLICATION_ID, "my_app", 6);
+
+    // 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) {
+    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);
+
+    // 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_));
+}
+
+// This test is especially useful when compiled for 32-bit mode and run under valgrind.
+TEST_F(KeyBlobTest, FuzzTest) {
+    time_t now = time(NULL);
+    std::cout << "Seeding rand() with " << now << " for fuzz test." << std::endl;
+    srand(now);
+
+    // Fill large buffer with random bytes.
+    const int kBufSize = 10000;
+    UniquePtr<uint8_t[]> buf(new uint8_t[kBufSize]);
+    for (size_t i = 0; i < kBufSize; ++i)
+        buf[i] = static_cast<uint8_t>(rand());
+
+    // Try to deserialize every offset with multiple methods.
+    size_t deserialize_auth_encrypted_success = 0;
+    for (size_t i = 0; i < kBufSize; ++i) {
+        keymaster_key_blob_t blob = {buf.get() + i, kBufSize - i};
+        KeymasterKeyBlob key_blob(blob);
+
+        // Integrity-assured blob.
+        ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+                  DeserializeIntegrityAssuredBlob(key_blob, hidden_, &key_material_, &hw_enforced_,
+                                                  &sw_enforced_));
+
+        // Auth-encrypted OCB blob.
+        keymaster_error_t error = DeserializeAuthEncryptedBlob(
+            key_blob, &ciphertext_, &hw_enforced_, &sw_enforced_, &nonce_, &tag_);
+        if (error == KM_ERROR_OK) {
+            // It's possible to deserialize successfully.  Decryption should always fail.
+            ++deserialize_auth_encrypted_success;
+            error = OcbDecryptKey(hw_enforced_, sw_enforced_, hidden_, master_key_, ciphertext_,
+                                  nonce_, tag_, &decrypted_plaintext_);
+        }
+        ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, error)
+            << "Somehow sucessfully parsed a blob with seed " << now << " at offset " << i;
+    }
+}
+
+TEST_F(KeyBlobTest, UnderflowTest) {
+    uint8_t buf[0];
+    keymaster_key_blob_t blob = {buf, 0};
+    KeymasterKeyBlob key_blob(blob);
+    EXPECT_NE(nullptr, key_blob.key_material);
+    EXPECT_EQ(0U, key_blob.key_material_size);
+
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+              DeserializeIntegrityAssuredBlob(key_blob, hidden_, &key_material_, &hw_enforced_,
+                                              &sw_enforced_));
+
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+              DeserializeAuthEncryptedBlob(key_blob, &ciphertext_, &hw_enforced_, &sw_enforced_,
+                                           &nonce_, &tag_));
+}
+
+TEST_F(KeyBlobTest, DupBufferToolarge) {
+    uint8_t buf[0];
+    keymaster_key_blob_t blob = {buf, 0};
+    blob.key_material_size = 16 * 1024 * 1024 + 1;
+    KeymasterKeyBlob key_blob(blob);
+    EXPECT_EQ(nullptr, key_blob.key_material);
+    EXPECT_EQ(0U, key_blob.key_material_size);
+
+    ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+              DeserializeIntegrityAssuredBlob(key_blob, hidden_, &key_material_, &hw_enforced_,
+                                              &sw_enforced_));
+
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+              DeserializeAuthEncryptedBlob(key_blob, &ciphertext_, &hw_enforced_, &sw_enforced_,
+                                           &nonce_, &tag_));
+}
+
+}  // namespace test
+}  // namespace keymaster
diff --git a/keymaster/key_exchange.h b/keymaster/key_exchange.h
new file mode 100644
index 0000000..1019e20
--- /dev/null
+++ b/keymaster/key_exchange.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_KEY_EXCHANGE_H_
+#define SYSTEM_KEYMASTER_KEY_EXCHANGE_H_
+
+#include <openssl/ec.h>
+
+#include <keymaster/serializable.h>
+
+namespace keymaster {
+
+/**
+ * KeyExchange is an abstract class that provides an interface to a
+ * key-exchange primitive.
+ */
+class KeyExchange {
+  public:
+    virtual ~KeyExchange() {}
+
+    /**
+     * CalculateSharedKey computes the shared key between the local private key
+     * (which is implicitly known by a KeyExchange object) and a public value
+     * from the peer.
+     */
+    virtual bool CalculateSharedKey(const Buffer& peer_public_value, Buffer* shared_key) const = 0;
+    virtual bool CalculateSharedKey(const uint8_t* peer_public_value, size_t peer_public_value_len,
+                                    Buffer* shared_key) const = 0;
+
+    /**
+     * public_value writes to |public_value| the local public key which can be
+     * sent to a peer in order to complete a key exchange.
+     */
+    virtual bool public_value(Buffer* public_value) const = 0;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_KEY_EXCHANGE_H_
diff --git a/keymaster/keymaster0_engine.cpp b/keymaster/keymaster0_engine.cpp
new file mode 100644
index 0000000..bcd64e5
--- /dev/null
+++ b/keymaster/keymaster0_engine.cpp
@@ -0,0 +1,400 @@
+/*
+ * 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 "keymaster0_engine.h"
+
+#include <assert.h>
+
+#include <memory>
+
+#define LOG_TAG "Keymaster0Engine"
+#include <cutils/log.h>
+
+#include "keymaster/android_keymaster_utils.h"
+
+#include <openssl/bn.h>
+#include <openssl/ec_key.h>
+#include <openssl/ecdsa.h>
+
+#include "openssl_utils.h"
+
+using std::shared_ptr;
+using std::unique_ptr;
+
+namespace keymaster {
+
+Keymaster0Engine* Keymaster0Engine::instance_ = nullptr;
+
+Keymaster0Engine::Keymaster0Engine(const keymaster0_device_t* keymaster0_device)
+    : keymaster0_device_(keymaster0_device), engine_(ENGINE_new()), supports_ec_(false) {
+    assert(!instance_);
+    instance_ = this;
+
+    rsa_index_ = RSA_get_ex_new_index(0 /* argl */, NULL /* argp */, NULL /* new_func */,
+                                      keyblob_dup, keyblob_free);
+    ec_key_index_ = EC_KEY_get_ex_new_index(0 /* argl */, NULL /* argp */, NULL /* new_func */,
+                                            keyblob_dup, keyblob_free);
+
+    rsa_method_.common.references = 0;
+    rsa_method_.common.is_static = 1;
+    rsa_method_.app_data = nullptr;
+    rsa_method_.init = nullptr;
+    rsa_method_.finish = nullptr;
+    rsa_method_.size = nullptr;
+    rsa_method_.sign = nullptr;
+    rsa_method_.verify = nullptr;
+    rsa_method_.encrypt = nullptr;
+    rsa_method_.sign_raw = nullptr;
+    rsa_method_.decrypt = nullptr;
+    rsa_method_.verify_raw = nullptr;
+    rsa_method_.private_transform = Keymaster0Engine::rsa_private_transform;
+    rsa_method_.mod_exp = nullptr;
+    rsa_method_.bn_mod_exp = BN_mod_exp_mont;
+    rsa_method_.flags = RSA_FLAG_OPAQUE;
+    rsa_method_.keygen = nullptr;
+    rsa_method_.supports_digest = nullptr;
+
+    ENGINE_set_RSA_method(engine_, &rsa_method_, sizeof(rsa_method_));
+
+    if ((keymaster0_device_->flags & KEYMASTER_SUPPORTS_EC) != 0) {
+        supports_ec_ = true;
+
+        ecdsa_method_.common.references = 0;
+        ecdsa_method_.common.is_static = 1;
+        ecdsa_method_.app_data = nullptr;
+        ecdsa_method_.init = nullptr;
+        ecdsa_method_.finish = nullptr;
+        ecdsa_method_.group_order_size = nullptr;
+        ecdsa_method_.sign = Keymaster0Engine::ecdsa_sign;
+        ecdsa_method_.verify = nullptr;
+        ecdsa_method_.flags = ECDSA_FLAG_OPAQUE;
+
+        ENGINE_set_ECDSA_method(engine_, &ecdsa_method_, sizeof(ecdsa_method_));
+    }
+}
+
+Keymaster0Engine::~Keymaster0Engine() {
+    if (keymaster0_device_)
+        keymaster0_device_->common.close(
+            reinterpret_cast<hw_device_t*>(const_cast<keymaster0_device_t*>(keymaster0_device_)));
+    ENGINE_free(engine_);
+    instance_ = nullptr;
+}
+
+bool Keymaster0Engine::GenerateRsaKey(uint64_t public_exponent, uint32_t public_modulus,
+                                      KeymasterKeyBlob* key_material) const {
+    assert(key_material);
+    keymaster_rsa_keygen_params_t params;
+    params.public_exponent = public_exponent;
+    params.modulus_size = public_modulus;
+
+    uint8_t* key_blob = 0;
+    if (keymaster0_device_->generate_keypair(keymaster0_device_, TYPE_RSA, &params, &key_blob,
+                                             &key_material->key_material_size) < 0) {
+        ALOGE("Error generating RSA key pair with keymaster0 device");
+        return false;
+    }
+    unique_ptr<uint8_t, Malloc_Delete> key_blob_deleter(key_blob);
+    key_material->key_material = dup_buffer(key_blob, key_material->key_material_size);
+    return true;
+}
+
+bool Keymaster0Engine::GenerateEcKey(uint32_t key_size, KeymasterKeyBlob* key_material) const {
+    assert(key_material);
+    keymaster_ec_keygen_params_t params;
+    params.field_size = key_size;
+
+    uint8_t* key_blob = 0;
+    if (keymaster0_device_->generate_keypair(keymaster0_device_, TYPE_EC, &params, &key_blob,
+                                             &key_material->key_material_size) < 0) {
+        ALOGE("Error generating EC key pair with keymaster0 device");
+        return false;
+    }
+    unique_ptr<uint8_t, Malloc_Delete> key_blob_deleter(key_blob);
+    key_material->key_material = dup_buffer(key_blob, key_material->key_material_size);
+    return true;
+}
+
+bool Keymaster0Engine::ImportKey(keymaster_key_format_t key_format,
+                                 const KeymasterKeyBlob& to_import,
+                                 KeymasterKeyBlob* imported_key) const {
+    assert(imported_key);
+    if (key_format != KM_KEY_FORMAT_PKCS8)
+        return false;
+
+    uint8_t* key_blob = 0;
+    if (keymaster0_device_->import_keypair(keymaster0_device_, to_import.key_material,
+                                           to_import.key_material_size, &key_blob,
+                                           &imported_key->key_material_size) < 0) {
+        ALOGW("Error importing keypair with keymaster0 device");
+        return false;
+    }
+    unique_ptr<uint8_t, Malloc_Delete> key_blob_deleter(key_blob);
+    imported_key->key_material = dup_buffer(key_blob, imported_key->key_material_size);
+    return true;
+}
+
+bool Keymaster0Engine::DeleteKey(const KeymasterKeyBlob& blob) const {
+    if (!keymaster0_device_->delete_keypair)
+        return true;
+    return (keymaster0_device_->delete_keypair(keymaster0_device_, blob.key_material,
+                                               blob.key_material_size) == 0);
+}
+
+bool Keymaster0Engine::DeleteAllKeys() const {
+    if (!keymaster0_device_->delete_all)
+        return true;
+    return (keymaster0_device_->delete_all(keymaster0_device_) == 0);
+}
+
+static keymaster_key_blob_t* duplicate_blob(const uint8_t* key_data, size_t key_data_size) {
+    unique_ptr<uint8_t[]> key_material_copy(dup_buffer(key_data, key_data_size));
+    if (!key_material_copy)
+        return nullptr;
+
+    unique_ptr<keymaster_key_blob_t> blob_copy(new (std::nothrow) keymaster_key_blob_t);
+    if (!blob_copy.get())
+        return nullptr;
+    blob_copy->key_material_size = key_data_size;
+    blob_copy->key_material = key_material_copy.release();
+    return blob_copy.release();
+}
+
+inline keymaster_key_blob_t* duplicate_blob(const keymaster_key_blob_t& blob) {
+    return duplicate_blob(blob.key_material, blob.key_material_size);
+}
+
+RSA* Keymaster0Engine::BlobToRsaKey(const KeymasterKeyBlob& blob) const {
+    // Create new RSA key (with engine methods) and insert blob
+    unique_ptr<RSA, RSA_Delete> rsa(RSA_new_method(engine_));
+    if (!rsa)
+        return nullptr;
+
+    keymaster_key_blob_t* blob_copy = duplicate_blob(blob);
+    if (!blob_copy->key_material || !RSA_set_ex_data(rsa.get(), rsa_index_, blob_copy))
+        return nullptr;
+
+    // Copy public key into new RSA key
+    unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(GetKeymaster0PublicKey(blob));
+    if (!pkey)
+        return nullptr;
+    unique_ptr<RSA, RSA_Delete> public_rsa(EVP_PKEY_get1_RSA(pkey.get()));
+    if (!public_rsa)
+        return nullptr;
+    rsa->n = BN_dup(public_rsa->n);
+    rsa->e = BN_dup(public_rsa->e);
+    if (!rsa->n || !rsa->e)
+        return nullptr;
+
+    return rsa.release();
+}
+
+EC_KEY* Keymaster0Engine::BlobToEcKey(const KeymasterKeyBlob& blob) const {
+    // Create new EC key (with engine methods) and insert blob
+    unique_ptr<EC_KEY, EC_KEY_Delete> ec_key(EC_KEY_new_method(engine_));
+    if (!ec_key)
+        return nullptr;
+
+    keymaster_key_blob_t* blob_copy = duplicate_blob(blob);
+    if (!blob_copy->key_material || !EC_KEY_set_ex_data(ec_key.get(), ec_key_index_, blob_copy))
+        return nullptr;
+
+    // Copy public key into new EC key
+    unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(GetKeymaster0PublicKey(blob));
+    if (!pkey)
+        return nullptr;
+
+    unique_ptr<EC_KEY, EC_KEY_Delete> public_ec_key(EVP_PKEY_get1_EC_KEY(pkey.get()));
+    if (!public_ec_key)
+        return nullptr;
+
+    if (!EC_KEY_set_group(ec_key.get(), EC_KEY_get0_group(public_ec_key.get())) ||
+        !EC_KEY_set_public_key(ec_key.get(), EC_KEY_get0_public_key(public_ec_key.get())))
+        return nullptr;
+
+    return ec_key.release();
+}
+
+const keymaster_key_blob_t* Keymaster0Engine::RsaKeyToBlob(const RSA* rsa) const {
+    return reinterpret_cast<keymaster_key_blob_t*>(RSA_get_ex_data(rsa, rsa_index_));
+}
+
+const keymaster_key_blob_t* Keymaster0Engine::EcKeyToBlob(const EC_KEY* ec_key) const {
+    return reinterpret_cast<keymaster_key_blob_t*>(EC_KEY_get_ex_data(ec_key, ec_key_index_));
+}
+
+/* static */
+int Keymaster0Engine::keyblob_dup(CRYPTO_EX_DATA* /* to */, const CRYPTO_EX_DATA* /* from */,
+                                  void** from_d, int /* index */, long /* argl */,
+                                  void* /* argp */) {
+    keymaster_key_blob_t* blob = reinterpret_cast<keymaster_key_blob_t*>(*from_d);
+    if (!blob)
+        return 1;
+    *from_d = duplicate_blob(*blob);
+    if (*from_d)
+        return 1;
+    return 0;
+}
+
+/* static */
+void Keymaster0Engine::keyblob_free(void* /* parent */, void* ptr, CRYPTO_EX_DATA* /* data */,
+                                    int /* index*/, long /* argl */, void* /* argp */) {
+    keymaster_key_blob_t* blob = reinterpret_cast<keymaster_key_blob_t*>(ptr);
+    if (blob) {
+        delete[] blob->key_material;
+        delete blob;
+    }
+}
+
+/* static */
+int Keymaster0Engine::rsa_private_transform(RSA* rsa, uint8_t* out, const uint8_t* in, size_t len) {
+    ALOGV("rsa_private_transform(%p, %p, %p, %u)", rsa, out, in, (unsigned)len);
+
+    assert(instance_);
+    return instance_->RsaPrivateTransform(rsa, out, in, len);
+}
+
+/* static */
+int Keymaster0Engine::ecdsa_sign(const uint8_t* digest, size_t digest_len, uint8_t* sig,
+                                 unsigned int* sig_len, EC_KEY* ec_key) {
+    ALOGV("ecdsa_sign(%p, %u, %p)", digest, (unsigned)digest_len, ec_key);
+    assert(instance_);
+    return instance_->EcdsaSign(digest, digest_len, sig, sig_len, ec_key);
+}
+
+bool Keymaster0Engine::Keymaster0Sign(const void* signing_params, const keymaster_key_blob_t& blob,
+                                      const uint8_t* data, const size_t data_length,
+                                      unique_ptr<uint8_t[], Malloc_Delete>* signature,
+                                      size_t* signature_length) const {
+    uint8_t* signed_data;
+    int err = keymaster0_device_->sign_data(keymaster0_device_, signing_params, blob.key_material,
+                                            blob.key_material_size, data, data_length, &signed_data,
+                                            signature_length);
+    if (err < 0) {
+        ALOGE("Keymaster0 signing failed with error %d", err);
+        return false;
+    }
+
+    signature->reset(signed_data);
+    return true;
+}
+
+EVP_PKEY* Keymaster0Engine::GetKeymaster0PublicKey(const KeymasterKeyBlob& blob) const {
+    uint8_t* pub_key_data;
+    size_t pub_key_data_length;
+    int err = keymaster0_device_->get_keypair_public(keymaster0_device_, blob.key_material,
+                                                     blob.key_material_size, &pub_key_data,
+                                                     &pub_key_data_length);
+    if (err < 0) {
+        ALOGE("Error %d extracting public key", err);
+        return nullptr;
+    }
+    unique_ptr<uint8_t, Malloc_Delete> pub_key(pub_key_data);
+
+    const uint8_t* p = pub_key_data;
+    return d2i_PUBKEY(nullptr /* allocate new struct */, &p, pub_key_data_length);
+}
+
+static bool data_too_large_for_public_modulus(const uint8_t* data, size_t len, const RSA* rsa) {
+    unique_ptr<BIGNUM, BIGNUM_Delete> input_as_bn(
+        BN_bin2bn(data, len, nullptr /* allocate result */));
+    return input_as_bn && BN_ucmp(input_as_bn.get(), rsa->n) >= 0;
+}
+
+int Keymaster0Engine::RsaPrivateTransform(RSA* rsa, uint8_t* out, const uint8_t* in,
+                                          size_t len) const {
+    const keymaster_key_blob_t* key_blob = RsaKeyToBlob(rsa);
+    if (key_blob == NULL) {
+        ALOGE("key had no key_blob!");
+        return 0;
+    }
+
+    keymaster_rsa_sign_params_t sign_params = {DIGEST_NONE, PADDING_NONE};
+    unique_ptr<uint8_t[], Malloc_Delete> signature;
+    size_t signature_length;
+    if (!Keymaster0Sign(&sign_params, *key_blob, in, len, &signature, &signature_length)) {
+        if (data_too_large_for_public_modulus(in, len, rsa)) {
+            ALOGE("Keymaster0 signing failed because data is too large.");
+            OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
+        } else {
+            // We don't know what error code is correct; force an "unknown error" return
+            OPENSSL_PUT_ERROR(USER, KM_ERROR_UNKNOWN_ERROR);
+        }
+        return 0;
+    }
+    Eraser eraser(signature.get(), signature_length);
+
+    if (signature_length > len) {
+        /* The result of the RSA operation can never be larger than the size of
+         * the modulus so we assume that the result has extra zeros on the
+         * left. This provides attackers with an oracle, but there's nothing
+         * that we can do about it here. */
+        memcpy(out, signature.get() + signature_length - len, len);
+    } else if (signature_length < len) {
+        /* If the keymaster0 implementation returns a short value we assume that
+         * it's because it removed leading zeros from the left side. This is
+         * bad because it provides attackers with an oracle but we cannot do
+         * anything about a broken keymaster0 implementation here. */
+        memset(out, 0, len);
+        memcpy(out + len - signature_length, signature.get(), signature_length);
+    } else {
+        memcpy(out, signature.get(), len);
+    }
+
+    ALOGV("rsa=%p keystore_rsa_priv_dec successful", rsa);
+    return 1;
+}
+
+int Keymaster0Engine::EcdsaSign(const uint8_t* digest, size_t digest_len, uint8_t* sig,
+                                unsigned int* sig_len, EC_KEY* ec_key) const {
+    const keymaster_key_blob_t* key_blob = EcKeyToBlob(ec_key);
+    if (key_blob == NULL) {
+        ALOGE("key had no key_blob!");
+        return 0;
+    }
+
+    // Truncate digest if it's too long
+    size_t max_input_len = (ec_group_size_bits(ec_key) + 7) / 8;
+    if (digest_len > max_input_len)
+        digest_len = max_input_len;
+
+    keymaster_ec_sign_params_t sign_params = {DIGEST_NONE};
+    unique_ptr<uint8_t[], Malloc_Delete> signature;
+    size_t signature_length;
+    if (!Keymaster0Sign(&sign_params, *key_blob, digest, digest_len, &signature,
+                        &signature_length)) {
+        // We don't know what error code is correct; force an "unknown error" return
+        OPENSSL_PUT_ERROR(USER, KM_ERROR_UNKNOWN_ERROR);
+        return 0;
+    }
+    Eraser eraser(signature.get(), signature_length);
+
+    if (signature_length == 0) {
+        ALOGW("No valid signature returned");
+        return 0;
+    } else if (signature_length > ECDSA_size(ec_key)) {
+        ALOGW("Signature is too large");
+        return 0;
+    } else {
+        memcpy(sig, signature.get(), signature_length);
+        *sig_len = signature_length;
+    }
+
+    ALOGV("ecdsa_sign(%p, %u, %p) => success", digest, (unsigned)digest_len, ec_key);
+    return 1;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/keymaster0_engine.h b/keymaster/keymaster0_engine.h
new file mode 100644
index 0000000..aedd85c
--- /dev/null
+++ b/keymaster/keymaster0_engine.h
@@ -0,0 +1,103 @@
+/*
+ * 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_KEYMASTER0_ENGINE_H_
+#define SYSTEM_KEYMASTER_KEYMASTER0_ENGINE_H_
+
+#include <memory>
+
+#include <openssl/ec.h>
+#include <openssl/engine.h>
+#include <openssl/ex_data.h>
+#include <openssl/rsa.h>
+
+#include <hardware/keymaster0.h>
+#include <hardware/keymaster_defs.h>
+
+namespace keymaster {
+
+struct KeymasterKeyBlob;
+
+/* Keymaster0Engine is a BoringSSL ENGINE that implements RSA & EC by forwarding the requested
+ * operations to a keymaster0 module. */
+class Keymaster0Engine {
+  public:
+    /**
+     * Create a Keymaster0Engine, wrapping the provided keymaster0_device.  The engine takes
+     * ownership of the device, and will close it during destruction.
+     */
+    explicit Keymaster0Engine(const keymaster0_device_t* keymaster0_device);
+    ~Keymaster0Engine();
+
+    bool supports_ec() const { return supports_ec_; }
+
+    bool GenerateRsaKey(uint64_t public_exponent, uint32_t public_modulus,
+                        KeymasterKeyBlob* key_material) const;
+    bool GenerateEcKey(uint32_t key_size, KeymasterKeyBlob* key_material) const;
+
+    bool ImportKey(keymaster_key_format_t key_format, const KeymasterKeyBlob& to_import,
+                   KeymasterKeyBlob* imported_key_material) const;
+    bool DeleteKey(const KeymasterKeyBlob& blob) const;
+    bool DeleteAllKeys() const;
+
+    RSA* BlobToRsaKey(const KeymasterKeyBlob& blob) const;
+    EC_KEY* BlobToEcKey(const KeymasterKeyBlob& blob) const;
+
+    const keymaster_key_blob_t* RsaKeyToBlob(const RSA* rsa) const;
+    const keymaster_key_blob_t* EcKeyToBlob(const EC_KEY* rsa) const;
+
+    const keymaster0_device_t* device() { return keymaster0_device_; }
+
+    EVP_PKEY* GetKeymaster0PublicKey(const KeymasterKeyBlob& blob) const;
+
+  private:
+    Keymaster0Engine(const Keymaster0Engine&);  // Uncopyable
+    void operator=(const Keymaster0Engine&);    // Unassignable
+
+    static int keyblob_dup(CRYPTO_EX_DATA* to, const CRYPTO_EX_DATA* from, void** from_d, int index,
+                           long argl, void* argp);
+    static void keyblob_free(void* parent, void* ptr, CRYPTO_EX_DATA* data, int index, long argl,
+                             void* argp);
+    static int rsa_private_transform(RSA* rsa, uint8_t* out, const uint8_t* in, size_t len);
+    static int ecdsa_sign(const uint8_t* digest, size_t digest_len, uint8_t* sig,
+                          unsigned int* sig_len, EC_KEY* ec_key);
+
+    struct Malloc_Delete {
+        void operator()(void* p) { free(p); }
+    };
+
+    bool Keymaster0Sign(const void* signing_params, const keymaster_key_blob_t& key_blob,
+                        const uint8_t* data, const size_t data_length,
+                        std::unique_ptr<uint8_t[], Malloc_Delete>* signature,
+                        size_t* signature_length) const;
+
+    int RsaPrivateTransform(RSA* rsa, uint8_t* out, const uint8_t* in, size_t len) const;
+    int EcdsaSign(const uint8_t* digest, size_t digest_len, uint8_t* sig, unsigned int* sig_len,
+                  EC_KEY* ec_key) const;
+
+    const keymaster0_device_t* keymaster0_device_;
+    ENGINE* const engine_;
+    int rsa_index_, ec_key_index_;
+    bool supports_ec_;
+    RSA_METHOD rsa_method_;
+    ECDSA_METHOD ecdsa_method_;
+
+    static Keymaster0Engine* instance_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_KEYMASTER0_ENGINE_H_
diff --git a/keymaster/keymaster1_engine.cpp b/keymaster/keymaster1_engine.cpp
new file mode 100644
index 0000000..b20a434
--- /dev/null
+++ b/keymaster/keymaster1_engine.cpp
@@ -0,0 +1,408 @@
+/*
+ * 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 "keymaster1_engine.h"
+
+#include <assert.h>
+
+#include <algorithm>
+#include <memory>
+
+#define LOG_TAG "Keymaster1Engine"
+#include <cutils/log.h>
+
+#include "keymaster/android_keymaster_utils.h"
+
+#include <openssl/bn.h>
+#include <openssl/ec_key.h>
+#include <openssl/ecdsa.h>
+
+#include "openssl_err.h"
+#include "openssl_utils.h"
+
+using std::shared_ptr;
+using std::unique_ptr;
+
+namespace keymaster {
+
+Keymaster1Engine* Keymaster1Engine::instance_ = nullptr;
+
+Keymaster1Engine::Keymaster1Engine(const keymaster1_device_t* keymaster1_device)
+    : keymaster1_device_(keymaster1_device), engine_(ENGINE_new()),
+      rsa_index_(RSA_get_ex_new_index(0 /* argl */, NULL /* argp */, NULL /* new_func */,
+                                      Keymaster1Engine::duplicate_key_data,
+                                      Keymaster1Engine::free_key_data)),
+      ec_key_index_(EC_KEY_get_ex_new_index(0 /* argl */, NULL /* argp */, NULL /* new_func */,
+                                            Keymaster1Engine::duplicate_key_data,
+                                            Keymaster1Engine::free_key_data)),
+      rsa_method_(BuildRsaMethod()), ecdsa_method_(BuildEcdsaMethod()) {
+    assert(rsa_index_ != -1);
+    assert(ec_key_index_ != -1);
+    assert(keymaster1_device);
+    assert(!instance_);
+
+    instance_ = this;
+
+    ENGINE_set_RSA_method(engine_.get(), &rsa_method_, sizeof(rsa_method_));
+    ENGINE_set_ECDSA_method(engine_.get(), &ecdsa_method_, sizeof(ecdsa_method_));
+}
+
+Keymaster1Engine::~Keymaster1Engine() {
+    keymaster1_device_->common.close(
+        reinterpret_cast<hw_device_t*>(const_cast<keymaster1_device_t*>(keymaster1_device_)));
+    instance_ = nullptr;
+}
+
+static void ConvertCharacteristics(keymaster_key_characteristics_t* characteristics,
+                                   AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) {
+    unique_ptr<keymaster_key_characteristics_t, Characteristics_Delete> characteristics_deleter(
+        characteristics);
+    if (hw_enforced)
+        hw_enforced->Reinitialize(characteristics->hw_enforced);
+    if (sw_enforced)
+        sw_enforced->Reinitialize(characteristics->sw_enforced);
+}
+
+keymaster_error_t Keymaster1Engine::GenerateKey(const AuthorizationSet& key_description,
+                                                KeymasterKeyBlob* key_blob,
+                                                AuthorizationSet* hw_enforced,
+                                                AuthorizationSet* sw_enforced) const {
+    assert(key_blob);
+
+    keymaster_key_characteristics_t* characteristics;
+    keymaster_key_blob_t blob;
+    keymaster_error_t error = keymaster1_device_->generate_key(keymaster1_device_, &key_description,
+                                                               &blob, &characteristics);
+    if (error != KM_ERROR_OK)
+        return error;
+    unique_ptr<uint8_t, Malloc_Delete> blob_deleter(const_cast<uint8_t*>(blob.key_material));
+    key_blob->key_material = dup_buffer(blob.key_material, blob.key_material_size);
+    key_blob->key_material_size = blob.key_material_size;
+
+    ConvertCharacteristics(characteristics, hw_enforced, sw_enforced);
+    return error;
+}
+
+keymaster_error_t Keymaster1Engine::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) const {
+    assert(output_key_blob);
+
+    keymaster_key_characteristics_t* characteristics;
+    const keymaster_blob_t input_key = {input_key_material.key_material,
+                                        input_key_material.key_material_size};
+    keymaster_key_blob_t blob;
+    keymaster_error_t error = keymaster1_device_->import_key(keymaster1_device_, &key_description,
+                                                             input_key_material_format, &input_key,
+                                                             &blob, &characteristics);
+    if (error != KM_ERROR_OK)
+        return error;
+    unique_ptr<uint8_t, Malloc_Delete> blob_deleter(const_cast<uint8_t*>(blob.key_material));
+    output_key_blob->key_material = dup_buffer(blob.key_material, blob.key_material_size);
+    output_key_blob->key_material_size = blob.key_material_size;
+
+    ConvertCharacteristics(characteristics, hw_enforced, sw_enforced);
+    return error;
+}
+
+keymaster_error_t Keymaster1Engine::DeleteKey(const KeymasterKeyBlob& blob) const {
+    if (!keymaster1_device_->delete_key)
+        return KM_ERROR_OK;
+    return keymaster1_device_->delete_key(keymaster1_device_, &blob);
+}
+
+keymaster_error_t Keymaster1Engine::DeleteAllKeys() const {
+    if (!keymaster1_device_->delete_all_keys)
+        return KM_ERROR_OK;
+    return keymaster1_device_->delete_all_keys(keymaster1_device_);
+}
+
+RSA* Keymaster1Engine::BuildRsaKey(const KeymasterKeyBlob& blob,
+                                   const AuthorizationSet& additional_params,
+                                   keymaster_error_t* error) const {
+    // Create new RSA key (with engine methods) and add metadata
+    unique_ptr<RSA, RSA_Delete> rsa(RSA_new_method(engine_.get()));
+    if (!rsa) {
+        *error = TranslateLastOpenSslError();
+        return nullptr;
+    }
+
+    KeyData* key_data = new KeyData(blob, additional_params);
+    if (!RSA_set_ex_data(rsa.get(), rsa_index_, key_data)) {
+        *error = TranslateLastOpenSslError();
+        delete key_data;
+        return nullptr;
+    }
+
+    // Copy public key into new RSA key
+    unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
+        GetKeymaster1PublicKey(key_data->key_material, key_data->begin_params, error));
+    if (!pkey) {
+        *error = TranslateLastOpenSslError();
+        return nullptr;
+    }
+
+    unique_ptr<RSA, RSA_Delete> public_rsa(EVP_PKEY_get1_RSA(pkey.get()));
+    if (!public_rsa) {
+        *error = TranslateLastOpenSslError();
+        return nullptr;
+    }
+
+    rsa->n = BN_dup(public_rsa->n);
+    rsa->e = BN_dup(public_rsa->e);
+    if (!rsa->n || !rsa->e) {
+        *error = TranslateLastOpenSslError();
+        return nullptr;
+    }
+
+    *error = KM_ERROR_OK;
+    return rsa.release();
+}
+
+EC_KEY* Keymaster1Engine::BuildEcKey(const KeymasterKeyBlob& blob,
+                                     const AuthorizationSet& additional_params,
+                                     keymaster_error_t* error) const {
+    // Create new EC key (with engine methods) and insert blob
+    unique_ptr<EC_KEY, EC_KEY_Delete> ec_key(EC_KEY_new_method(engine_.get()));
+    if (!ec_key) {
+        *error = TranslateLastOpenSslError();
+        return nullptr;
+    }
+
+    KeyData* key_data = new KeyData(blob, additional_params);
+    if (!EC_KEY_set_ex_data(ec_key.get(), ec_key_index_, key_data)) {
+        *error = TranslateLastOpenSslError();
+        delete key_data;
+        return nullptr;
+    }
+
+    // Copy public key into new EC key
+    unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
+        GetKeymaster1PublicKey(blob, additional_params, error));
+    if (!pkey) {
+        *error = TranslateLastOpenSslError();
+        return nullptr;
+    }
+
+    unique_ptr<EC_KEY, EC_KEY_Delete> public_ec_key(EVP_PKEY_get1_EC_KEY(pkey.get()));
+    if (!public_ec_key) {
+        *error = TranslateLastOpenSslError();
+        return nullptr;
+    }
+
+    if (!EC_KEY_set_group(ec_key.get(), EC_KEY_get0_group(public_ec_key.get())) ||
+        !EC_KEY_set_public_key(ec_key.get(), EC_KEY_get0_public_key(public_ec_key.get()))) {
+        *error = TranslateLastOpenSslError();
+        return nullptr;
+    }
+
+    *error = KM_ERROR_OK;
+    return ec_key.release();
+}
+
+Keymaster1Engine::KeyData* Keymaster1Engine::GetData(EVP_PKEY* key) const {
+    switch (EVP_PKEY_type(key->type)) {
+    case EVP_PKEY_RSA: {
+        unique_ptr<RSA, RSA_Delete> rsa(EVP_PKEY_get1_RSA(key));
+        return GetData(rsa.get());
+    }
+
+    case EVP_PKEY_EC: {
+        unique_ptr<EC_KEY, EC_KEY_Delete> ec_key(EVP_PKEY_get1_EC_KEY(key));
+        return GetData(ec_key.get());
+    }
+
+    default:
+        return nullptr;
+    };
+}
+
+Keymaster1Engine::KeyData* Keymaster1Engine::GetData(const RSA* rsa) const {
+    if (!rsa)
+        return nullptr;
+    return reinterpret_cast<KeyData*>(RSA_get_ex_data(rsa, rsa_index_));
+}
+
+Keymaster1Engine::KeyData* Keymaster1Engine::GetData(const EC_KEY* ec_key) const {
+    if (!ec_key)
+        return nullptr;
+    return reinterpret_cast<KeyData*>(EC_KEY_get_ex_data(ec_key, ec_key_index_));
+}
+
+/* static */
+int Keymaster1Engine::duplicate_key_data(CRYPTO_EX_DATA* /* to */, const CRYPTO_EX_DATA* /* from */,
+                                         void** from_d, int /* index */, long /* argl */,
+                                         void* /* argp */) {
+    KeyData* data = reinterpret_cast<KeyData*>(*from_d);
+    if (!data)
+        return 1;
+
+    // Default copy ctor is good.
+    *from_d = new KeyData(*data);
+    if (*from_d)
+        return 1;
+    return 0;
+}
+
+/* static */
+void Keymaster1Engine::free_key_data(void* /* parent */, void* ptr, CRYPTO_EX_DATA* /* data */,
+                                     int /* index*/, long /* argl */, void* /* argp */) {
+    delete reinterpret_cast<KeyData*>(ptr);
+}
+
+keymaster_error_t Keymaster1Engine::Keymaster1Finish(const KeyData* key_data,
+                                                     const keymaster_blob_t& input,
+                                                     keymaster_blob_t* output) {
+    if (key_data->op_handle == 0)
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    size_t input_consumed;
+    // Note: devices are required to consume all input in a single update call for undigested
+    // signing operations and encryption operations.  No need to loop here.
+    keymaster_error_t error =
+        device()->update(device(), key_data->op_handle, &key_data->finish_params, &input,
+                         &input_consumed, nullptr /* out_params */, nullptr /* output */);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    return device()->finish(device(), key_data->op_handle, &key_data->finish_params,
+                            nullptr /* signature */, nullptr /* out_params */, output);
+}
+
+/* static */
+int Keymaster1Engine::rsa_sign_raw(RSA* rsa, size_t* out_len, uint8_t* out, size_t max_out,
+                                   const uint8_t* in, size_t in_len, int padding) {
+    KeyData* key_data = instance_->GetData(rsa);
+    if (!key_data)
+        return 0;
+
+    if (padding != key_data->expected_openssl_padding) {
+        LOG_E("Expected sign_raw with padding %d but got padding %d",
+              key_data->expected_openssl_padding, padding);
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+
+    keymaster_blob_t input = {in, in_len};
+    keymaster_blob_t output;
+    key_data->error = instance_->Keymaster1Finish(key_data, input, &output);
+    if (key_data->error != KM_ERROR_OK)
+        return 0;
+    unique_ptr<uint8_t, Malloc_Delete> output_deleter(const_cast<uint8_t*>(output.data));
+
+    *out_len = std::min(output.data_length, max_out);
+    memcpy(out, output.data, *out_len);
+    return 1;
+}
+
+/* static */
+int Keymaster1Engine::rsa_decrypt(RSA* rsa, size_t* out_len, uint8_t* out, size_t max_out,
+                                  const uint8_t* in, size_t in_len, int padding) {
+    KeyData* key_data = instance_->GetData(rsa);
+    if (!key_data)
+        return 0;
+
+    if (padding != key_data->expected_openssl_padding) {
+        LOG_E("Expected sign_raw with padding %d but got padding %d",
+              key_data->expected_openssl_padding, padding);
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+
+    keymaster_blob_t input = {in, in_len};
+    keymaster_blob_t output;
+    key_data->error = instance_->Keymaster1Finish(key_data, input, &output);
+    if (key_data->error != KM_ERROR_OK)
+        return 0;
+    unique_ptr<uint8_t, Malloc_Delete> output_deleter(const_cast<uint8_t*>(output.data));
+
+    *out_len = std::min(output.data_length, max_out);
+    memcpy(out, output.data, *out_len);
+    return 1;
+}
+
+/* static */
+int Keymaster1Engine::ecdsa_sign(const uint8_t* digest, size_t digest_len, uint8_t* sig,
+                                 unsigned int* sig_len, EC_KEY* ec_key) {
+    KeyData* key_data = instance_->GetData(ec_key);
+    if (!key_data)
+        return 0;
+
+    // Truncate digest if it's too long
+    size_t max_input_len = (ec_group_size_bits(ec_key) + 7) / 8;
+    if (digest_len > max_input_len)
+        digest_len = max_input_len;
+
+    keymaster_blob_t input = {digest, digest_len};
+    keymaster_blob_t output;
+    key_data->error = instance_->Keymaster1Finish(key_data, input, &output);
+    if (key_data->error != KM_ERROR_OK)
+        return 0;
+    unique_ptr<uint8_t, Malloc_Delete> output_deleter(const_cast<uint8_t*>(output.data));
+
+    *sig_len = std::min(output.data_length, ECDSA_size(ec_key));
+    memcpy(sig, output.data, *sig_len);
+    return 1;
+}
+
+EVP_PKEY* Keymaster1Engine::GetKeymaster1PublicKey(const KeymasterKeyBlob& blob,
+                                                   const AuthorizationSet& additional_params,
+                                                   keymaster_error_t* error) const {
+    keymaster_blob_t client_id = {nullptr, 0};
+    keymaster_blob_t app_data = {nullptr, 0};
+    keymaster_blob_t* client_id_ptr = nullptr;
+    keymaster_blob_t* app_data_ptr = nullptr;
+    if (additional_params.GetTagValue(TAG_APPLICATION_ID, &client_id))
+        client_id_ptr = &client_id;
+    if (additional_params.GetTagValue(TAG_APPLICATION_DATA, &app_data))
+        app_data_ptr = &app_data;
+
+    keymaster_blob_t export_data = {nullptr, 0};
+    *error = keymaster1_device_->export_key(keymaster1_device_, KM_KEY_FORMAT_X509, &blob,
+                                            client_id_ptr, app_data_ptr, &export_data);
+    if (*error != KM_ERROR_OK)
+        return nullptr;
+
+    unique_ptr<uint8_t, Malloc_Delete> pub_key(const_cast<uint8_t*>(export_data.data));
+
+    const uint8_t* p = export_data.data;
+    return d2i_PUBKEY(nullptr /* allocate new struct */, &p, export_data.data_length);
+}
+
+RSA_METHOD Keymaster1Engine::BuildRsaMethod() {
+    RSA_METHOD method = {};
+
+    method.common.is_static = 1;
+    method.sign_raw = Keymaster1Engine::rsa_sign_raw;
+    method.decrypt = Keymaster1Engine::rsa_decrypt;
+    method.bn_mod_exp = BN_mod_exp_mont;
+    method.flags = RSA_FLAG_OPAQUE;
+
+    return method;
+}
+
+ECDSA_METHOD Keymaster1Engine::BuildEcdsaMethod() {
+    ECDSA_METHOD method = {};
+
+    method.common.is_static = 1;
+    method.sign = Keymaster1Engine::ecdsa_sign;
+    method.flags = ECDSA_FLAG_OPAQUE;
+
+    return method;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/keymaster1_engine.h b/keymaster/keymaster1_engine.h
new file mode 100644
index 0000000..9e2f13e
--- /dev/null
+++ b/keymaster/keymaster1_engine.h
@@ -0,0 +1,123 @@
+/*
+ * 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_KEYMASTER1_ENGINE_H_
+#define SYSTEM_KEYMASTER_KEYMASTER1_ENGINE_H_
+
+#include <memory>
+
+#include <openssl/ec.h>
+#include <openssl/engine.h>
+#include <openssl/ex_data.h>
+#include <openssl/rsa.h>
+
+#include <hardware/keymaster1.h>
+#include <hardware/keymaster_defs.h>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
+
+#include "openssl_utils.h"
+
+namespace keymaster {
+
+class Keymaster1Engine {
+  public:
+    /**
+     * Create a Keymaster1Engine, wrapping the provided keymaster1_device.  The engine takes
+     * ownership of the device, and will close it during destruction.
+     */
+    explicit Keymaster1Engine(const keymaster1_device_t* keymaster1_device);
+    ~Keymaster1Engine();
+
+    keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+                                  KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced,
+                                  AuthorizationSet* sw_enforced) const;
+
+    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) const;
+    keymaster_error_t DeleteKey(const KeymasterKeyBlob& blob) const;
+    keymaster_error_t DeleteAllKeys() const;
+
+    struct KeyData {
+        KeyData(const KeymasterKeyBlob& blob, const AuthorizationSet& params)
+            : op_handle(0), begin_params(params), key_material(blob), error(KM_ERROR_OK),
+              expected_openssl_padding(-1) {}
+
+        keymaster_operation_handle_t op_handle;
+        AuthorizationSet begin_params;
+        AuthorizationSet finish_params;
+        KeymasterKeyBlob key_material;
+        keymaster_error_t error;
+        int expected_openssl_padding;
+    };
+
+    RSA* BuildRsaKey(const KeymasterKeyBlob& blob, const AuthorizationSet& additional_params,
+                     keymaster_error_t* error) const;
+    EC_KEY* BuildEcKey(const KeymasterKeyBlob& blob, const AuthorizationSet& additional_params,
+                       keymaster_error_t* error) const;
+
+    KeyData* GetData(EVP_PKEY* key) const;
+    KeyData* GetData(const RSA* rsa) const;
+    KeyData* GetData(const EC_KEY* rsa) const;
+
+    const keymaster1_device_t* device() const { return keymaster1_device_; }
+
+    EVP_PKEY* GetKeymaster1PublicKey(const KeymasterKeyBlob& blob,
+                                     const AuthorizationSet& additional_params,
+                                     keymaster_error_t* error) const;
+
+  private:
+    Keymaster1Engine(const Keymaster1Engine&);  // Uncopyable
+    void operator=(const Keymaster1Engine&);    // Unassignable
+
+    RSA_METHOD BuildRsaMethod();
+    ECDSA_METHOD BuildEcdsaMethod();
+    void ConfigureEngineForRsa();
+    void ConfigureEngineForEcdsa();
+
+    keymaster_error_t Keymaster1Finish(const KeyData* key_data, const keymaster_blob_t& input,
+                                       keymaster_blob_t* output);
+
+    static int duplicate_key_data(CRYPTO_EX_DATA* to, const CRYPTO_EX_DATA* from, void** from_d,
+                                  int index, long argl, void* argp);
+    static void free_key_data(void* parent, void* ptr, CRYPTO_EX_DATA* data, int index, long argl,
+                              void* argp);
+
+    static int rsa_sign_raw(RSA* rsa, size_t* out_len, uint8_t* out, size_t max_out,
+                            const uint8_t* in, size_t in_len, int padding);
+    static int rsa_decrypt(RSA* rsa, size_t* out_len, uint8_t* out, size_t max_out,
+                           const uint8_t* in, size_t in_len, int padding);
+    static int ecdsa_sign(const uint8_t* digest, size_t digest_len, uint8_t* sig,
+                          unsigned int* sig_len, EC_KEY* ec_key);
+
+    const keymaster1_device_t* const keymaster1_device_;
+    const std::unique_ptr<ENGINE, ENGINE_Delete> engine_;
+    const int rsa_index_;
+    const int ec_key_index_;
+
+    const RSA_METHOD rsa_method_;
+    const ECDSA_METHOD ecdsa_method_;
+
+    static Keymaster1Engine* instance_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_KEYMASTER1_ENGINE_H_
diff --git a/keymaster/keymaster_enforcement.cpp b/keymaster/keymaster_enforcement.cpp
new file mode 100644
index 0000000..7696d89
--- /dev/null
+++ b/keymaster/keymaster_enforcement.cpp
@@ -0,0 +1,574 @@
+/*
+ * Copyright (C) 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 <keymaster/keymaster_enforcement.h>
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
+#include <openssl/evp.h>
+
+#include <hardware/hw_auth_token.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/logger.h>
+
+#include "List.h"
+
+using android::List;
+
+namespace keymaster {
+
+class AccessTimeMap {
+  public:
+    explicit AccessTimeMap(uint32_t max_size) : max_size_(max_size) {}
+
+    /* If the key is found, returns true and fills \p last_access_time.  If not found returns
+     * false. */
+    bool LastKeyAccessTime(km_id_t keyid, uint32_t* last_access_time) const;
+
+    /* Updates the last key access time with the currentTime parameter.  Adds the key if
+     * needed, returning false if key cannot be added because list is full. */
+    bool UpdateKeyAccessTime(km_id_t keyid, uint32_t current_time, uint32_t timeout);
+
+  private:
+    struct AccessTime {
+        km_id_t keyid;
+        uint32_t access_time;
+        uint32_t timeout;
+    };
+    android::List<AccessTime> last_access_list_;
+    const uint32_t max_size_;
+};
+
+class AccessCountMap {
+  public:
+    explicit AccessCountMap(uint32_t max_size) : max_size_(max_size) {}
+
+    /* If the key is found, returns true and fills \p count.  If not found returns
+     * false. */
+    bool KeyAccessCount(km_id_t keyid, uint32_t* count) const;
+
+    /* Increments key access count, adding an entry if the key has never been used.  Returns
+     * false if the list has reached maximum size. */
+    bool IncrementKeyAccessCount(km_id_t keyid);
+
+  private:
+    struct AccessCount {
+        km_id_t keyid;
+        uint64_t access_count;
+    };
+    android::List<AccessCount> access_count_list_;
+    const uint32_t max_size_;
+};
+
+bool is_public_key_algorithm(const AuthorizationSet& auth_set) {
+    keymaster_algorithm_t algorithm;
+    return auth_set.GetTagValue(TAG_ALGORITHM, &algorithm) &&
+           (algorithm == KM_ALGORITHM_RSA || algorithm == KM_ALGORITHM_EC);
+}
+
+static keymaster_error_t authorized_purpose(const keymaster_purpose_t purpose,
+                                            const AuthorizationSet& auth_set) {
+    switch (purpose) {
+    case KM_PURPOSE_VERIFY:
+    case KM_PURPOSE_ENCRYPT:
+    case KM_PURPOSE_SIGN:
+    case KM_PURPOSE_DECRYPT:
+        if (auth_set.Contains(TAG_PURPOSE, purpose))
+            return KM_ERROR_OK;
+        return KM_ERROR_INCOMPATIBLE_PURPOSE;
+
+    default:
+        return KM_ERROR_UNSUPPORTED_PURPOSE;
+    }
+}
+
+inline bool is_origination_purpose(keymaster_purpose_t purpose) {
+    return purpose == KM_PURPOSE_ENCRYPT || purpose == KM_PURPOSE_SIGN;
+}
+
+inline bool is_usage_purpose(keymaster_purpose_t purpose) {
+    return purpose == KM_PURPOSE_DECRYPT || purpose == KM_PURPOSE_VERIFY;
+}
+
+KeymasterEnforcement::KeymasterEnforcement(uint32_t max_access_time_map_size,
+                                           uint32_t max_access_count_map_size)
+    : access_time_map_(new (std::nothrow) AccessTimeMap(max_access_time_map_size)),
+      access_count_map_(new (std::nothrow) AccessCountMap(max_access_count_map_size)) {}
+
+KeymasterEnforcement::~KeymasterEnforcement() {
+    delete access_time_map_;
+    delete access_count_map_;
+}
+
+keymaster_error_t KeymasterEnforcement::AuthorizeOperation(const keymaster_purpose_t purpose,
+                                                           const km_id_t keyid,
+                                                           const AuthorizationSet& auth_set,
+                                                           const AuthorizationSet& operation_params,
+                                                           keymaster_operation_handle_t op_handle,
+                                                           bool is_begin_operation) {
+    if (is_public_key_algorithm(auth_set)) {
+        switch (purpose) {
+        case KM_PURPOSE_ENCRYPT:
+        case KM_PURPOSE_VERIFY:
+            /* Public key operations are always authorized. */
+            return KM_ERROR_OK;
+
+        case KM_PURPOSE_DECRYPT:
+        case KM_PURPOSE_SIGN:
+        case KM_PURPOSE_DERIVE_KEY:
+            break;
+        };
+    };
+
+    if (is_begin_operation)
+        return AuthorizeBegin(purpose, keyid, auth_set, operation_params);
+    else
+        return AuthorizeUpdateOrFinish(auth_set, operation_params, op_handle);
+}
+
+// For update and finish the only thing to check is user authentication, and then only if it's not
+// timeout-based.
+keymaster_error_t
+KeymasterEnforcement::AuthorizeUpdateOrFinish(const AuthorizationSet& auth_set,
+                                              const AuthorizationSet& operation_params,
+                                              keymaster_operation_handle_t op_handle) {
+    int auth_type_index = -1;
+    for (size_t pos = 0; pos < auth_set.size(); ++pos) {
+        switch (auth_set[pos].tag) {
+        case KM_TAG_NO_AUTH_REQUIRED:
+        case KM_TAG_AUTH_TIMEOUT:
+            // If no auth is required or if auth is timeout-based, we have nothing to check.
+            return KM_ERROR_OK;
+
+        case KM_TAG_USER_AUTH_TYPE:
+            auth_type_index = pos;
+            break;
+
+        default:
+            break;
+        }
+    }
+
+    // Note that at this point we should be able to assume that authentication is required, because
+    // authentication is required if KM_TAG_NO_AUTH_REQUIRED is absent.  However, there are legacy
+    // keys which have no authentication-related tags, so we assume that absence is equivalent to
+    // presence of KM_TAG_NO_AUTH_REQUIRED.
+    //
+    // So, if we found KM_TAG_USER_AUTH_TYPE or if we find KM_TAG_USER_SECURE_ID then authentication
+    // is required.  If we find neither, then we assume authentication is not required and return
+    // success.
+    bool authentication_required = (auth_type_index != -1);
+    for (auto& param : auth_set) {
+        if (param.tag == KM_TAG_USER_SECURE_ID) {
+            authentication_required = true;
+            int auth_timeout_index = -1;
+            if (AuthTokenMatches(auth_set, operation_params, param.long_integer, auth_type_index,
+                                 auth_timeout_index, op_handle, false /* is_begin_operation */))
+                return KM_ERROR_OK;
+        }
+    }
+
+    if (authentication_required)
+        return KM_ERROR_KEY_USER_NOT_AUTHENTICATED;
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t KeymasterEnforcement::AuthorizeBegin(const keymaster_purpose_t purpose,
+                                                       const km_id_t keyid,
+                                                       const AuthorizationSet& auth_set,
+                                                       const AuthorizationSet& operation_params) {
+    // Find some entries that may be needed to handle KM_TAG_USER_SECURE_ID
+    int auth_timeout_index = -1;
+    int auth_type_index = -1;
+    int no_auth_required_index = -1;
+    for (size_t pos = 0; pos < auth_set.size(); ++pos) {
+        switch (auth_set[pos].tag) {
+        case KM_TAG_AUTH_TIMEOUT:
+            auth_timeout_index = pos;
+            break;
+        case KM_TAG_USER_AUTH_TYPE:
+            auth_type_index = pos;
+            break;
+        case KM_TAG_NO_AUTH_REQUIRED:
+            no_auth_required_index = pos;
+            break;
+        default:
+            break;
+        }
+    }
+
+    keymaster_error_t error = authorized_purpose(purpose, auth_set);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    // If successful, and if key has a min time between ops, this will be set to the time limit
+    uint32_t min_ops_timeout = UINT32_MAX;
+
+    bool update_access_count = false;
+    bool caller_nonce_authorized_by_key = false;
+    bool authentication_required = false;
+    bool auth_token_matched = false;
+
+    for (auto& param : auth_set) {
+
+        // KM_TAG_PADDING_OLD and KM_TAG_DIGEST_OLD aren't actually members of the enum, so we can't
+        // switch on them.  There's nothing to validate for them, though, so just ignore them.
+        if (param.tag == KM_TAG_PADDING_OLD || param.tag == KM_TAG_DIGEST_OLD)
+            continue;
+
+        switch (param.tag) {
+
+        case KM_TAG_ACTIVE_DATETIME:
+            if (!activation_date_valid(param.date_time))
+                return KM_ERROR_KEY_NOT_YET_VALID;
+            break;
+
+        case KM_TAG_ORIGINATION_EXPIRE_DATETIME:
+            if (is_origination_purpose(purpose) && expiration_date_passed(param.date_time))
+                return KM_ERROR_KEY_EXPIRED;
+            break;
+
+        case KM_TAG_USAGE_EXPIRE_DATETIME:
+            if (is_usage_purpose(purpose) && expiration_date_passed(param.date_time))
+                return KM_ERROR_KEY_EXPIRED;
+            break;
+
+        case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
+            min_ops_timeout = param.integer;
+            if (!MinTimeBetweenOpsPassed(min_ops_timeout, keyid))
+                return KM_ERROR_KEY_RATE_LIMIT_EXCEEDED;
+            break;
+
+        case KM_TAG_MAX_USES_PER_BOOT:
+            update_access_count = true;
+            if (!MaxUsesPerBootNotExceeded(keyid, param.integer))
+                return KM_ERROR_KEY_MAX_OPS_EXCEEDED;
+            break;
+
+        case KM_TAG_USER_SECURE_ID:
+            if (no_auth_required_index != -1) {
+                // Key has both KM_TAG_USER_SECURE_ID and KM_TAG_NO_AUTH_REQUIRED
+                return KM_ERROR_INVALID_KEY_BLOB;
+            }
+
+            if (auth_timeout_index != -1) {
+                authentication_required = true;
+                if (AuthTokenMatches(auth_set, operation_params, param.long_integer,
+                                     auth_type_index, auth_timeout_index, 0 /* op_handle */,
+                                     true /* is_begin_operation */))
+                    auth_token_matched = true;
+            }
+            break;
+
+        case KM_TAG_CALLER_NONCE:
+            caller_nonce_authorized_by_key = true;
+            break;
+
+        /* Tags should never be in key auths. */
+        case KM_TAG_INVALID:
+        case KM_TAG_AUTH_TOKEN:
+        case KM_TAG_ROOT_OF_TRUST:
+        case KM_TAG_APPLICATION_DATA:
+            return KM_ERROR_INVALID_KEY_BLOB;
+
+        /* Tags used for cryptographic parameters in keygen.  Nothing to enforce. */
+        case KM_TAG_PURPOSE:
+        case KM_TAG_ALGORITHM:
+        case KM_TAG_KEY_SIZE:
+        case KM_TAG_BLOCK_MODE:
+        case KM_TAG_DIGEST:
+        case KM_TAG_MAC_LENGTH:
+        case KM_TAG_PADDING:
+        case KM_TAG_NONCE:
+        case KM_TAG_MIN_MAC_LENGTH:
+        case KM_TAG_KDF:
+        case KM_TAG_EC_CURVE:
+
+        /* Tags not used for operations. */
+        case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+        case KM_TAG_EXPORTABLE:
+
+        /* Algorithm specific parameters not used for access control. */
+        case KM_TAG_RSA_PUBLIC_EXPONENT:
+        case KM_TAG_ECIES_SINGLE_HASH_MODE:
+
+        /* Informational tags. */
+        case KM_TAG_CREATION_DATETIME:
+        case KM_TAG_ORIGIN:
+        case KM_TAG_ROLLBACK_RESISTANT:
+
+        /* Tags handled when KM_TAG_USER_SECURE_ID is handled */
+        case KM_TAG_NO_AUTH_REQUIRED:
+        case KM_TAG_USER_AUTH_TYPE:
+        case KM_TAG_AUTH_TIMEOUT:
+
+        /* Tag to provide data to operations. */
+        case KM_TAG_ASSOCIATED_DATA:
+
+        /* Tags that are implicitly verified by secure side */
+        case KM_TAG_ALL_APPLICATIONS:
+        case KM_TAG_APPLICATION_ID:
+        case KM_TAG_OS_VERSION:
+        case KM_TAG_OS_PATCHLEVEL:
+
+        /* Ignored pending removal */
+        case KM_TAG_USER_ID:
+        case KM_TAG_ALL_USERS:
+
+        /* TODO(swillden): Handle these */
+        case KM_TAG_INCLUDE_UNIQUE_ID:
+        case KM_TAG_UNIQUE_ID:
+        case KM_TAG_RESET_SINCE_ID_ROTATION:
+        case KM_TAG_ALLOW_WHILE_ON_BODY:
+            break;
+
+        case KM_TAG_BOOTLOADER_ONLY:
+            return KM_ERROR_INVALID_KEY_BLOB;
+        }
+    }
+
+    if (authentication_required && !auth_token_matched) {
+        LOG_E("Auth required but no matching auth token found", 0);
+        return KM_ERROR_KEY_USER_NOT_AUTHENTICATED;
+    }
+
+    if (!caller_nonce_authorized_by_key && is_origination_purpose(purpose) &&
+        operation_params.find(KM_TAG_NONCE) != -1)
+        return KM_ERROR_CALLER_NONCE_PROHIBITED;
+
+    if (min_ops_timeout != UINT32_MAX) {
+        if (!access_time_map_) {
+            LOG_S("Rate-limited keys table not allocated.  Rate-limited keys disabled", 0);
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        }
+
+        if (!access_time_map_->UpdateKeyAccessTime(keyid, get_current_time(), min_ops_timeout)) {
+            LOG_E("Rate-limited keys table full.  Entries will time out.", 0);
+            return KM_ERROR_TOO_MANY_OPERATIONS;
+        }
+    }
+
+    if (update_access_count) {
+        if (!access_count_map_) {
+            LOG_S("Usage-count limited keys tabel not allocated.  Count-limited keys disabled", 0);
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        }
+
+        if (!access_count_map_->IncrementKeyAccessCount(keyid)) {
+            LOG_E("Usage count-limited keys table full, until reboot.", 0);
+            return KM_ERROR_TOO_MANY_OPERATIONS;
+        }
+    }
+
+    return KM_ERROR_OK;
+}
+
+class EvpMdCtx {
+  public:
+    EvpMdCtx() { EVP_MD_CTX_init(&ctx_); }
+    ~EvpMdCtx() { EVP_MD_CTX_cleanup(&ctx_); }
+
+    EVP_MD_CTX* get() { return &ctx_; }
+
+  private:
+    EVP_MD_CTX ctx_;
+};
+
+/* static */
+bool KeymasterEnforcement::CreateKeyId(const keymaster_key_blob_t& key_blob, km_id_t* keyid) {
+    EvpMdCtx ctx;
+
+    uint8_t hash[EVP_MAX_MD_SIZE];
+    unsigned int hash_len;
+    if (EVP_DigestInit_ex(ctx.get(), EVP_sha256(), nullptr /* ENGINE */) &&
+        EVP_DigestUpdate(ctx.get(), key_blob.key_material, key_blob.key_material_size) &&
+        EVP_DigestFinal_ex(ctx.get(), hash, &hash_len)) {
+        assert(hash_len >= sizeof(*keyid));
+        memcpy(keyid, hash, sizeof(*keyid));
+        return true;
+    }
+
+    return false;
+}
+
+bool KeymasterEnforcement::MinTimeBetweenOpsPassed(uint32_t min_time_between, const km_id_t keyid) {
+    if (!access_time_map_)
+        return false;
+
+    uint32_t last_access_time;
+    if (!access_time_map_->LastKeyAccessTime(keyid, &last_access_time))
+        return true;
+    return min_time_between <= static_cast<int64_t>(get_current_time()) - last_access_time;
+}
+
+bool KeymasterEnforcement::MaxUsesPerBootNotExceeded(const km_id_t keyid, uint32_t max_uses) {
+    if (!access_count_map_)
+        return false;
+
+    uint32_t key_access_count;
+    if (!access_count_map_->KeyAccessCount(keyid, &key_access_count))
+        return true;
+    return key_access_count < max_uses;
+}
+
+bool KeymasterEnforcement::AuthTokenMatches(const AuthorizationSet& auth_set,
+                                            const AuthorizationSet& operation_params,
+                                            const uint64_t user_secure_id,
+                                            const int auth_type_index, const int auth_timeout_index,
+                                            const keymaster_operation_handle_t op_handle,
+                                            bool is_begin_operation) const {
+    assert(auth_type_index < static_cast<int>(auth_set.size()));
+    assert(auth_timeout_index < static_cast<int>(auth_set.size()));
+
+    keymaster_blob_t auth_token_blob;
+    if (!operation_params.GetTagValue(TAG_AUTH_TOKEN, &auth_token_blob)) {
+        LOG_E("Authentication required, but auth token not provided", 0);
+        return false;
+    }
+
+    if (auth_token_blob.data_length != sizeof(hw_auth_token_t)) {
+        LOG_E("Bug: Auth token is the wrong size (%d expected, %d found)", sizeof(hw_auth_token_t),
+              auth_token_blob.data_length);
+        return false;
+    }
+
+    hw_auth_token_t auth_token;
+    memcpy(&auth_token, auth_token_blob.data, sizeof(hw_auth_token_t));
+    if (auth_token.version != HW_AUTH_TOKEN_VERSION) {
+        LOG_E("Bug: Auth token is the version %d (or is not an auth token). Expected %d",
+              auth_token.version, HW_AUTH_TOKEN_VERSION);
+        return false;
+    }
+
+    if (!ValidateTokenSignature(auth_token)) {
+        LOG_E("Auth token signature invalid", 0);
+        return false;
+    }
+
+    if (auth_timeout_index == -1 && op_handle && op_handle != auth_token.challenge) {
+        LOG_E("Auth token has the challenge %llu, need %llu", auth_token.challenge, op_handle);
+        return false;
+    }
+
+    if (user_secure_id != auth_token.user_id && user_secure_id != auth_token.authenticator_id) {
+        LOG_I("Auth token SIDs %llu and %llu do not match key SID %llu", auth_token.user_id,
+              auth_token.authenticator_id, user_secure_id);
+        return false;
+    }
+
+    if (auth_type_index < 0 || auth_type_index > static_cast<int>(auth_set.size())) {
+        LOG_E("Auth required but no auth type found", 0);
+        return false;
+    }
+
+    assert(auth_set[auth_type_index].tag == KM_TAG_USER_AUTH_TYPE);
+    if (auth_set[auth_type_index].tag != KM_TAG_USER_AUTH_TYPE)
+        return false;
+
+    uint32_t key_auth_type_mask = auth_set[auth_type_index].integer;
+    uint32_t token_auth_type = ntoh(auth_token.authenticator_type);
+    if ((key_auth_type_mask & token_auth_type) == 0) {
+        LOG_E("Key requires match of auth type mask 0%uo, but token contained 0%uo",
+              key_auth_type_mask, token_auth_type);
+        return false;
+    }
+
+    if (auth_timeout_index != -1 && is_begin_operation) {
+        assert(auth_set[auth_timeout_index].tag == KM_TAG_AUTH_TIMEOUT);
+        if (auth_set[auth_timeout_index].tag != KM_TAG_AUTH_TIMEOUT)
+            return false;
+
+        if (auth_token_timed_out(auth_token, auth_set[auth_timeout_index].integer)) {
+            LOG_E("Auth token has timed out", 0);
+            return false;
+        }
+    }
+
+    // Survived the whole gauntlet.  We have authentage!
+    return true;
+}
+
+bool AccessTimeMap::LastKeyAccessTime(km_id_t keyid, uint32_t* last_access_time) const {
+    for (auto& entry : last_access_list_)
+        if (entry.keyid == keyid) {
+            *last_access_time = entry.access_time;
+            return true;
+        }
+    return false;
+}
+
+bool AccessTimeMap::UpdateKeyAccessTime(km_id_t keyid, uint32_t current_time, uint32_t timeout) {
+    List<AccessTime>::iterator iter;
+    for (iter = last_access_list_.begin(); iter != last_access_list_.end();) {
+        if (iter->keyid == keyid) {
+            iter->access_time = current_time;
+            return true;
+        }
+
+        // Expire entry if possible.
+        assert(current_time >= iter->access_time);
+        if (current_time - iter->access_time >= iter->timeout)
+            iter = last_access_list_.erase(iter);
+        else
+            ++iter;
+    }
+
+    if (last_access_list_.size() >= max_size_)
+        return false;
+
+    AccessTime new_entry;
+    new_entry.keyid = keyid;
+    new_entry.access_time = current_time;
+    new_entry.timeout = timeout;
+    last_access_list_.push_front(new_entry);
+    return true;
+}
+
+bool AccessCountMap::KeyAccessCount(km_id_t keyid, uint32_t* count) const {
+    for (auto& entry : access_count_list_)
+        if (entry.keyid == keyid) {
+            *count = entry.access_count;
+            return true;
+        }
+    return false;
+}
+
+bool AccessCountMap::IncrementKeyAccessCount(km_id_t keyid) {
+    for (auto& entry : access_count_list_)
+        if (entry.keyid == keyid) {
+            // Note that the 'if' below will always be true because KM_TAG_MAX_USES_PER_BOOT is a
+            // uint32_t, and as soon as entry.access_count reaches the specified maximum value
+            // operation requests will be rejected and access_count won't be incremented any more.
+            // And, besides, UINT64_MAX is huge.  But we ensure that it doesn't wrap anyway, out of
+            // an abundance of caution.
+            if (entry.access_count < UINT64_MAX)
+                ++entry.access_count;
+            return true;
+        }
+
+    if (access_count_list_.size() >= max_size_)
+        return false;
+
+    AccessCount new_entry;
+    new_entry.keyid = keyid;
+    new_entry.access_count = 1;
+    access_count_list_.push_front(new_entry);
+    return true;
+}
+}; /* namespace keymaster */
diff --git a/keymaster/keymaster_enforcement_test.cpp b/keymaster/keymaster_enforcement_test.cpp
new file mode 100644
index 0000000..3874744
--- /dev/null
+++ b/keymaster/keymaster_enforcement_test.cpp
@@ -0,0 +1,872 @@
+/*
+ * Copyright (C) 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 <errno.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <keymaster/android_keymaster.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/keymaster_enforcement.h>
+
+#include "android_keymaster_test_utils.h"
+
+namespace keymaster {
+namespace test {
+
+class TestKeymasterEnforcement : public KeymasterEnforcement {
+  public:
+    TestKeymasterEnforcement()
+        : KeymasterEnforcement(3, 3), current_time_(10000), report_token_valid_(true) {}
+
+    keymaster_error_t AuthorizeOperation(const keymaster_purpose_t purpose, const km_id_t keyid,
+                                         const AuthorizationSet& auth_set) {
+        AuthorizationSet empty_set;
+        return KeymasterEnforcement::AuthorizeOperation(
+            purpose, keyid, auth_set, empty_set, 0 /* op_handle */, true /* is_begin_operation */);
+    }
+    using KeymasterEnforcement::AuthorizeOperation;
+
+    uint32_t get_current_time() const override { return current_time_; }
+    bool activation_date_valid(uint64_t activation_date) const override {
+        // Convert java date to time_t, non-portably.
+        time_t activation_time = activation_date / 1000;
+        return difftime(time(NULL), activation_time) >= 0;
+    }
+    bool expiration_date_passed(uint64_t expiration_date) const override {
+        // Convert jave date to time_t, non-portably.
+        time_t expiration_time = expiration_date / 1000;
+        return difftime(time(NULL), expiration_time) > 0;
+    }
+    bool auth_token_timed_out(const hw_auth_token_t& token, uint32_t timeout) const {
+        return current_time_ > ntoh(token.timestamp) + timeout;
+    }
+    bool ValidateTokenSignature(const hw_auth_token_t&) const override {
+        return report_token_valid_;
+    }
+
+    void tick(unsigned seconds = 1) { current_time_ += seconds; }
+    uint32_t current_time() { return current_time_; }
+    void set_report_token_valid(bool report_token_valid) {
+        report_token_valid_ = report_token_valid;
+    }
+
+  private:
+    uint32_t current_time_;
+    bool report_token_valid_;
+};
+
+class KeymasterBaseTest : public ::testing::Test {
+  protected:
+    KeymasterBaseTest() {
+        past_time = 0;
+
+        time_t t = time(NULL);
+        future_tm = localtime(&t);
+        future_tm->tm_year += 1;
+        future_time = static_cast<uint64_t>(mktime(future_tm)) * 1000;
+        sign_param = Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN);
+    }
+    virtual ~KeymasterBaseTest() {}
+
+    TestKeymasterEnforcement kmen;
+
+    tm past_tm;
+    tm* future_tm;
+    uint64_t past_time;
+    uint64_t future_time;
+    static const km_id_t key_id = 0xa;
+    static const uid_t uid = 0xf;
+    keymaster_key_param_t sign_param;
+};
+
+TEST_F(KeymasterBaseTest, TestValidKeyPeriodNoTags) {
+    keymaster_key_param_t params[] = {
+        sign_param,
+    };
+    AuthorizationSet single_auth_set(params, array_length(params));
+
+    keymaster_error_t kmer = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, single_auth_set);
+    ASSERT_EQ(KM_ERROR_OK, kmer);
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidActiveTime) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+        Authorization(TAG_NO_AUTH_REQUIRED), Authorization(TAG_ACTIVE_DATETIME, future_time),
+    };
+
+    AuthorizationSet auth_set(params, array_length(params));
+
+    ASSERT_EQ(KM_ERROR_KEY_NOT_YET_VALID,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+
+    // Pubkey ops allowed.
+    ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestValidActiveTime) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ACTIVE_DATETIME, past_time),
+    };
+
+    AuthorizationSet auth_set(params, array_length(params));
+
+    keymaster_error_t kmer_valid_time = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
+    ASSERT_EQ(KM_ERROR_OK, kmer_valid_time);
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidOriginationExpireTime) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+        Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, past_time),
+    };
+
+    AuthorizationSet auth_set(params, array_length(params));
+
+    ASSERT_EQ(KM_ERROR_KEY_EXPIRED, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+
+    // Pubkey ops allowed.
+    ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidOriginationExpireTimeOnUsgae) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+        Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, past_time),
+    };
+
+    AuthorizationSet auth_set(params, array_length(params));
+
+    keymaster_error_t kmer_invalid_origination =
+        kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set);
+    ASSERT_EQ(KM_ERROR_OK, kmer_invalid_origination);
+}
+
+TEST_F(KeymasterBaseTest, TestValidOriginationExpireTime) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+        Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, future_time),
+    };
+
+    AuthorizationSet auth_set(params, array_length(params));
+
+    keymaster_error_t kmer_valid_origination =
+        kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
+    ASSERT_EQ(KM_ERROR_OK, kmer_valid_origination);
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidUsageExpireTime) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES),
+        Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+        Authorization(TAG_USAGE_EXPIRE_DATETIME, past_time),
+    };
+
+    AuthorizationSet auth_set(params, array_length(params));
+
+    keymaster_error_t kmer_invalid_origination =
+        kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set);
+    ASSERT_EQ(KM_ERROR_KEY_EXPIRED, kmer_invalid_origination);
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidPubkeyUsageExpireTime) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
+        Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+        Authorization(TAG_USAGE_EXPIRE_DATETIME, past_time),
+    };
+
+    AuthorizationSet auth_set(params, array_length(params));
+
+    keymaster_error_t kmer_invalid_origination =
+        kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set);
+    // Pubkey ops allowed.
+    ASSERT_EQ(KM_ERROR_OK, kmer_invalid_origination);
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidUsageExpireTimeOnOrigination) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+        Authorization(TAG_USAGE_EXPIRE_DATETIME, past_time),
+    };
+
+    AuthorizationSet auth_set(params, array_length(params));
+
+    keymaster_error_t kmer_invalid_origination =
+        kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
+    ASSERT_EQ(KM_ERROR_OK, kmer_invalid_origination);
+}
+
+TEST_F(KeymasterBaseTest, TestValidUsageExpireTime) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+        Authorization(TAG_USAGE_EXPIRE_DATETIME, future_time),
+    };
+
+    AuthorizationSet auth_set(params, array_length(params));
+
+    keymaster_error_t kmer_valid_usage =
+        kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set);
+    ASSERT_EQ(KM_ERROR_OK, kmer_valid_usage);
+}
+
+TEST_F(KeymasterBaseTest, TestValidSingleUseAccesses) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+    };
+
+    AuthorizationSet auth_set(params, array_length(params));
+
+    keymaster_error_t kmer1 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
+    keymaster_error_t kmer2 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
+
+    ASSERT_EQ(KM_ERROR_OK, kmer1);
+    ASSERT_EQ(KM_ERROR_OK, kmer2);
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidMaxOps) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
+        Authorization(TAG_MAX_USES_PER_BOOT, 4),
+    };
+
+    AuthorizationSet auth_set(params, array_length(params));
+
+    ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+    ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+    ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+    ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+    ASSERT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+    // Pubkey ops allowed.
+    ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestOverFlowMaxOpsTable) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+        Authorization(TAG_MAX_USES_PER_BOOT, 2),
+    };
+
+    AuthorizationSet auth_set(params, array_length(params));
+
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set));
+
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 2 /* key_id */, auth_set));
+
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 3 /* key_id */, auth_set));
+
+    // Key 4 should fail, because table is full.
+    EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 4 /* key_id */, auth_set));
+
+    // Key 1 still works, because it's already in the table and hasn't reached max.
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set));
+
+    // Key 1 no longer works, because it's reached max.
+    EXPECT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set));
+
+    // Key 4 should fail, because table is (still and forever) full.
+    EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 4 /* key_id */, auth_set));
+
+    // Pubkey ops allowed.
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidTimeBetweenOps) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+        Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 10),
+    };
+
+    AuthorizationSet auth_set(params, array_length(params));
+
+    keymaster_error_t kmer1 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
+    keymaster_error_t kmer2 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
+    keymaster_error_t kmer3 = kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set);
+
+    ASSERT_EQ(KM_ERROR_OK, kmer1);
+    kmen.tick(2);
+    ASSERT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, kmer2);
+
+    // Allowed because it's a pubkey op.
+    ASSERT_EQ(KM_ERROR_OK, kmer3);
+}
+
+TEST_F(KeymasterBaseTest, TestValidTimeBetweenOps) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+        Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 2),
+    };
+
+    AuthorizationSet auth_set(params, array_length(params));
+
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
+    kmen.tick();
+    EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+    kmen.tick();
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestOptTimeoutTableOverflow) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES),
+        Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 4),
+        Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+    };
+
+    AuthorizationSet auth_set(params, array_length(params));
+
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+
+    kmen.tick();
+
+    // Key 1 fails because it's too soon
+    EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
+
+    kmen.tick();
+
+    // Key 1 fails because it's too soon
+    EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+    // Key 2 fails because it's too soon
+    EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
+
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
+
+    kmen.tick();
+
+    // Key 1 fails because it's too soon
+    EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+    // Key 2 fails because it's too soon
+    EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
+    // Key 3 fails because it's too soon
+    EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
+    // Key 4 fails because the table is full
+    EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, auth_set));
+
+    kmen.tick();
+
+    // Key 4 succeeds because key 1 expired.
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, auth_set));
+
+    // Key 1 fails because the table is full... and key 1 is no longer in it.
+    EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+    // Key 2 fails because it's too soon
+    EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
+    // Key 3 fails because it's too soon
+    EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
+
+    kmen.tick();
+
+    // Key 1 succeeds because key 2 expired
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+    // Key 2 fails because the table is full... and key 2 is no longer in it.
+    EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
+    // Key 3 fails because it's too soon
+    EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
+    // Key 4 fails because it's too soon
+    EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, auth_set));
+
+    kmen.tick(4);
+
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestPubkeyOptTimeoutTableOverflow) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
+        Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 4), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+    };
+
+    AuthorizationSet auth_set(params, array_length(params));
+
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set));
+
+    kmen.tick();
+
+    // Key 1 fails because it's too soon
+    EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set));
+    // Too soo, but pubkey ops allowed.
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidPurpose) {
+    keymaster_purpose_t invalidPurpose1 = static_cast<keymaster_purpose_t>(-1);
+    keymaster_purpose_t invalidPurpose2 = static_cast<keymaster_purpose_t>(4);
+
+    AuthorizationSet auth_set(
+        AuthorizationSetBuilder().Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY));
+
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE,
+              kmen.AuthorizeOperation(invalidPurpose1, key_id, auth_set));
+    EXPECT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE,
+              kmen.AuthorizeOperation(invalidPurpose2, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestIncompatiblePurposeSymmetricKey) {
+    AuthorizationSet auth_set(AuthorizationSetBuilder()
+                                  .Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES)
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
+
+    EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE,
+              kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, auth_set));
+    EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE,
+              kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestIncompatiblePurposeAssymmetricKey) {
+    AuthorizationSet auth_set(AuthorizationSetBuilder()
+                                  .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
+
+    // This one is allowed because it's a pubkey op.
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, auth_set));
+    EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE,
+              kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidCallerNonce) {
+    AuthorizationSet no_caller_nonce(AuthorizationSetBuilder()
+                                         .Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT)
+                                         .Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT)
+                                         .Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES));
+    AuthorizationSet caller_nonce(AuthorizationSetBuilder()
+                                      .Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT)
+                                      .Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT)
+                                      .Authorization(TAG_ALGORITHM, KM_ALGORITHM_HMAC)
+                                      .Authorization(TAG_CALLER_NONCE));
+    AuthorizationSet begin_params(AuthorizationSetBuilder().Authorization(TAG_NONCE, "foo", 3));
+
+    EXPECT_EQ(KM_ERROR_OK,
+              kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, caller_nonce, begin_params,
+                                      0 /* challenge */, true /* is_begin_operation */));
+    EXPECT_EQ(KM_ERROR_OK,
+              kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, caller_nonce, begin_params,
+                                      0 /* challenge */, true /* is_begin_operation */));
+    EXPECT_EQ(KM_ERROR_CALLER_NONCE_PROHIBITED,
+              kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, no_caller_nonce, begin_params,
+                                      0 /* challenge */, true /* is_begin_operation */));
+    EXPECT_EQ(KM_ERROR_OK,
+              kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, no_caller_nonce, begin_params,
+                                      0 /* challenge */, true /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestBootloaderOnly) {
+    AuthorizationSet auth_set(AuthorizationSetBuilder()
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+                                  .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                                  .Authorization(TAG_BOOTLOADER_ONLY));
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+
+    // Pubkey ops allowed.
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidTag) {
+    AuthorizationSet auth_set(AuthorizationSetBuilder()
+                                  .Authorization(TAG_INVALID)
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthPerOpSuccess) {
+    hw_auth_token_t token;
+    memset(&token, 0, sizeof(token));
+    token.version = HW_AUTH_TOKEN_VERSION;
+    token.challenge = 99;
+    token.user_id = 9;
+    token.authenticator_id = 0;
+    token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+    token.timestamp = 0;
+
+    AuthorizationSet auth_set(AuthorizationSetBuilder()
+                                  .Authorization(TAG_USER_SECURE_ID, token.user_id)
+                                  .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+    AuthorizationSet op_params;
+    op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+    EXPECT_EQ(KM_ERROR_OK,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+                                      false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthPerOpInvalidTokenSignature) {
+    hw_auth_token_t token;
+    memset(&token, 0, sizeof(token));
+    token.version = HW_AUTH_TOKEN_VERSION;
+    token.challenge = 99;
+    token.user_id = 9;
+    token.authenticator_id = 0;
+    token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+    token.timestamp = 0;
+
+    AuthorizationSet auth_set(AuthorizationSetBuilder()
+                                  .Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC)
+                                  .Authorization(TAG_USER_SECURE_ID, token.user_id)
+                                  .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+    AuthorizationSet op_params;
+    op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+    kmen.set_report_token_valid(false);
+    EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+                                      false /* is_begin_operation */));
+    // Pubkey ops allowed.
+    EXPECT_EQ(KM_ERROR_OK,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
+                                      token.challenge, false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthPerOpWrongChallenge) {
+    hw_auth_token_t token;
+    memset(&token, 0, sizeof(token));
+    token.version = HW_AUTH_TOKEN_VERSION;
+    token.challenge = 99;
+    token.user_id = 9;
+    token.authenticator_id = 0;
+    token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+    token.timestamp = 0;
+
+    AuthorizationSet auth_set(AuthorizationSetBuilder()
+                                  .Authorization(TAG_USER_SECURE_ID, token.user_id)
+                                  .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+    AuthorizationSet op_params;
+    op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+    EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+                                      token.challenge + 1 /* doesn't match token */,
+                                      false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthPerOpNoAuthType) {
+    hw_auth_token_t token;
+    memset(&token, 0, sizeof(token));
+    token.version = HW_AUTH_TOKEN_VERSION;
+    token.challenge = 99;
+    token.user_id = 9;
+    token.authenticator_id = 0;
+    token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+    token.timestamp = 0;
+
+    AuthorizationSet auth_set(AuthorizationSetBuilder()
+                                  .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                                  .Authorization(TAG_USER_SECURE_ID, token.user_id)
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+    AuthorizationSet op_params;
+    op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+    EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+                                      false /* is_begin_operation */));
+    // Pubkey ops allowed.
+    EXPECT_EQ(KM_ERROR_OK,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
+                                      token.challenge, false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthPerOpWrongAuthType) {
+    hw_auth_token_t token;
+    memset(&token, 0, sizeof(token));
+    token.version = HW_AUTH_TOKEN_VERSION;
+    token.challenge = 99;
+    token.user_id = 9;
+    token.authenticator_id = 0;
+    token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+    token.timestamp = 0;
+
+    AuthorizationSet auth_set(
+        AuthorizationSetBuilder()
+            .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+            .Authorization(TAG_USER_SECURE_ID, token.user_id)
+            .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_FINGERPRINT /* doesn't match token */)
+            .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+    AuthorizationSet op_params;
+    op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+    EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+                                      false /* is_begin_operation */));
+    // Pubkey ops allowed.
+    EXPECT_EQ(KM_ERROR_OK,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
+                                      token.challenge, false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthPerOpWrongSid) {
+    hw_auth_token_t token;
+    memset(&token, 0, sizeof(token));
+    token.version = HW_AUTH_TOKEN_VERSION;
+    token.challenge = 99;
+    token.user_id = 9;
+    token.authenticator_id = 0;
+    token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+    token.timestamp = 0;
+
+    AuthorizationSet auth_set(
+        AuthorizationSetBuilder()
+            .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+            .Authorization(TAG_USER_SECURE_ID, token.user_id + 1 /* doesn't match token */)
+            .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+            .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+    AuthorizationSet op_params;
+    op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+    EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+                                      false /* is_begin_operation */));
+    // Pubkey op allowed.
+    EXPECT_EQ(KM_ERROR_OK,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
+                                      token.challenge, false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthPerOpSuccessAlternateSid) {
+    hw_auth_token_t token;
+    memset(&token, 0, sizeof(token));
+    token.version = HW_AUTH_TOKEN_VERSION;
+    token.challenge = 99;
+    token.user_id = 9;
+    token.authenticator_id = 10;
+    token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+    token.timestamp = 0;
+
+    AuthorizationSet auth_set(AuthorizationSetBuilder()
+                                  .Authorization(TAG_USER_SECURE_ID, token.authenticator_id)
+                                  .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+    AuthorizationSet op_params;
+    op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+    EXPECT_EQ(KM_ERROR_OK,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+                                      false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthPerOpMissingToken) {
+    hw_auth_token_t token;
+    memset(&token, 0, sizeof(token));
+    token.version = HW_AUTH_TOKEN_VERSION;
+    token.challenge = 99;
+    token.user_id = 9;
+    token.authenticator_id = 0;
+    token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+    token.timestamp = 0;
+
+    AuthorizationSet auth_set(AuthorizationSetBuilder()
+                                  .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                                  .Authorization(TAG_USER_SECURE_ID, token.user_id)
+                                  .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+    AuthorizationSet op_params;
+
+    // During begin we can skip the auth token
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+                                                   token.challenge, true /* is_begin_operation */));
+    // Afterwards we must have authentication
+    EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+                                      false /* is_begin_operation */));
+    // Pubkey ops allowed
+    EXPECT_EQ(KM_ERROR_OK,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
+                                      token.challenge, false /* is_begin_operation */));
+
+    auth_set.Reinitialize(AuthorizationSetBuilder()
+                              .Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES)
+                              .Authorization(TAG_USER_SECURE_ID, token.user_id)
+                              .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+                              .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+                              .build());
+
+    EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
+                                      token.challenge, false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthAndNoAuth) {
+    AuthorizationSet auth_set(AuthorizationSetBuilder()
+                                  .Authorization(TAG_USER_SECURE_ID, 1)
+                                  .Authorization(TAG_NO_AUTH_REQUIRED)
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestTimedAuthSuccess) {
+    hw_auth_token_t token;
+    memset(&token, 0, sizeof(token));
+    token.version = HW_AUTH_TOKEN_VERSION;
+    token.challenge = 99;
+    token.user_id = 9;
+    token.authenticator_id = 0;
+    token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+    token.timestamp = hton(kmen.current_time());
+
+    AuthorizationSet auth_set(AuthorizationSetBuilder()
+                                  .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                                  .Authorization(TAG_USER_SECURE_ID, token.user_id)
+                                  .Authorization(TAG_AUTH_TIMEOUT, 1)
+                                  .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+    AuthorizationSet op_params;
+    op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+    EXPECT_EQ(KM_ERROR_OK,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+                                      0 /* irrelevant */, false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestTimedAuthTimedOut) {
+    hw_auth_token_t token;
+    memset(&token, 0, sizeof(token));
+    token.version = HW_AUTH_TOKEN_VERSION;
+    token.challenge = 99;
+    token.user_id = 9;
+    token.authenticator_id = 0;
+    token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+    token.timestamp = hton(static_cast<uint64_t>(kmen.current_time()));
+
+    AuthorizationSet auth_set(AuthorizationSetBuilder()
+                                  .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                                  .Authorization(TAG_USER_SECURE_ID, token.user_id)
+                                  .Authorization(TAG_AUTH_TIMEOUT, 1)
+                                  .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+    AuthorizationSet op_params;
+    op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+    EXPECT_EQ(KM_ERROR_OK,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+                                      0 /* irrelevant */, false /* is_begin_operation */));
+
+    kmen.tick(1);
+
+    // token still good
+    EXPECT_EQ(KM_ERROR_OK,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+                                      0 /* irrelevant */, false /* is_begin_operation */));
+
+    kmen.tick(1);
+
+    // token expired, not allowed during begin.
+    EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+                                      0 /* irrelevant */, true /* is_begin_operation */));
+
+    // token expired, afterwards it's okay.
+    EXPECT_EQ(KM_ERROR_OK,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+                                      0 /* irrelevant */, false /* is_begin_operation */));
+
+    // Pubkey ops allowed.
+    EXPECT_EQ(KM_ERROR_OK,
+              kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
+                                      0 /* irrelevant */, true /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestTimedAuthMissingToken) {
+    hw_auth_token_t token;
+    memset(&token, 0, sizeof(token));
+    token.version = HW_AUTH_TOKEN_VERSION;
+    token.challenge = 99;
+    token.user_id = 9;
+    token.authenticator_id = 0;
+    token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+    token.timestamp = hton(static_cast<uint64_t>(kmen.current_time()));
+
+    AuthorizationSet auth_set(AuthorizationSetBuilder()
+                                  .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+                                  .Authorization(TAG_USER_SECURE_ID, token.user_id)
+                                  .Authorization(TAG_AUTH_TIMEOUT, 1)
+                                  .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+    AuthorizationSet op_params;
+
+    // Unlike auth-per-op, must have the auth token during begin.
+    EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+                                      true /* is_begin_operation */));
+
+    // Later we don't check (though begin would fail, so there wouldn't be a later).
+    EXPECT_EQ(KM_ERROR_OK,
+              kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+                                      false /* is_begin_operation */));
+
+    // Pubkey ops allowed.
+    EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
+                                                   token.challenge, true /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestCreateKeyId) {
+    keymaster_key_blob_t blob = {reinterpret_cast<const uint8_t*>("foobar"), 6};
+
+    km_id_t key_id = 0;
+    EXPECT_TRUE(KeymasterEnforcement::CreateKeyId(blob, &key_id));
+    EXPECT_NE(0U, key_id);
+}
+
+}; /* namespace test */
+}; /* namespace keymaster */
diff --git a/keymaster/keymaster_tags.cpp b/keymaster/keymaster_tags.cpp
new file mode 100644
index 0000000..ce7156f
--- /dev/null
+++ b/keymaster/keymaster_tags.cpp
@@ -0,0 +1,171 @@
+/*
+ * 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 <keymaster/keymaster_tags.h>
+
+namespace keymaster {
+
+#ifdef KEYMASTER_NAME_TAGS
+const char* StringifyTag(keymaster_tag_t tag) {
+    switch (tag) {
+    case KM_TAG_INVALID:
+        return "KM_TAG_INVALID";
+    case KM_TAG_PURPOSE:
+        return "KM_TAG_PURPOSE";
+    case KM_TAG_ALGORITHM:
+        return "KM_TAG_ALGORITHM";
+    case KM_TAG_KEY_SIZE:
+        return "KM_TAG_KEY_SIZE";
+    case KM_TAG_BLOCK_MODE:
+        return "KM_TAG_BLOCK_MODE";
+    case KM_TAG_DIGEST:
+        return "KM_TAG_DIGEST";
+    case KM_TAG_PADDING:
+        return "KM_TAG_PADDING";
+    case KM_TAG_CALLER_NONCE:
+        return "KM_TAG_CALLER_NONCE";
+    case KM_TAG_MIN_MAC_LENGTH:
+        return "KM_TAG_MIN_MAC_LENGTH";
+    case KM_TAG_RSA_PUBLIC_EXPONENT:
+        return "KM_TAG_RSA_PUBLIC_EXPONENT";
+    case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+        return "KM_TAG_BLOB_USAGE_REQUIREMENTS";
+    case KM_TAG_BOOTLOADER_ONLY:
+        return "KM_TAG_BOOTLOADER_ONLY";
+    case KM_TAG_ACTIVE_DATETIME:
+        return "KM_TAG_ACTIVE_DATETIME";
+    case KM_TAG_ORIGINATION_EXPIRE_DATETIME:
+        return "KM_TAG_ORIGINATION_EXPIRE_DATETIME";
+    case KM_TAG_USAGE_EXPIRE_DATETIME:
+        return "KM_TAG_USAGE_EXPIRE_DATETIME";
+    case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
+        return "KM_TAG_MIN_SECONDS_BETWEEN_OPS";
+    case KM_TAG_MAX_USES_PER_BOOT:
+        return "KM_TAG_MAX_USES_PER_BOOT";
+    case KM_TAG_ALL_USERS:
+        return "KM_TAG_ALL_USERS";
+    case KM_TAG_USER_ID:
+        return "KM_TAG_USER_ID";
+    case KM_TAG_USER_SECURE_ID:
+        return "KM_TAG_USER_SECURE_ID";
+    case KM_TAG_NO_AUTH_REQUIRED:
+        return "KM_TAG_NO_AUTH_REQUIRED";
+    case KM_TAG_USER_AUTH_TYPE:
+        return "KM_TAG_USER_AUTH_TYPE";
+    case KM_TAG_AUTH_TIMEOUT:
+        return "KM_TAG_AUTH_TIMEOUT";
+    case KM_TAG_ALL_APPLICATIONS:
+        return "KM_TAG_ALL_APPLICATIONS";
+    case KM_TAG_APPLICATION_ID:
+        return "KM_TAG_APPLICATION_ID";
+    case KM_TAG_APPLICATION_DATA:
+        return "KM_TAG_APPLICATION_DATA";
+    case KM_TAG_CREATION_DATETIME:
+        return "KM_TAG_CREATION_DATETIME";
+    case KM_TAG_ORIGIN:
+        return "KM_TAG_ORIGIN";
+    case KM_TAG_ROLLBACK_RESISTANT:
+        return "KM_TAG_ROLLBACK_RESISTANT";
+    case KM_TAG_ROOT_OF_TRUST:
+        return "KM_TAG_ROOT_OF_TRUST";
+    case KM_TAG_ASSOCIATED_DATA:
+        return "KM_TAG_ASSOCIATED_DATA";
+    case KM_TAG_NONCE:
+        return "KM_TAG_NONCE";
+    case KM_TAG_AUTH_TOKEN:
+        return "KM_TAG_AUTH_TOKEN";
+    case KM_TAG_MAC_LENGTH:
+        return "KM_TAG_MAC_LENGTH";
+    case KM_TAG_KDF:
+        return "KM_TAG_KDF";
+    case KM_TAG_EC_CURVE:
+        return "KM_TAG_EC_CURVE";
+    case KM_TAG_ECIES_SINGLE_HASH_MODE:
+        return "KM_TAG_ECIES_SINGLE_HASH_MODE";
+    case KM_TAG_OS_VERSION:
+        return "KM_TAG_OS_VERSION";
+    case KM_TAG_OS_PATCHLEVEL:
+        return "KM_TAG_OS_PATCHLEVEL";
+    case KM_TAG_EXPORTABLE:
+        return "KM_TAG_EXPORTABLE";
+    case KM_TAG_UNIQUE_ID:
+        return "KM_TAG_UNIQUE_ID";
+    case KM_TAG_INCLUDE_UNIQUE_ID:
+        return "KM_TAG_INCLUDE_UNIQUE_ID";
+    case KM_TAG_RESET_SINCE_ID_ROTATION:
+        return "KM_TAG_RESET_SINCE_ID_ROTATION";
+    case KM_TAG_ALLOW_WHILE_ON_BODY:
+        return "KM_TAG_ALLOW_WHILE_ON_BODY";
+    }
+    return "<Unknown>";
+}
+#endif  // KEYMASTER_NAME_TAGS
+
+// DEFINE_KEYMASTER_TAG is used to create TypedTag instances for each non-enum keymaster tag.
+#define DEFINE_KEYMASTER_TAG(type, name) TypedTag<type, KM_##name> name
+
+DEFINE_KEYMASTER_TAG(KM_INVALID, TAG_INVALID);
+DEFINE_KEYMASTER_TAG(KM_UINT, TAG_KEY_SIZE);
+DEFINE_KEYMASTER_TAG(KM_UINT, TAG_MAC_LENGTH);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_CALLER_NONCE);
+DEFINE_KEYMASTER_TAG(KM_UINT, TAG_MIN_MAC_LENGTH);
+DEFINE_KEYMASTER_TAG(KM_ULONG, TAG_RSA_PUBLIC_EXPONENT);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ECIES_SINGLE_HASH_MODE);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_INCLUDE_UNIQUE_ID);
+DEFINE_KEYMASTER_TAG(KM_DATE, TAG_ACTIVE_DATETIME);
+DEFINE_KEYMASTER_TAG(KM_DATE, TAG_ORIGINATION_EXPIRE_DATETIME);
+DEFINE_KEYMASTER_TAG(KM_DATE, TAG_USAGE_EXPIRE_DATETIME);
+DEFINE_KEYMASTER_TAG(KM_UINT, TAG_MIN_SECONDS_BETWEEN_OPS);
+DEFINE_KEYMASTER_TAG(KM_UINT, TAG_MAX_USES_PER_BOOT);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ALL_USERS);
+DEFINE_KEYMASTER_TAG(KM_UINT, TAG_USER_ID);
+DEFINE_KEYMASTER_TAG(KM_ULONG_REP, TAG_USER_SECURE_ID);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_NO_AUTH_REQUIRED);
+DEFINE_KEYMASTER_TAG(KM_UINT, TAG_AUTH_TIMEOUT);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ALLOW_WHILE_ON_BODY);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ALL_APPLICATIONS);
+DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_APPLICATION_ID);
+DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_APPLICATION_DATA);
+DEFINE_KEYMASTER_TAG(KM_DATE, TAG_CREATION_DATETIME);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ROLLBACK_RESISTANT);
+DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_ROOT_OF_TRUST);
+DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_ASSOCIATED_DATA);
+DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_NONCE);
+DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_AUTH_TOKEN);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_BOOTLOADER_ONLY);
+DEFINE_KEYMASTER_TAG(KM_UINT, TAG_OS_VERSION);
+DEFINE_KEYMASTER_TAG(KM_UINT, TAG_OS_PATCHLEVEL);
+DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_UNIQUE_ID);
+
+// DEFINE_KEYMASTER_ENUM_TAG is used to create TypedEnumTag instances for each enum keymaster tag.
+
+#define DEFINE_KEYMASTER_ENUM_TAG(type, name, enumtype) TypedEnumTag<type, KM_##name, enumtype> name
+
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_PURPOSE, keymaster_purpose_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_ALGORITHM, keymaster_algorithm_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_BLOCK_MODE, keymaster_block_mode_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_DIGEST, keymaster_digest_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_DIGEST_OLD, keymaster_digest_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_PADDING, keymaster_padding_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_PADDING_OLD, keymaster_padding_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_BLOB_USAGE_REQUIREMENTS,
+                          keymaster_key_blob_usage_requirements_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_ORIGIN, keymaster_key_origin_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_USER_AUTH_TYPE, hw_authenticator_type_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_KDF, keymaster_kdf_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_EC_CURVE, keymaster_ec_curve_t);
+
+}  // namespace keymaster
diff --git a/keymaster/km0_sw_rsa_512.blob b/keymaster/km0_sw_rsa_512.blob
new file mode 100644
index 0000000..7fee81c
--- /dev/null
+++ b/keymaster/km0_sw_rsa_512.blob
Binary files differ
diff --git a/keymaster/km1_sw_ecdsa_256.blob b/keymaster/km1_sw_ecdsa_256.blob
new file mode 100644
index 0000000..5b9a6f4
--- /dev/null
+++ b/keymaster/km1_sw_ecdsa_256.blob
Binary files differ
diff --git a/keymaster/km1_sw_rsa_512.blob b/keymaster/km1_sw_rsa_512.blob
new file mode 100644
index 0000000..db1730a
--- /dev/null
+++ b/keymaster/km1_sw_rsa_512.blob
Binary files differ
diff --git a/keymaster/km1_sw_rsa_512_unversioned.blob b/keymaster/km1_sw_rsa_512_unversioned.blob
new file mode 100644
index 0000000..e4f6a11
--- /dev/null
+++ b/keymaster/km1_sw_rsa_512_unversioned.blob
Binary files differ
diff --git a/keymaster/logger.cpp b/keymaster/logger.cpp
new file mode 100644
index 0000000..f86a68f
--- /dev/null
+++ b/keymaster/logger.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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 <keymaster/logger.h>
+
+namespace keymaster {
+
+Logger* Logger::instance_ = 0;
+
+/* static */
+int Logger::Log(LogLevel level, const char* fmt, va_list args) {
+    if (!instance_)
+        return 0;
+    return instance_->log_msg(level, fmt, args);
+}
+
+/* static */
+int Logger::Log(LogLevel level, const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    int result = Log(level, fmt, args);
+    va_end(args);
+    return result;
+}
+
+/* static */
+int Logger::Debug(const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    int result = Log(DEBUG_LVL, fmt, args);
+    va_end(args);
+    return result;
+}
+
+/* static */
+int Logger::Info(const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    int result = Log(INFO_LVL, fmt, args);
+    va_end(args);
+    return result;
+}
+/* static */
+int Logger::Warning(const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    int result = Log(WARNING_LVL, fmt, args);
+    va_end(args);
+    return result;
+}
+/* static */
+int Logger::Error(const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    int result = Log(ERROR_LVL, fmt, args);
+    va_end(args);
+    return result;
+}
+/* static */
+int Logger::Severe(const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    int result = Log(SEVERE_LVL, fmt, args);
+    va_end(args);
+    return result;
+}
+
+
+}  // namespace keymaster
diff --git a/keymaster/nist_curve_key_exchange.cpp b/keymaster/nist_curve_key_exchange.cpp
new file mode 100644
index 0000000..0dd3a54
--- /dev/null
+++ b/keymaster/nist_curve_key_exchange.cpp
@@ -0,0 +1,127 @@
+/*
+ * 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 "nist_curve_key_exchange.h"
+
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+
+#include "openssl_err.h"
+
+namespace keymaster {
+
+NistCurveKeyExchange::NistCurveKeyExchange(EC_KEY* private_key, keymaster_error_t* error)
+    : private_key_(private_key) {
+    if (!private_key_.get() || !EC_KEY_check_key(private_key_.get())) {
+        *error = KM_ERROR_INVALID_ARGUMENT;
+        return;
+    }
+    *error = ExtractPublicKey();
+}
+
+/* static */
+NistCurveKeyExchange* NistCurveKeyExchange::GenerateKeyExchange(keymaster_ec_curve_t curve) {
+    int curve_name;
+    switch (curve) {
+    case KM_EC_CURVE_P_224:
+        curve_name = NID_secp224r1;
+        break;
+    case KM_EC_CURVE_P_256:
+        curve_name = NID_X9_62_prime256v1;
+        break;
+    case KM_EC_CURVE_P_384:
+        curve_name = NID_secp384r1;
+        break;
+    case KM_EC_CURVE_P_521:
+        curve_name = NID_secp521r1;
+        break;
+    default:
+        LOG_E("Not a NIST curve: %d", curve);
+        return nullptr;
+    }
+
+    UniquePtr<EC_KEY, EC_KEY_Delete> key(EC_KEY_new_by_curve_name(curve_name));
+    if (!key.get() || !EC_KEY_generate_key(key.get())) {
+        return nullptr;
+    }
+    keymaster_error_t error;
+    NistCurveKeyExchange* key_exchange = new NistCurveKeyExchange(key.release(), &error);
+    if (error != KM_ERROR_OK) {
+        return nullptr;
+    }
+    return key_exchange;
+}
+
+keymaster_error_t NistCurveKeyExchange::ExtractPublicKey() {
+    const EC_GROUP* group = EC_KEY_get0_group(private_key_.get());
+    size_t field_len_bits;
+    keymaster_error_t error = ec_get_group_size(group, &field_len_bits);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    shared_secret_len_ = (field_len_bits + 7) / 8;
+    public_key_len_ = 1 + 2 * shared_secret_len_;
+    public_key_.reset(new uint8_t[public_key_len_]);
+    if (EC_POINT_point2oct(group, EC_KEY_get0_public_key(private_key_.get()),
+                           POINT_CONVERSION_UNCOMPRESSED, public_key_.get(), public_key_len_,
+                           nullptr /* ctx */) != public_key_len_) {
+        return TranslateLastOpenSslError();
+    }
+    return KM_ERROR_OK;
+}
+
+bool NistCurveKeyExchange::CalculateSharedKey(const Buffer& peer_public_value,
+                                              Buffer* out_result) const {
+
+    return CalculateSharedKey(peer_public_value.peek_read(), peer_public_value.available_read(),
+                              out_result);
+}
+
+bool NistCurveKeyExchange::CalculateSharedKey(const uint8_t* peer_public_value,
+                                              size_t peer_public_value_len,
+                                              Buffer* out_result) const {
+    const EC_GROUP* group = EC_KEY_get0_group(private_key_.get());
+    UniquePtr<EC_POINT, EC_POINT_Delete> point(EC_POINT_new(group));
+    if (!point.get() ||
+        !EC_POINT_oct2point(/* also test if point is on curve */
+                            group, point.get(), peer_public_value, peer_public_value_len,
+                            nullptr /* ctx */) ||
+        !EC_POINT_is_on_curve(group, point.get(), nullptr /* ctx */)) {
+        LOG_E("Can't convert peer public value to point: %d", TranslateLastOpenSslError());
+        return false;
+    }
+
+    UniquePtr<uint8_t[]> result(new uint8_t[shared_secret_len_]);
+    if (ECDH_compute_key(result.get(), shared_secret_len_, point.get(), private_key_.get(),
+                         nullptr /* kdf */) != static_cast<int>(shared_secret_len_)) {
+        LOG_E("Can't compute ECDH shared key: %d", TranslateLastOpenSslError());
+        return false;
+    }
+
+    out_result->Reinitialize(result.get(), shared_secret_len_);
+    return true;
+}
+
+bool NistCurveKeyExchange::public_value(Buffer* public_value) const {
+    if (public_key_.get() != nullptr && public_key_len_ != 0) {
+        return public_value->Reinitialize(public_key_.get(), public_key_len_);
+    }
+    return false;
+}
+
+}  // namespace keymaster
\ No newline at end of file
diff --git a/keymaster/nist_curve_key_exchange.h b/keymaster/nist_curve_key_exchange.h
new file mode 100644
index 0000000..0a93882
--- /dev/null
+++ b/keymaster/nist_curve_key_exchange.h
@@ -0,0 +1,72 @@
+/*
+ * 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_NIST_CURVE_KEY_EXCHANGE_H_
+#define SYSTEM_KEYMASTER_NIST_CURVE_KEY_EXCHANGE_H_
+
+#include "key_exchange.h"
+
+#include <keymaster/authorization_set.h>
+#include <hardware/keymaster_defs.h>
+
+#include <UniquePtr.h>
+
+#include "openssl_utils.h"
+
+namespace keymaster {
+
+/**
+ * NistCurveKeyExchange implements a KeyExchange using elliptic-curve
+ * Diffie-Hellman on NIST curves: P-224, P-256, P-384 and P-521.
+ */
+class NistCurveKeyExchange : public KeyExchange {
+  public:
+    ~NistCurveKeyExchange() override {}
+
+    /**
+     * NistCurveKeyExchange takes ownership of \p private_key.
+     */
+    NistCurveKeyExchange(EC_KEY* private_key, keymaster_error_t* error);
+
+    /**
+     * GenerateKeyExchange generates a new public/private key pair on a NIST curve and returns
+     * a new key exchange object.
+     */
+    static NistCurveKeyExchange* GenerateKeyExchange(keymaster_ec_curve_t curve);
+
+    /**
+     * KeyExchange interface.
+     */
+    bool CalculateSharedKey(const uint8_t* peer_public_value, size_t peer_public_value_len,
+                            Buffer* shared_key) const override;
+    bool CalculateSharedKey(const Buffer& peer_public_value, Buffer* shared_key) const override;
+    bool public_value(Buffer* public_value) const override;
+
+    /* Caller takes ownership of \p private_key. */
+    EC_KEY* private_key() { return private_key_.release(); }
+
+  private:
+    keymaster_error_t ExtractPublicKey();
+
+    UniquePtr<EC_KEY, EC_KEY_Delete> private_key_;
+    UniquePtr<uint8_t[]> public_key_;
+    size_t public_key_len_;
+    size_t shared_secret_len_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_NIST_CURVE_KEY_EXCHANGE_H_
\ No newline at end of file
diff --git a/keymaster/nist_curve_key_exchange_test.cpp b/keymaster/nist_curve_key_exchange_test.cpp
new file mode 100644
index 0000000..39ea38b
--- /dev/null
+++ b/keymaster/nist_curve_key_exchange_test.cpp
@@ -0,0 +1,219 @@
+/*
+ * 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 "nist_curve_key_exchange.h"
+
+#include <gtest/gtest.h>
+#include <openssl/evp.h>
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/android_keymaster_utils.h>
+
+#include "android_keymaster_test_utils.h"
+
+using std::string;
+
+namespace keymaster {
+namespace test {
+
+StdoutLogger logger;
+
+static const keymaster_ec_curve_t kEcCurves[] = {KM_EC_CURVE_P_224, KM_EC_CURVE_P_256,
+                                                 KM_EC_CURVE_P_384, KM_EC_CURVE_P_521};
+
+/**
+ * SharedKey just tests that the basic key exchange identity holds: that both
+ * parties end up with the same key.
+ */
+TEST(NistCurveKeyExchange, SharedKey) {
+    for (auto& curve : kEcCurves) {
+        AuthorizationSet kex_description(
+            AuthorizationSetBuilder().Authorization(TAG_EC_CURVE, curve));
+        for (size_t j = 0; j < 5; j++) {
+            NistCurveKeyExchange* alice_keyex = NistCurveKeyExchange::GenerateKeyExchange(curve);
+            NistCurveKeyExchange* bob_keyex = NistCurveKeyExchange::GenerateKeyExchange(curve);
+
+            ASSERT_TRUE(alice_keyex != nullptr);
+            ASSERT_TRUE(bob_keyex != nullptr);
+
+            Buffer alice_public_value;
+            ASSERT_TRUE(alice_keyex->public_value(&alice_public_value));
+            Buffer bob_public_value;
+            ASSERT_TRUE(bob_keyex->public_value(&bob_public_value));
+
+            Buffer alice_shared, bob_shared;
+            ASSERT_TRUE(alice_keyex->CalculateSharedKey(bob_public_value, &alice_shared));
+            ASSERT_TRUE(bob_keyex->CalculateSharedKey(alice_public_value, &bob_shared));
+            EXPECT_EQ(alice_shared.available_read(), bob_shared.available_read());
+            EXPECT_EQ(0, memcmp(alice_shared.peek_read(), bob_shared.peek_read(),
+                                alice_shared.available_read()));
+        }
+    }
+}
+
+/*
+ * This test tries a key agreement with a false public key (i.e. with
+ * a point not on the curve.)
+ * The expected result of such a protocol should be that the
+ * key agreement fails and returns an error.
+*/
+static const char* kInvalidPublicKeys[] = {
+    "04"  // uncompressed public key
+    "deadbeef7f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287"
+    "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac",
+};
+
+TEST(NistCurveKeyExchange, InvalidPublicKey) {
+    for (auto& curve : kEcCurves) {
+        AuthorizationSet kex_description(
+            AuthorizationSetBuilder().Authorization(TAG_EC_CURVE, curve));
+        KeyExchange* key_exchange = NistCurveKeyExchange::GenerateKeyExchange(curve);
+        ASSERT_TRUE(key_exchange != nullptr);
+
+        string peer_public_key = hex2str(kInvalidPublicKeys[0]);
+        Buffer computed_shared_secret;
+        ASSERT_FALSE(key_exchange->CalculateSharedKey(
+            reinterpret_cast<const uint8_t*>(peer_public_key.data()), peer_public_key.size(),
+            &computed_shared_secret));
+    }
+}
+
+/**
+ * Test that key exchange fails when peer public key is the point at infinity.
+ */
+TEST(NistCurveKeyExchange, TestInfinity) {
+    for (auto& curve : kEcCurves) {
+        /* Obtain the point at infinity */
+        EC_GROUP* group = ec_get_group(curve);
+        EC_POINT* point_at_infinity = EC_POINT_new(group);
+        EC_POINT_set_to_infinity(group, point_at_infinity);
+        EXPECT_EQ(1, EC_POINT_is_on_curve(group, point_at_infinity, nullptr));
+        size_t field_len_in_bits;
+        ec_get_group_size(group, &field_len_in_bits);
+        size_t field_len = (field_len_in_bits + 7) / 8;
+        size_t public_key_len = (field_len * 2) + 1;
+        uint8_t* public_key = new uint8_t[public_key_len];
+        public_key_len = EC_POINT_point2oct(group, point_at_infinity, POINT_CONVERSION_UNCOMPRESSED,
+                                            public_key, public_key_len, nullptr /* ctx */);
+
+        /* Perform the key exchange */
+        AuthorizationSet kex_description(
+            AuthorizationSetBuilder().Authorization(TAG_EC_CURVE, curve));
+        NistCurveKeyExchange* key_exchange = NistCurveKeyExchange::GenerateKeyExchange(curve);
+        ASSERT_TRUE(key_exchange != nullptr);
+        Buffer computed_shared_secret;
+        /* It should fail */
+        ASSERT_FALSE(key_exchange->CalculateSharedKey(reinterpret_cast<const uint8_t*>(public_key),
+                                                      public_key_len, &computed_shared_secret));
+
+        /* Explicitly test that ECDH_compute_key fails when the public key is the point at infinity
+         */
+        UniquePtr<uint8_t[]> result(new uint8_t[field_len]);
+        EXPECT_EQ(-1 /* error */, ECDH_compute_key(result.get(), field_len, point_at_infinity,
+                                                   key_exchange->private_key(), nullptr /* kdf */));
+    }
+}
+
+/* Test vectors for P-256, downloaded from NIST. */
+struct NistCurveTest {
+    const keymaster_ec_curve_t curve;
+    const char* peer_public_key;
+    const char* my_private_key;
+    const char* shared_secret;
+};
+
+static const NistCurveTest kNistCurveTests[] = {
+    {
+        KM_EC_CURVE_P_256,
+        "04"  // uncompressed public key
+        "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287"
+        "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac",
+        // https://tools.ietf.org/html/rfc5915
+        "30770201010420"  // DER-encodeded EC private key header
+        "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534"  // private key
+        "a00a06082a8648ce3d030107a144034200"  // DER-encoded curve OID,
+        "04"
+        "ead218590119e8876b29146ff89ca61770c4edbbf97d38ce385ed281d8a6b230"
+        "28af61281fd35e2fa7002523acc85a429cb06ee6648325389f59edfce1405141",
+        "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b",
+    },
+    {
+        KM_EC_CURVE_P_256, "04"
+                           "809f04289c64348c01515eb03d5ce7ac1a8cb9498f5caa50197e58d43a86a7ae"
+                           "b29d84e811197f25eba8f5194092cb6ff440e26d4421011372461f579271cda3",
+        // https://tools.ietf.org/html/rfc5915
+        "30770201010420"  // DER-encodeded EC private key header
+        "38f65d6dce47676044d58ce5139582d568f64bb16098d179dbab07741dd5caf5"  // private key
+        "a00a06082a8648ce3d030107a144034200"  // DER-encoded curve OID,
+        "04"
+        "119f2f047902782ab0c9e27a54aff5eb9b964829ca99c06b02ddba95b0a3f6d0"
+        "8f52b726664cac366fc98ac7a012b2682cbd962e5acb544671d41b9445704d1d",
+        "057d636096cb80b67a8c038c890e887d1adfa4195e9b3ce241c8a778c59cda67",
+    },
+    {
+        KM_EC_CURVE_P_256, "04"
+                           "df3989b9fa55495719b3cf46dccd28b5153f7808191dd518eff0c3cff2b705ed"
+                           "422294ff46003429d739a33206c8752552c8ba54a270defc06e221e0feaf6ac4",
+        // https://tools.ietf.org/html/rfc5915
+        "30770201010420"  // DER-encodeded EC private key header
+        "207c43a79bfee03db6f4b944f53d2fb76cc49ef1c9c4d34d51b6c65c4db6932d"  // private key
+        "a00a06082a8648ce3d030107a144034200"  // DER-encoded curve OID,
+        "04"
+        "24277c33f450462dcb3d4801d57b9ced05188f16c28eda873258048cd1607e0d"
+        "c4789753e2b1f63b32ff014ec42cd6a69fac81dfe6d0d6fd4af372ae27c46f88",
+        "96441259534b80f6aee3d287a6bb17b5094dd4277d9e294f8fe73e48bf2a0024",
+    },
+};
+
+/**
+ * Test that key exchange works with NIST test vectors.
+ */
+TEST(NistCurveKeyExchange, NistTestVectors) {
+    for (auto& test : kNistCurveTests) {
+        string private_key = hex2str(test.my_private_key);
+        string shared_secret = hex2str(test.shared_secret);
+
+        const uint8_t* private_key_data = reinterpret_cast<const uint8_t*>(private_key.data());
+        UniquePtr<EC_KEY, EC_KEY_Delete> ec_key(
+            d2i_ECPrivateKey(nullptr, &private_key_data, private_key.size()));
+        ASSERT_TRUE(ec_key.get() && EC_KEY_check_key(ec_key.get()));
+
+        keymaster_error_t error;
+        NistCurveKeyExchange* key_exchange = new NistCurveKeyExchange(ec_key.release(), &error);
+        EXPECT_EQ(KM_ERROR_OK, error);
+        ASSERT_TRUE(key_exchange != nullptr);
+
+        Buffer computed_shared_secret;
+        string peer_public_key = hex2str(test.peer_public_key);
+        ASSERT_TRUE(key_exchange->CalculateSharedKey(
+            reinterpret_cast<const uint8_t*>(peer_public_key.data()), peer_public_key.size(),
+            &computed_shared_secret));
+        EXPECT_EQ(shared_secret.size(), computed_shared_secret.available_read());
+        EXPECT_EQ(0, memcmp(shared_secret.data(), computed_shared_secret.peek_read(),
+                            shared_secret.size()));
+
+        for (size_t i = 0; i < peer_public_key.size(); i++) {
+            // randomly flip some bits in the peer public key to make it invalid
+            peer_public_key[i] ^= 0xff;
+            ASSERT_FALSE(key_exchange->CalculateSharedKey(
+                reinterpret_cast<const uint8_t*>(peer_public_key.data()), peer_public_key.size(),
+                &computed_shared_secret));
+        }
+    }
+}
+
+}  // namespace test
+}  // namespace keymaster
diff --git a/keymaster/ocb.c b/keymaster/ocb.c
new file mode 100644
index 0000000..461fe9d
--- /dev/null
+++ b/keymaster/ocb.c
@@ -0,0 +1,1480 @@
+/*------------------------------------------------------------------------
+/ OCB Version 3 Reference Code (Optimized C)     Last modified 12-JUN-2013
+/-------------------------------------------------------------------------
+/ Copyright (c) 2013 Ted Krovetz.
+/
+/ Permission to use, copy, modify, and/or distribute this software for any
+/ purpose with or without fee is hereby granted, provided that the above
+/ copyright notice and this permission notice appear in all copies.
+/
+/ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+/ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+/ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+/ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+/ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+/ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+/ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+/
+/ Phillip Rogaway holds patents relevant to OCB. See the following for
+/ his patent grant: http://www.cs.ucdavis.edu/~rogaway/ocb/grant.htm
+/
+/ Special thanks to Keegan McAllister for suggesting several good improvements
+/
+/ Comments are welcome: Ted Krovetz <ted@krovetz.net> - Dedicated to Laurel K
+/------------------------------------------------------------------------- */
+
+/* ----------------------------------------------------------------------- */
+/* Usage notes                                                             */
+/* ----------------------------------------------------------------------- */
+
+/* - When AE_PENDING is passed as the 'final' parameter of any function,
+/    the length parameters must be a multiple of (BPI*16).
+/  - When available, SSE or AltiVec registers are used to manipulate data.
+/    So, when on machines with these facilities, all pointers passed to
+/    any function should be 16-byte aligned.
+/  - Plaintext and ciphertext pointers may be equal (ie, plaintext gets
+/    encrypted in-place), but no other pair of pointers may be equal.
+/  - This code assumes all x86 processors have SSE2 and SSSE3 instructions
+/    when compiling under MSVC. If untrue, alter the #define.
+/  - This code is tested for C99 and recent versions of GCC and MSVC.      */
+
+/* ----------------------------------------------------------------------- */
+/* User configuration options                                              */
+/* ----------------------------------------------------------------------- */
+
+/* Set the AES key length to use and length of authentication tag to produce.
+/  Setting either to 0 requires the value be set at runtime via ae_init().
+/  Some optimizations occur for each when set to a fixed value.            */
+#define OCB_KEY_LEN 16 /* 0, 16, 24 or 32. 0 means set in ae_init */
+#define OCB_TAG_LEN 16 /* 0 to 16. 0 means set in ae_init         */
+
+/* This implementation has built-in support for multiple AES APIs. Set any
+/  one of the following to non-zero to specify which to use.               */
+#define USE_OPENSSL_AES 1   /* http://openssl.org                      */
+#define USE_REFERENCE_AES 0 /* Internet search: rijndael-alg-fst.c     */
+#define USE_AES_NI 0        /* Uses compiler's intrinsics              */
+
+/* During encryption and decryption, various "L values" are required.
+/  The L values can be precomputed during initialization (requiring extra
+/  space in ae_ctx), generated as needed (slightly slowing encryption and
+/  decryption), or some combination of the two. L_TABLE_SZ specifies how many
+/  L values to precompute. L_TABLE_SZ must be at least 3. L_TABLE_SZ*16 bytes
+/  are used for L values in ae_ctx. Plaintext and ciphertexts shorter than
+/  2^L_TABLE_SZ blocks need no L values calculated dynamically.            */
+#define L_TABLE_SZ 16
+
+/* Set L_TABLE_SZ_IS_ENOUGH non-zero iff you know that all plaintexts
+/  will be shorter than 2^(L_TABLE_SZ+4) bytes in length. This results
+/  in better performance.                                                  */
+#define L_TABLE_SZ_IS_ENOUGH 1
+
+/* ----------------------------------------------------------------------- */
+/* Includes and compiler specific definitions                              */
+/* ----------------------------------------------------------------------- */
+
+#include "ae.h"
+#include <stdlib.h>
+#include <string.h>
+
+/* Define standard sized integers                                          */
+#if defined(_MSC_VER) && (_MSC_VER < 1600)
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+typedef __int64 int64_t;
+#else
+#include <stdint.h>
+#endif
+
+/* Compiler-specific intrinsics and fixes: bswap64, ntz                    */
+#if _MSC_VER
+#define inline __inline                           /* MSVC doesn't recognize "inline" in C */
+#define restrict __restrict                       /* MSVC doesn't recognize "restrict" in C */
+#define __SSE2__ (_M_IX86 || _M_AMD64 || _M_X64)  /* Assume SSE2  */
+#define __SSSE3__ (_M_IX86 || _M_AMD64 || _M_X64) /* Assume SSSE3 */
+#include <intrin.h>
+#pragma intrinsic(_byteswap_uint64, _BitScanForward, memcpy)
+#define bswap64(x) _byteswap_uint64(x)
+static inline unsigned ntz(unsigned x) {
+    _BitScanForward(&x, x);
+    return x;
+}
+#elif __GNUC__
+#define inline __inline__                   /* No "inline" in GCC ansi C mode */
+#define restrict __restrict__               /* No "restrict" in GCC ansi C mode */
+#define bswap64(x) __builtin_bswap64(x)     /* Assuming GCC 4.3+ */
+#define ntz(x) __builtin_ctz((unsigned)(x)) /* Assuming GCC 3.4+ */
+#else /* Assume some C99 features: stdint.h, inline, restrict */
+#define bswap32(x)                                                                                 \
+    ((((x)&0xff000000u) >> 24) | (((x)&0x00ff0000u) >> 8) | (((x)&0x0000ff00u) << 8) |             \
+     (((x)&0x000000ffu) << 24))
+
+static inline uint64_t bswap64(uint64_t x) {
+    union {
+        uint64_t u64;
+        uint32_t u32[2];
+    } in, out;
+    in.u64 = x;
+    out.u32[0] = bswap32(in.u32[1]);
+    out.u32[1] = bswap32(in.u32[0]);
+    return out.u64;
+}
+
+#if (L_TABLE_SZ <= 9) && (L_TABLE_SZ_IS_ENOUGH) /* < 2^13 byte texts */
+static inline unsigned ntz(unsigned x) {
+    static const unsigned char tz_table[] = {
+        0, 2, 3, 2, 4, 2, 3, 2, 5, 2, 3, 2, 4, 2, 3, 2, 6, 2, 3, 2, 4, 2, 3, 2, 5, 2,
+        3, 2, 4, 2, 3, 2, 7, 2, 3, 2, 4, 2, 3, 2, 5, 2, 3, 2, 4, 2, 3, 2, 6, 2, 3, 2,
+        4, 2, 3, 2, 5, 2, 3, 2, 4, 2, 3, 2, 8, 2, 3, 2, 4, 2, 3, 2, 5, 2, 3, 2, 4, 2,
+        3, 2, 6, 2, 3, 2, 4, 2, 3, 2, 5, 2, 3, 2, 4, 2, 3, 2, 7, 2, 3, 2, 4, 2, 3, 2,
+        5, 2, 3, 2, 4, 2, 3, 2, 6, 2, 3, 2, 4, 2, 3, 2, 5, 2, 3, 2, 4, 2, 3, 2};
+    return tz_table[x / 4];
+}
+#else                                           /* From http://supertech.csail.mit.edu/papers/debruijn.pdf */
+static inline unsigned ntz(unsigned x) {
+    static const unsigned char tz_table[32] = {0,  1,  28, 2,  29, 14, 24, 3,  30, 22, 20,
+                                               15, 25, 17, 4,  8,  31, 27, 13, 23, 21, 19,
+                                               16, 7,  26, 12, 18, 6,  11, 5,  10, 9};
+    return tz_table[((uint32_t)((x & -x) * 0x077CB531u)) >> 27];
+}
+#endif
+#endif
+
+/* ----------------------------------------------------------------------- */
+/* Define blocks and operations -- Patch if incorrect on your compiler.    */
+/* ----------------------------------------------------------------------- */
+
+#if __SSE2__ && !KEYMASTER_CLANG_TEST_BUILD
+#include <xmmintrin.h> /* SSE instructions and _mm_malloc */
+#include <emmintrin.h> /* SSE2 instructions               */
+typedef __m128i block;
+#define xor_block(x, y) _mm_xor_si128(x, y)
+#define zero_block() _mm_setzero_si128()
+#define unequal_blocks(x, y) (_mm_movemask_epi8(_mm_cmpeq_epi8(x, y)) != 0xffff)
+#if __SSSE3__ || USE_AES_NI
+#include <tmmintrin.h> /* SSSE3 instructions              */
+#define swap_if_le(b)                                                                              \
+    _mm_shuffle_epi8(b, _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15))
+#else
+static inline block swap_if_le(block b) {
+    block a = _mm_shuffle_epi32(b, _MM_SHUFFLE(0, 1, 2, 3));
+    a = _mm_shufflehi_epi16(a, _MM_SHUFFLE(2, 3, 0, 1));
+    a = _mm_shufflelo_epi16(a, _MM_SHUFFLE(2, 3, 0, 1));
+    return _mm_xor_si128(_mm_srli_epi16(a, 8), _mm_slli_epi16(a, 8));
+}
+#endif
+static inline block gen_offset(uint64_t KtopStr[3], unsigned bot) {
+    block hi = _mm_load_si128((__m128i*)(KtopStr + 0));  /* hi = B A */
+    block lo = _mm_loadu_si128((__m128i*)(KtopStr + 1)); /* lo = C B */
+    __m128i lshift = _mm_cvtsi32_si128(bot);
+    __m128i rshift = _mm_cvtsi32_si128(64 - bot);
+    lo = _mm_xor_si128(_mm_sll_epi64(hi, lshift), _mm_srl_epi64(lo, rshift));
+#if __SSSE3__ || USE_AES_NI
+    return _mm_shuffle_epi8(lo, _mm_set_epi8(8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7));
+#else
+    return swap_if_le(_mm_shuffle_epi32(lo, _MM_SHUFFLE(1, 0, 3, 2)));
+#endif
+}
+static inline block double_block(block bl) {
+    const __m128i mask = _mm_set_epi32(135, 1, 1, 1);
+    __m128i tmp = _mm_srai_epi32(bl, 31);
+    tmp = _mm_and_si128(tmp, mask);
+    tmp = _mm_shuffle_epi32(tmp, _MM_SHUFFLE(2, 1, 0, 3));
+    bl = _mm_slli_epi32(bl, 1);
+    return _mm_xor_si128(bl, tmp);
+}
+#elif __ALTIVEC__
+#include <altivec.h>
+typedef vector unsigned block;
+#define xor_block(x, y) vec_xor(x, y)
+#define zero_block() vec_splat_u32(0)
+#define unequal_blocks(x, y) vec_any_ne(x, y)
+#define swap_if_le(b) (b)
+#if __PPC64__
+block gen_offset(uint64_t KtopStr[3], unsigned bot) {
+    union {
+        uint64_t u64[2];
+        block bl;
+    } rval;
+    rval.u64[0] = (KtopStr[0] << bot) | (KtopStr[1] >> (64 - bot));
+    rval.u64[1] = (KtopStr[1] << bot) | (KtopStr[2] >> (64 - bot));
+    return rval.bl;
+}
+#else
+/* Special handling: Shifts are mod 32, and no 64-bit types */
+block gen_offset(uint64_t KtopStr[3], unsigned bot) {
+    const vector unsigned k32 = {32, 32, 32, 32};
+    vector unsigned hi = *(vector unsigned*)(KtopStr + 0);
+    vector unsigned lo = *(vector unsigned*)(KtopStr + 2);
+    vector unsigned bot_vec;
+    if (bot < 32) {
+        lo = vec_sld(hi, lo, 4);
+    } else {
+        vector unsigned t = vec_sld(hi, lo, 4);
+        lo = vec_sld(hi, lo, 8);
+        hi = t;
+        bot = bot - 32;
+    }
+    if (bot == 0)
+        return hi;
+    *(unsigned*)&bot_vec = bot;
+    vector unsigned lshift = vec_splat(bot_vec, 0);
+    vector unsigned rshift = vec_sub(k32, lshift);
+    hi = vec_sl(hi, lshift);
+    lo = vec_sr(lo, rshift);
+    return vec_xor(hi, lo);
+}
+#endif
+static inline block double_block(block b) {
+    const vector unsigned char mask = {135, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+    const vector unsigned char perm = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0};
+    const vector unsigned char shift7 = vec_splat_u8(7);
+    const vector unsigned char shift1 = vec_splat_u8(1);
+    vector unsigned char c = (vector unsigned char)b;
+    vector unsigned char t = vec_sra(c, shift7);
+    t = vec_and(t, mask);
+    t = vec_perm(t, t, perm);
+    c = vec_sl(c, shift1);
+    return (block)vec_xor(c, t);
+}
+#elif __ARM_NEON__
+#include <arm_neon.h>
+typedef int8x16_t block; /* Yay! Endian-neutral reads! */
+#define xor_block(x, y) veorq_s8(x, y)
+#define zero_block() vdupq_n_s8(0)
+static inline int unequal_blocks(block a, block b) {
+    int64x2_t t = veorq_s64((int64x2_t)a, (int64x2_t)b);
+    return (vgetq_lane_s64(t, 0) | vgetq_lane_s64(t, 1)) != 0;
+}
+#define swap_if_le(b) (b) /* Using endian-neutral int8x16_t */
+/* KtopStr is reg correct by 64 bits, return mem correct */
+block gen_offset(uint64_t KtopStr[3], unsigned bot) {
+    const union {
+        unsigned x;
+        unsigned char endian;
+    } little = {1};
+    const int64x2_t k64 = {-64, -64};
+    uint64x2_t hi = *(uint64x2_t*)(KtopStr + 0); /* hi = A B */
+    uint64x2_t lo = *(uint64x2_t*)(KtopStr + 1); /* hi = B C */
+    int64x2_t ls = vdupq_n_s64(bot);
+    int64x2_t rs = vqaddq_s64(k64, ls);
+    block rval = (block)veorq_u64(vshlq_u64(hi, ls), vshlq_u64(lo, rs));
+    if (little.endian)
+        rval = vrev64q_s8(rval);
+    return rval;
+}
+static inline block double_block(block b) {
+    const block mask = {135, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+    block tmp = vshrq_n_s8(b, 7);
+    tmp = vandq_s8(tmp, mask);
+    tmp = vextq_s8(tmp, tmp, 1); /* Rotate high byte to end */
+    b = vshlq_n_s8(b, 1);
+    return veorq_s8(tmp, b);
+}
+#else
+typedef struct { uint64_t l, r; } block;
+static inline block xor_block(block x, block y) {
+    x.l ^= y.l;
+    x.r ^= y.r;
+    return x;
+}
+static inline block zero_block(void) {
+    const block t = {0, 0};
+    return t;
+}
+#define unequal_blocks(x, y) ((((x).l ^ (y).l) | ((x).r ^ (y).r)) != 0)
+static inline block swap_if_le(block b) {
+    const union {
+        unsigned x;
+        unsigned char endian;
+    } little = {1};
+    if (little.endian) {
+        block r;
+        r.l = bswap64(b.l);
+        r.r = bswap64(b.r);
+        return r;
+    } else
+        return b;
+}
+
+/* KtopStr is reg correct by 64 bits, return mem correct */
+block gen_offset(uint64_t KtopStr[3], unsigned bot) {
+    block rval;
+    if (bot != 0) {
+        rval.l = (KtopStr[0] << bot) | (KtopStr[1] >> (64 - bot));
+        rval.r = (KtopStr[1] << bot) | (KtopStr[2] >> (64 - bot));
+    } else {
+        rval.l = KtopStr[0];
+        rval.r = KtopStr[1];
+    }
+    return swap_if_le(rval);
+}
+
+#if __GNUC__ && __arm__
+static inline block double_block(block b) {
+    __asm__("adds %1,%1,%1\n\t"
+            "adcs %H1,%H1,%H1\n\t"
+            "adcs %0,%0,%0\n\t"
+            "adcs %H0,%H0,%H0\n\t"
+            "it cs\n\t"
+            "eorcs %1,%1,#135"
+            : "+r"(b.l), "+r"(b.r)
+            :
+            : "cc");
+    return b;
+}
+#else
+static inline block double_block(block b) {
+    uint64_t t = (uint64_t)((int64_t)b.l >> 63);
+    b.l = (b.l + b.l) ^ (b.r >> 63);
+    b.r = (b.r + b.r) ^ (t & 135);
+    return b;
+}
+#endif
+
+#endif
+
+/* ----------------------------------------------------------------------- */
+/* AES - Code uses OpenSSL API. Other implementations get mapped to it.    */
+/* ----------------------------------------------------------------------- */
+
+/*---------------*/
+#if USE_OPENSSL_AES
+/*---------------*/
+
+#include <openssl/aes.h> /* http://openssl.org/ */
+
+/* How to ECB encrypt an array of blocks, in place                         */
+static inline void AES_ecb_encrypt_blks(block* blks, unsigned nblks, AES_KEY* key) {
+    while (nblks) {
+        --nblks;
+        AES_encrypt((unsigned char*)(blks + nblks), (unsigned char*)(blks + nblks), key);
+    }
+}
+
+static inline void AES_ecb_decrypt_blks(block* blks, unsigned nblks, AES_KEY* key) {
+    while (nblks) {
+        --nblks;
+        AES_decrypt((unsigned char*)(blks + nblks), (unsigned char*)(blks + nblks), key);
+    }
+}
+
+#define BPI 4 /* Number of blocks in buffer per ECB call */
+
+/*-------------------*/
+#elif USE_REFERENCE_AES
+/*-------------------*/
+
+#include "rijndael-alg-fst.h" /* Barreto's Public-Domain Code */
+#if (OCB_KEY_LEN == 0)
+typedef struct {
+    uint32_t rd_key[60];
+    int rounds;
+} AES_KEY;
+#define ROUNDS(ctx) ((ctx)->rounds)
+#define AES_set_encrypt_key(x, y, z)                                                               \
+    do {                                                                                           \
+        rijndaelKeySetupEnc((z)->rd_key, x, y);                                                    \
+        (z)->rounds = y / 32 + 6;                                                                  \
+    } while (0)
+#define AES_set_decrypt_key(x, y, z)                                                               \
+    do {                                                                                           \
+        rijndaelKeySetupDec((z)->rd_key, x, y);                                                    \
+        (z)->rounds = y / 32 + 6;                                                                  \
+    } while (0)
+#else
+typedef struct { uint32_t rd_key[OCB_KEY_LEN + 28]; } AES_KEY;
+#define ROUNDS(ctx) (6 + OCB_KEY_LEN / 4)
+#define AES_set_encrypt_key(x, y, z) rijndaelKeySetupEnc((z)->rd_key, x, y)
+#define AES_set_decrypt_key(x, y, z) rijndaelKeySetupDec((z)->rd_key, x, y)
+#endif
+#define AES_encrypt(x, y, z) rijndaelEncrypt((z)->rd_key, ROUNDS(z), x, y)
+#define AES_decrypt(x, y, z) rijndaelDecrypt((z)->rd_key, ROUNDS(z), x, y)
+
+static void AES_ecb_encrypt_blks(block* blks, unsigned nblks, AES_KEY* key) {
+    while (nblks) {
+        --nblks;
+        AES_encrypt((unsigned char*)(blks + nblks), (unsigned char*)(blks + nblks), key);
+    }
+}
+
+void AES_ecb_decrypt_blks(block* blks, unsigned nblks, AES_KEY* key) {
+    while (nblks) {
+        --nblks;
+        AES_decrypt((unsigned char*)(blks + nblks), (unsigned char*)(blks + nblks), key);
+    }
+}
+
+#define BPI 4 /* Number of blocks in buffer per ECB call */
+
+/*----------*/
+#elif USE_AES_NI
+/*----------*/
+
+#include <wmmintrin.h>
+
+#if (OCB_KEY_LEN == 0)
+typedef struct {
+    __m128i rd_key[15];
+    int rounds;
+} AES_KEY;
+#define ROUNDS(ctx) ((ctx)->rounds)
+#else
+typedef struct { __m128i rd_key[7 + OCB_KEY_LEN / 4]; } AES_KEY;
+#define ROUNDS(ctx) (6 + OCB_KEY_LEN / 4)
+#endif
+
+#define EXPAND_ASSIST(v1, v2, v3, v4, shuff_const, aes_const)                                      \
+    v2 = _mm_aeskeygenassist_si128(v4, aes_const);                                                 \
+    v3 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(v3), _mm_castsi128_ps(v1), 16));         \
+    v1 = _mm_xor_si128(v1, v3);                                                                    \
+    v3 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(v3), _mm_castsi128_ps(v1), 140));        \
+    v1 = _mm_xor_si128(v1, v3);                                                                    \
+    v2 = _mm_shuffle_epi32(v2, shuff_const);                                                       \
+    v1 = _mm_xor_si128(v1, v2)
+
+#define EXPAND192_STEP(idx, aes_const)                                                             \
+    EXPAND_ASSIST(x0, x1, x2, x3, 85, aes_const);                                                  \
+    x3 = _mm_xor_si128(x3, _mm_slli_si128(x3, 4));                                                 \
+    x3 = _mm_xor_si128(x3, _mm_shuffle_epi32(x0, 255));                                            \
+    kp[idx] = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(tmp), _mm_castsi128_ps(x0), 68));   \
+    kp[idx + 1] =                                                                                  \
+        _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(x0), _mm_castsi128_ps(x3), 78));          \
+    EXPAND_ASSIST(x0, x1, x2, x3, 85, (aes_const * 2));                                            \
+    x3 = _mm_xor_si128(x3, _mm_slli_si128(x3, 4));                                                 \
+    x3 = _mm_xor_si128(x3, _mm_shuffle_epi32(x0, 255));                                            \
+    kp[idx + 2] = x0;                                                                              \
+    tmp = x3
+
+static void AES_128_Key_Expansion(const unsigned char* userkey, void* key) {
+    __m128i x0, x1, x2;
+    __m128i* kp = (__m128i*)key;
+    kp[0] = x0 = _mm_loadu_si128((__m128i*)userkey);
+    x2 = _mm_setzero_si128();
+    EXPAND_ASSIST(x0, x1, x2, x0, 255, 1);
+    kp[1] = x0;
+    EXPAND_ASSIST(x0, x1, x2, x0, 255, 2);
+    kp[2] = x0;
+    EXPAND_ASSIST(x0, x1, x2, x0, 255, 4);
+    kp[3] = x0;
+    EXPAND_ASSIST(x0, x1, x2, x0, 255, 8);
+    kp[4] = x0;
+    EXPAND_ASSIST(x0, x1, x2, x0, 255, 16);
+    kp[5] = x0;
+    EXPAND_ASSIST(x0, x1, x2, x0, 255, 32);
+    kp[6] = x0;
+    EXPAND_ASSIST(x0, x1, x2, x0, 255, 64);
+    kp[7] = x0;
+    EXPAND_ASSIST(x0, x1, x2, x0, 255, 128);
+    kp[8] = x0;
+    EXPAND_ASSIST(x0, x1, x2, x0, 255, 27);
+    kp[9] = x0;
+    EXPAND_ASSIST(x0, x1, x2, x0, 255, 54);
+    kp[10] = x0;
+}
+
+static void AES_192_Key_Expansion(const unsigned char* userkey, void* key) {
+    __m128i x0, x1, x2, x3, tmp, *kp = (__m128i*)key;
+    kp[0] = x0 = _mm_loadu_si128((__m128i*)userkey);
+    tmp = x3 = _mm_loadu_si128((__m128i*)(userkey + 16));
+    x2 = _mm_setzero_si128();
+    EXPAND192_STEP(1, 1);
+    EXPAND192_STEP(4, 4);
+    EXPAND192_STEP(7, 16);
+    EXPAND192_STEP(10, 64);
+}
+
+static void AES_256_Key_Expansion(const unsigned char* userkey, void* key) {
+    __m128i x0, x1, x2, x3, *kp = (__m128i*)key;
+    kp[0] = x0 = _mm_loadu_si128((__m128i*)userkey);
+    kp[1] = x3 = _mm_loadu_si128((__m128i*)(userkey + 16));
+    x2 = _mm_setzero_si128();
+    EXPAND_ASSIST(x0, x1, x2, x3, 255, 1);
+    kp[2] = x0;
+    EXPAND_ASSIST(x3, x1, x2, x0, 170, 1);
+    kp[3] = x3;
+    EXPAND_ASSIST(x0, x1, x2, x3, 255, 2);
+    kp[4] = x0;
+    EXPAND_ASSIST(x3, x1, x2, x0, 170, 2);
+    kp[5] = x3;
+    EXPAND_ASSIST(x0, x1, x2, x3, 255, 4);
+    kp[6] = x0;
+    EXPAND_ASSIST(x3, x1, x2, x0, 170, 4);
+    kp[7] = x3;
+    EXPAND_ASSIST(x0, x1, x2, x3, 255, 8);
+    kp[8] = x0;
+    EXPAND_ASSIST(x3, x1, x2, x0, 170, 8);
+    kp[9] = x3;
+    EXPAND_ASSIST(x0, x1, x2, x3, 255, 16);
+    kp[10] = x0;
+    EXPAND_ASSIST(x3, x1, x2, x0, 170, 16);
+    kp[11] = x3;
+    EXPAND_ASSIST(x0, x1, x2, x3, 255, 32);
+    kp[12] = x0;
+    EXPAND_ASSIST(x3, x1, x2, x0, 170, 32);
+    kp[13] = x3;
+    EXPAND_ASSIST(x0, x1, x2, x3, 255, 64);
+    kp[14] = x0;
+}
+
+static int AES_set_encrypt_key(const unsigned char* userKey, const int bits, AES_KEY* key) {
+    if (bits == 128) {
+        AES_128_Key_Expansion(userKey, key);
+    } else if (bits == 192) {
+        AES_192_Key_Expansion(userKey, key);
+    } else if (bits == 256) {
+        AES_256_Key_Expansion(userKey, key);
+    }
+#if (OCB_KEY_LEN == 0)
+    key->rounds = 6 + bits / 32;
+#endif
+    return 0;
+}
+
+static void AES_set_decrypt_key_fast(AES_KEY* dkey, const AES_KEY* ekey) {
+    int j = 0;
+    int i = ROUNDS(ekey);
+#if (OCB_KEY_LEN == 0)
+    dkey->rounds = i;
+#endif
+    dkey->rd_key[i--] = ekey->rd_key[j++];
+    while (i)
+        dkey->rd_key[i--] = _mm_aesimc_si128(ekey->rd_key[j++]);
+    dkey->rd_key[i] = ekey->rd_key[j];
+}
+
+static int AES_set_decrypt_key(const unsigned char* userKey, const int bits, AES_KEY* key) {
+    AES_KEY temp_key;
+    AES_set_encrypt_key(userKey, bits, &temp_key);
+    AES_set_decrypt_key_fast(key, &temp_key);
+    return 0;
+}
+
+static inline void AES_encrypt(const unsigned char* in, unsigned char* out, const AES_KEY* key) {
+    int j, rnds = ROUNDS(key);
+    const __m128i* sched = ((__m128i*)(key->rd_key));
+    __m128i tmp = _mm_load_si128((__m128i*)in);
+    tmp = _mm_xor_si128(tmp, sched[0]);
+    for (j = 1; j < rnds; j++)
+        tmp = _mm_aesenc_si128(tmp, sched[j]);
+    tmp = _mm_aesenclast_si128(tmp, sched[j]);
+    _mm_store_si128((__m128i*)out, tmp);
+}
+
+static inline void AES_decrypt(const unsigned char* in, unsigned char* out, const AES_KEY* key) {
+    int j, rnds = ROUNDS(key);
+    const __m128i* sched = ((__m128i*)(key->rd_key));
+    __m128i tmp = _mm_load_si128((__m128i*)in);
+    tmp = _mm_xor_si128(tmp, sched[0]);
+    for (j = 1; j < rnds; j++)
+        tmp = _mm_aesdec_si128(tmp, sched[j]);
+    tmp = _mm_aesdeclast_si128(tmp, sched[j]);
+    _mm_store_si128((__m128i*)out, tmp);
+}
+
+static inline void AES_ecb_encrypt_blks(block* blks, unsigned nblks, AES_KEY* key) {
+    unsigned i, j, rnds = ROUNDS(key);
+    const __m128i* sched = ((__m128i*)(key->rd_key));
+    for (i = 0; i < nblks; ++i)
+        blks[i] = _mm_xor_si128(blks[i], sched[0]);
+    for (j = 1; j < rnds; ++j)
+        for (i = 0; i < nblks; ++i)
+            blks[i] = _mm_aesenc_si128(blks[i], sched[j]);
+    for (i = 0; i < nblks; ++i)
+        blks[i] = _mm_aesenclast_si128(blks[i], sched[j]);
+}
+
+static inline void AES_ecb_decrypt_blks(block* blks, unsigned nblks, AES_KEY* key) {
+    unsigned i, j, rnds = ROUNDS(key);
+    const __m128i* sched = ((__m128i*)(key->rd_key));
+    for (i = 0; i < nblks; ++i)
+        blks[i] = _mm_xor_si128(blks[i], sched[0]);
+    for (j = 1; j < rnds; ++j)
+        for (i = 0; i < nblks; ++i)
+            blks[i] = _mm_aesdec_si128(blks[i], sched[j]);
+    for (i = 0; i < nblks; ++i)
+        blks[i] = _mm_aesdeclast_si128(blks[i], sched[j]);
+}
+
+#define BPI 8 /* Number of blocks in buffer per ECB call   */
+/* Set to 4 for Westmere, 8 for Sandy Bridge */
+
+#endif
+
+/* ----------------------------------------------------------------------- */
+/* Define OCB context structure.                                           */
+/* ----------------------------------------------------------------------- */
+
+/*------------------------------------------------------------------------
+/ Each item in the OCB context is stored either "memory correct" or
+/ "register correct". On big-endian machines, this is identical. On
+/ little-endian machines, one must choose whether the byte-string
+/ is in the correct order when it resides in memory or in registers.
+/ It must be register correct whenever it is to be manipulated
+/ arithmetically, but must be memory correct whenever it interacts
+/ with the plaintext or ciphertext.
+/------------------------------------------------------------------------- */
+
+struct _ae_ctx {
+    block offset;        /* Memory correct               */
+    block checksum;      /* Memory correct               */
+    block Lstar;         /* Memory correct               */
+    block Ldollar;       /* Memory correct               */
+    block L[L_TABLE_SZ]; /* Memory correct               */
+    block ad_checksum;   /* Memory correct               */
+    block ad_offset;     /* Memory correct               */
+    block cached_Top;    /* Memory correct               */
+    uint64_t KtopStr[3]; /* Register correct, each item  */
+    uint32_t ad_blocks_processed;
+    uint32_t blocks_processed;
+    AES_KEY decrypt_key;
+    AES_KEY encrypt_key;
+#if (OCB_TAG_LEN == 0)
+    unsigned tag_len;
+#endif
+};
+
+/* ----------------------------------------------------------------------- */
+/* L table lookup (or on-the-fly generation)                               */
+/* ----------------------------------------------------------------------- */
+
+#if L_TABLE_SZ_IS_ENOUGH
+#define getL(_ctx, _tz) ((_ctx)->L[_tz])
+#else
+static block getL(const ae_ctx* ctx, unsigned tz) {
+    if (tz < L_TABLE_SZ)
+        return ctx->L[tz];
+    else {
+        unsigned i;
+        /* Bring L[MAX] into registers, make it register correct */
+        block rval = swap_if_le(ctx->L[L_TABLE_SZ - 1]);
+        rval = double_block(rval);
+        for (i = L_TABLE_SZ; i < tz; i++)
+            rval = double_block(rval);
+        return swap_if_le(rval); /* To memory correct */
+    }
+}
+#endif
+
+/* ----------------------------------------------------------------------- */
+/* Public functions                                                        */
+/* ----------------------------------------------------------------------- */
+
+/* 32-bit SSE2 and Altivec systems need to be forced to allocate memory
+   on 16-byte alignments. (I believe all major 64-bit systems do already.) */
+
+ae_ctx* ae_allocate(void* misc) {
+    void* p;
+    (void)misc; /* misc unused in this implementation */
+#if (__SSE2__ && !_M_X64 && !_M_AMD64 && !__amd64__)
+    p = _mm_malloc(sizeof(ae_ctx), 16);
+#elif(__ALTIVEC__ && !__PPC64__)
+    if (posix_memalign(&p, 16, sizeof(ae_ctx)) != 0)
+        p = NULL;
+#else
+    p = malloc(sizeof(ae_ctx));
+#endif
+    return (ae_ctx*)p;
+}
+
+void ae_free(ae_ctx* ctx) {
+#if (__SSE2__ && !_M_X64 && !_M_AMD64 && !__amd64__)
+    _mm_free(ctx);
+#else
+    free(ctx);
+#endif
+}
+
+/* ----------------------------------------------------------------------- */
+
+int ae_clear(ae_ctx* ctx) /* Zero ae_ctx and undo initialization          */
+{
+    memset(ctx, 0, sizeof(ae_ctx));
+    return AE_SUCCESS;
+}
+
+int ae_ctx_sizeof(void) {
+    return (int)sizeof(ae_ctx);
+}
+
+/* ----------------------------------------------------------------------- */
+
+int ae_init(ae_ctx* ctx, const void* key, int key_len, int nonce_len, int tag_len) {
+    unsigned i;
+    block tmp_blk;
+
+    if (nonce_len != 12)
+        return AE_NOT_SUPPORTED;
+
+/* Initialize encryption & decryption keys */
+#if (OCB_KEY_LEN > 0)
+    key_len = OCB_KEY_LEN;
+#endif
+    AES_set_encrypt_key((unsigned char*)key, key_len * 8, &ctx->encrypt_key);
+#if USE_AES_NI
+    AES_set_decrypt_key_fast(&ctx->decrypt_key, &ctx->encrypt_key);
+#else
+    AES_set_decrypt_key((unsigned char*)key, (int)(key_len * 8), &ctx->decrypt_key);
+#endif
+
+    /* Zero things that need zeroing */
+    ctx->cached_Top = ctx->ad_checksum = zero_block();
+    ctx->ad_blocks_processed = 0;
+
+    /* Compute key-dependent values */
+    AES_encrypt((unsigned char*)&ctx->cached_Top, (unsigned char*)&ctx->Lstar, &ctx->encrypt_key);
+    tmp_blk = swap_if_le(ctx->Lstar);
+    tmp_blk = double_block(tmp_blk);
+    ctx->Ldollar = swap_if_le(tmp_blk);
+    tmp_blk = double_block(tmp_blk);
+    ctx->L[0] = swap_if_le(tmp_blk);
+    for (i = 1; i < L_TABLE_SZ; i++) {
+        tmp_blk = double_block(tmp_blk);
+        ctx->L[i] = swap_if_le(tmp_blk);
+    }
+
+#if (OCB_TAG_LEN == 0)
+    ctx->tag_len = tag_len;
+#else
+    (void)tag_len; /* Suppress var not used error */
+#endif
+
+    return AE_SUCCESS;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static block gen_offset_from_nonce(ae_ctx* ctx, const void* nonce) {
+    const union {
+        unsigned x;
+        unsigned char endian;
+    } little = {1};
+    union {
+        uint32_t u32[4];
+        uint8_t u8[16];
+        block bl;
+    } tmp;
+    unsigned idx;
+
+/* Replace cached nonce Top if needed */
+#if (OCB_TAG_LEN > 0)
+    if (little.endian)
+        tmp.u32[0] = 0x01000000 + ((OCB_TAG_LEN * 8 % 128) << 1);
+    else
+        tmp.u32[0] = 0x00000001 + ((OCB_TAG_LEN * 8 % 128) << 25);
+#else
+    if (little.endian)
+        tmp.u32[0] = 0x01000000 + ((ctx->tag_len * 8 % 128) << 1);
+    else
+        tmp.u32[0] = 0x00000001 + ((ctx->tag_len * 8 % 128) << 25);
+#endif
+    tmp.u32[1] = ((uint32_t*)nonce)[0];
+    tmp.u32[2] = ((uint32_t*)nonce)[1];
+    tmp.u32[3] = ((uint32_t*)nonce)[2];
+    idx = (unsigned)(tmp.u8[15] & 0x3f);           /* Get low 6 bits of nonce  */
+    tmp.u8[15] = tmp.u8[15] & 0xc0;                /* Zero low 6 bits of nonce */
+    if (unequal_blocks(tmp.bl, ctx->cached_Top)) { /* Cached?       */
+        ctx->cached_Top = tmp.bl;                  /* Update cache, KtopStr    */
+        AES_encrypt(tmp.u8, (unsigned char*)&ctx->KtopStr, &ctx->encrypt_key);
+        if (little.endian) { /* Make Register Correct    */
+            ctx->KtopStr[0] = bswap64(ctx->KtopStr[0]);
+            ctx->KtopStr[1] = bswap64(ctx->KtopStr[1]);
+        }
+        ctx->KtopStr[2] = ctx->KtopStr[0] ^ (ctx->KtopStr[0] << 8) ^ (ctx->KtopStr[1] >> 56);
+    }
+    return gen_offset(ctx->KtopStr, idx);
+}
+
+static void process_ad(ae_ctx* ctx, const void* ad, int ad_len, int final) {
+    union {
+        uint32_t u32[4];
+        uint8_t u8[16];
+        block bl;
+    } tmp;
+    block ad_offset, ad_checksum;
+    const block* adp = (block*)ad;
+    unsigned i, k, tz, remaining;
+
+    ad_offset = ctx->ad_offset;
+    ad_checksum = ctx->ad_checksum;
+    i = ad_len / (BPI * 16);
+    if (i) {
+        unsigned ad_block_num = ctx->ad_blocks_processed;
+        do {
+            block ta[BPI], oa[BPI];
+            ad_block_num += BPI;
+            tz = ntz(ad_block_num);
+            oa[0] = xor_block(ad_offset, ctx->L[0]);
+            ta[0] = xor_block(oa[0], adp[0]);
+            oa[1] = xor_block(oa[0], ctx->L[1]);
+            ta[1] = xor_block(oa[1], adp[1]);
+            oa[2] = xor_block(ad_offset, ctx->L[1]);
+            ta[2] = xor_block(oa[2], adp[2]);
+#if BPI == 4
+            ad_offset = xor_block(oa[2], getL(ctx, tz));
+            ta[3] = xor_block(ad_offset, adp[3]);
+#elif BPI == 8
+            oa[3] = xor_block(oa[2], ctx->L[2]);
+            ta[3] = xor_block(oa[3], adp[3]);
+            oa[4] = xor_block(oa[1], ctx->L[2]);
+            ta[4] = xor_block(oa[4], adp[4]);
+            oa[5] = xor_block(oa[0], ctx->L[2]);
+            ta[5] = xor_block(oa[5], adp[5]);
+            oa[6] = xor_block(ad_offset, ctx->L[2]);
+            ta[6] = xor_block(oa[6], adp[6]);
+            ad_offset = xor_block(oa[6], getL(ctx, tz));
+            ta[7] = xor_block(ad_offset, adp[7]);
+#endif
+            AES_ecb_encrypt_blks(ta, BPI, &ctx->encrypt_key);
+            ad_checksum = xor_block(ad_checksum, ta[0]);
+            ad_checksum = xor_block(ad_checksum, ta[1]);
+            ad_checksum = xor_block(ad_checksum, ta[2]);
+            ad_checksum = xor_block(ad_checksum, ta[3]);
+#if (BPI == 8)
+            ad_checksum = xor_block(ad_checksum, ta[4]);
+            ad_checksum = xor_block(ad_checksum, ta[5]);
+            ad_checksum = xor_block(ad_checksum, ta[6]);
+            ad_checksum = xor_block(ad_checksum, ta[7]);
+#endif
+            adp += BPI;
+        } while (--i);
+        ctx->ad_blocks_processed = ad_block_num;
+        ctx->ad_offset = ad_offset;
+        ctx->ad_checksum = ad_checksum;
+    }
+
+    if (final) {
+        block ta[BPI];
+
+        /* Process remaining associated data, compute its tag contribution */
+        remaining = ((unsigned)ad_len) % (BPI * 16);
+        if (remaining) {
+            k = 0;
+#if (BPI == 8)
+            if (remaining >= 64) {
+                tmp.bl = xor_block(ad_offset, ctx->L[0]);
+                ta[0] = xor_block(tmp.bl, adp[0]);
+                tmp.bl = xor_block(tmp.bl, ctx->L[1]);
+                ta[1] = xor_block(tmp.bl, adp[1]);
+                ad_offset = xor_block(ad_offset, ctx->L[1]);
+                ta[2] = xor_block(ad_offset, adp[2]);
+                ad_offset = xor_block(ad_offset, ctx->L[2]);
+                ta[3] = xor_block(ad_offset, adp[3]);
+                remaining -= 64;
+                k = 4;
+            }
+#endif
+            if (remaining >= 32) {
+                ad_offset = xor_block(ad_offset, ctx->L[0]);
+                ta[k] = xor_block(ad_offset, adp[k]);
+                ad_offset = xor_block(ad_offset, getL(ctx, ntz(k + 2)));
+                ta[k + 1] = xor_block(ad_offset, adp[k + 1]);
+                remaining -= 32;
+                k += 2;
+            }
+            if (remaining >= 16) {
+                ad_offset = xor_block(ad_offset, ctx->L[0]);
+                ta[k] = xor_block(ad_offset, adp[k]);
+                remaining = remaining - 16;
+                ++k;
+            }
+            if (remaining) {
+                ad_offset = xor_block(ad_offset, ctx->Lstar);
+                tmp.bl = zero_block();
+                memcpy(tmp.u8, adp + k, remaining);
+                tmp.u8[remaining] = (unsigned char)0x80u;
+                ta[k] = xor_block(ad_offset, tmp.bl);
+                ++k;
+            }
+            AES_ecb_encrypt_blks(ta, k, &ctx->encrypt_key);
+            switch (k) {
+#if (BPI == 8)
+            case 8:
+                ad_checksum = xor_block(ad_checksum, ta[7]);
+            case 7:
+                ad_checksum = xor_block(ad_checksum, ta[6]);
+            case 6:
+                ad_checksum = xor_block(ad_checksum, ta[5]);
+            case 5:
+                ad_checksum = xor_block(ad_checksum, ta[4]);
+#endif
+            case 4:
+                ad_checksum = xor_block(ad_checksum, ta[3]);
+            case 3:
+                ad_checksum = xor_block(ad_checksum, ta[2]);
+            case 2:
+                ad_checksum = xor_block(ad_checksum, ta[1]);
+            case 1:
+                ad_checksum = xor_block(ad_checksum, ta[0]);
+            }
+            ctx->ad_checksum = ad_checksum;
+        }
+    }
+}
+
+/* ----------------------------------------------------------------------- */
+
+int ae_encrypt(ae_ctx* ctx, const void* nonce, const void* pt, int pt_len, const void* ad,
+               int ad_len, void* ct, void* tag, int final) {
+    union {
+        uint32_t u32[4];
+        uint8_t u8[16];
+        block bl;
+    } tmp;
+    block offset, checksum;
+    unsigned i, k;
+    block* ctp = (block*)ct;
+    const block* ptp = (block*)pt;
+
+    /* Non-null nonce means start of new message, init per-message values */
+    if (nonce) {
+        ctx->offset = gen_offset_from_nonce(ctx, nonce);
+        ctx->ad_offset = ctx->checksum = zero_block();
+        ctx->ad_blocks_processed = ctx->blocks_processed = 0;
+        if (ad_len >= 0)
+            ctx->ad_checksum = zero_block();
+    }
+
+    /* Process associated data */
+    if (ad_len > 0)
+        process_ad(ctx, ad, ad_len, final);
+
+    /* Encrypt plaintext data BPI blocks at a time */
+    offset = ctx->offset;
+    checksum = ctx->checksum;
+    i = pt_len / (BPI * 16);
+    if (i) {
+        block oa[BPI];
+        unsigned block_num = ctx->blocks_processed;
+        oa[BPI - 1] = offset;
+        do {
+            block ta[BPI];
+            block_num += BPI;
+            oa[0] = xor_block(oa[BPI - 1], ctx->L[0]);
+            ta[0] = xor_block(oa[0], ptp[0]);
+            checksum = xor_block(checksum, ptp[0]);
+            oa[1] = xor_block(oa[0], ctx->L[1]);
+            ta[1] = xor_block(oa[1], ptp[1]);
+            checksum = xor_block(checksum, ptp[1]);
+            oa[2] = xor_block(oa[1], ctx->L[0]);
+            ta[2] = xor_block(oa[2], ptp[2]);
+            checksum = xor_block(checksum, ptp[2]);
+#if BPI == 4
+            oa[3] = xor_block(oa[2], getL(ctx, ntz(block_num)));
+            ta[3] = xor_block(oa[3], ptp[3]);
+            checksum = xor_block(checksum, ptp[3]);
+#elif BPI == 8
+            oa[3] = xor_block(oa[2], ctx->L[2]);
+            ta[3] = xor_block(oa[3], ptp[3]);
+            checksum = xor_block(checksum, ptp[3]);
+            oa[4] = xor_block(oa[1], ctx->L[2]);
+            ta[4] = xor_block(oa[4], ptp[4]);
+            checksum = xor_block(checksum, ptp[4]);
+            oa[5] = xor_block(oa[0], ctx->L[2]);
+            ta[5] = xor_block(oa[5], ptp[5]);
+            checksum = xor_block(checksum, ptp[5]);
+            oa[6] = xor_block(oa[7], ctx->L[2]);
+            ta[6] = xor_block(oa[6], ptp[6]);
+            checksum = xor_block(checksum, ptp[6]);
+            oa[7] = xor_block(oa[6], getL(ctx, ntz(block_num)));
+            ta[7] = xor_block(oa[7], ptp[7]);
+            checksum = xor_block(checksum, ptp[7]);
+#endif
+            AES_ecb_encrypt_blks(ta, BPI, &ctx->encrypt_key);
+            ctp[0] = xor_block(ta[0], oa[0]);
+            ctp[1] = xor_block(ta[1], oa[1]);
+            ctp[2] = xor_block(ta[2], oa[2]);
+            ctp[3] = xor_block(ta[3], oa[3]);
+#if (BPI == 8)
+            ctp[4] = xor_block(ta[4], oa[4]);
+            ctp[5] = xor_block(ta[5], oa[5]);
+            ctp[6] = xor_block(ta[6], oa[6]);
+            ctp[7] = xor_block(ta[7], oa[7]);
+#endif
+            ptp += BPI;
+            ctp += BPI;
+        } while (--i);
+        ctx->offset = offset = oa[BPI - 1];
+        ctx->blocks_processed = block_num;
+        ctx->checksum = checksum;
+    }
+
+    if (final) {
+        block ta[BPI + 1], oa[BPI];
+
+        /* Process remaining plaintext and compute its tag contribution    */
+        unsigned remaining = ((unsigned)pt_len) % (BPI * 16);
+        k = 0; /* How many blocks in ta[] need ECBing */
+        if (remaining) {
+#if (BPI == 8)
+            if (remaining >= 64) {
+                oa[0] = xor_block(offset, ctx->L[0]);
+                ta[0] = xor_block(oa[0], ptp[0]);
+                checksum = xor_block(checksum, ptp[0]);
+                oa[1] = xor_block(oa[0], ctx->L[1]);
+                ta[1] = xor_block(oa[1], ptp[1]);
+                checksum = xor_block(checksum, ptp[1]);
+                oa[2] = xor_block(oa[1], ctx->L[0]);
+                ta[2] = xor_block(oa[2], ptp[2]);
+                checksum = xor_block(checksum, ptp[2]);
+                offset = oa[3] = xor_block(oa[2], ctx->L[2]);
+                ta[3] = xor_block(offset, ptp[3]);
+                checksum = xor_block(checksum, ptp[3]);
+                remaining -= 64;
+                k = 4;
+            }
+#endif
+            if (remaining >= 32) {
+                oa[k] = xor_block(offset, ctx->L[0]);
+                ta[k] = xor_block(oa[k], ptp[k]);
+                checksum = xor_block(checksum, ptp[k]);
+                offset = oa[k + 1] = xor_block(oa[k], ctx->L[1]);
+                ta[k + 1] = xor_block(offset, ptp[k + 1]);
+                checksum = xor_block(checksum, ptp[k + 1]);
+                remaining -= 32;
+                k += 2;
+            }
+            if (remaining >= 16) {
+                offset = oa[k] = xor_block(offset, ctx->L[0]);
+                ta[k] = xor_block(offset, ptp[k]);
+                checksum = xor_block(checksum, ptp[k]);
+                remaining -= 16;
+                ++k;
+            }
+            if (remaining) {
+                tmp.bl = zero_block();
+                memcpy(tmp.u8, ptp + k, remaining);
+                tmp.u8[remaining] = (unsigned char)0x80u;
+                checksum = xor_block(checksum, tmp.bl);
+                ta[k] = offset = xor_block(offset, ctx->Lstar);
+                ++k;
+            }
+        }
+        offset = xor_block(offset, ctx->Ldollar); /* Part of tag gen */
+        ta[k] = xor_block(offset, checksum);      /* Part of tag gen */
+        AES_ecb_encrypt_blks(ta, k + 1, &ctx->encrypt_key);
+        offset = xor_block(ta[k], ctx->ad_checksum); /* Part of tag gen */
+        if (remaining) {
+            --k;
+            tmp.bl = xor_block(tmp.bl, ta[k]);
+            memcpy(ctp + k, tmp.u8, remaining);
+        }
+        switch (k) {
+#if (BPI == 8)
+        case 7:
+            ctp[6] = xor_block(ta[6], oa[6]);
+        case 6:
+            ctp[5] = xor_block(ta[5], oa[5]);
+        case 5:
+            ctp[4] = xor_block(ta[4], oa[4]);
+        case 4:
+            ctp[3] = xor_block(ta[3], oa[3]);
+#endif
+        case 3:
+            ctp[2] = xor_block(ta[2], oa[2]);
+        case 2:
+            ctp[1] = xor_block(ta[1], oa[1]);
+        case 1:
+            ctp[0] = xor_block(ta[0], oa[0]);
+        }
+
+        /* Tag is placed at the correct location
+         */
+        if (tag) {
+#if (OCB_TAG_LEN == 16)
+            *(block*)tag = offset;
+#elif(OCB_TAG_LEN > 0)
+            memcpy((char*)tag, &offset, OCB_TAG_LEN);
+#else
+            memcpy((char*)tag, &offset, ctx->tag_len);
+#endif
+        } else {
+#if (OCB_TAG_LEN > 0)
+            memcpy((char*)ct + pt_len, &offset, OCB_TAG_LEN);
+            pt_len += OCB_TAG_LEN;
+#else
+            memcpy((char*)ct + pt_len, &offset, ctx->tag_len);
+            pt_len += ctx->tag_len;
+#endif
+        }
+    }
+    return (int)pt_len;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* Compare two regions of memory, taking a constant amount of time for a
+   given buffer size -- under certain assumptions about the compiler
+   and machine, of course.
+
+   Use this to avoid timing side-channel attacks.
+
+   Returns 0 for memory regions with equal contents; non-zero otherwise. */
+static int constant_time_memcmp(const void* av, const void* bv, size_t n) {
+    const uint8_t* a = (const uint8_t*)av;
+    const uint8_t* b = (const uint8_t*)bv;
+    uint8_t result = 0;
+    size_t i;
+
+    for (i = 0; i < n; i++) {
+        result |= *a ^ *b;
+        a++;
+        b++;
+    }
+
+    return (int)result;
+}
+
+int ae_decrypt(ae_ctx* ctx, const void* nonce, const void* ct, int ct_len, const void* ad,
+               int ad_len, void* pt, const void* tag, int final) {
+    union {
+        uint32_t u32[4];
+        uint8_t u8[16];
+        block bl;
+    } tmp;
+    block offset, checksum;
+    unsigned i, k;
+    block* ctp = (block*)ct;
+    block* ptp = (block*)pt;
+
+    /* Reduce ct_len tag bundled in ct */
+    if ((final) && (!tag))
+#if (OCB_TAG_LEN > 0)
+        ct_len -= OCB_TAG_LEN;
+#else
+        ct_len -= ctx->tag_len;
+#endif
+
+    /* Non-null nonce means start of new message, init per-message values */
+    if (nonce) {
+        ctx->offset = gen_offset_from_nonce(ctx, nonce);
+        ctx->ad_offset = ctx->checksum = zero_block();
+        ctx->ad_blocks_processed = ctx->blocks_processed = 0;
+        if (ad_len >= 0)
+            ctx->ad_checksum = zero_block();
+    }
+
+    /* Process associated data */
+    if (ad_len > 0)
+        process_ad(ctx, ad, ad_len, final);
+
+    /* Encrypt plaintext data BPI blocks at a time */
+    offset = ctx->offset;
+    checksum = ctx->checksum;
+    i = ct_len / (BPI * 16);
+    if (i) {
+        block oa[BPI];
+        unsigned block_num = ctx->blocks_processed;
+        oa[BPI - 1] = offset;
+        do {
+            block ta[BPI];
+            block_num += BPI;
+            oa[0] = xor_block(oa[BPI - 1], ctx->L[0]);
+            ta[0] = xor_block(oa[0], ctp[0]);
+            oa[1] = xor_block(oa[0], ctx->L[1]);
+            ta[1] = xor_block(oa[1], ctp[1]);
+            oa[2] = xor_block(oa[1], ctx->L[0]);
+            ta[2] = xor_block(oa[2], ctp[2]);
+#if BPI == 4
+            oa[3] = xor_block(oa[2], getL(ctx, ntz(block_num)));
+            ta[3] = xor_block(oa[3], ctp[3]);
+#elif BPI == 8
+            oa[3] = xor_block(oa[2], ctx->L[2]);
+            ta[3] = xor_block(oa[3], ctp[3]);
+            oa[4] = xor_block(oa[1], ctx->L[2]);
+            ta[4] = xor_block(oa[4], ctp[4]);
+            oa[5] = xor_block(oa[0], ctx->L[2]);
+            ta[5] = xor_block(oa[5], ctp[5]);
+            oa[6] = xor_block(oa[7], ctx->L[2]);
+            ta[6] = xor_block(oa[6], ctp[6]);
+            oa[7] = xor_block(oa[6], getL(ctx, ntz(block_num)));
+            ta[7] = xor_block(oa[7], ctp[7]);
+#endif
+            AES_ecb_decrypt_blks(ta, BPI, &ctx->decrypt_key);
+            ptp[0] = xor_block(ta[0], oa[0]);
+            checksum = xor_block(checksum, ptp[0]);
+            ptp[1] = xor_block(ta[1], oa[1]);
+            checksum = xor_block(checksum, ptp[1]);
+            ptp[2] = xor_block(ta[2], oa[2]);
+            checksum = xor_block(checksum, ptp[2]);
+            ptp[3] = xor_block(ta[3], oa[3]);
+            checksum = xor_block(checksum, ptp[3]);
+#if (BPI == 8)
+            ptp[4] = xor_block(ta[4], oa[4]);
+            checksum = xor_block(checksum, ptp[4]);
+            ptp[5] = xor_block(ta[5], oa[5]);
+            checksum = xor_block(checksum, ptp[5]);
+            ptp[6] = xor_block(ta[6], oa[6]);
+            checksum = xor_block(checksum, ptp[6]);
+            ptp[7] = xor_block(ta[7], oa[7]);
+            checksum = xor_block(checksum, ptp[7]);
+#endif
+            ptp += BPI;
+            ctp += BPI;
+        } while (--i);
+        ctx->offset = offset = oa[BPI - 1];
+        ctx->blocks_processed = block_num;
+        ctx->checksum = checksum;
+    }
+
+    if (final) {
+        block ta[BPI + 1], oa[BPI];
+
+        /* Process remaining plaintext and compute its tag contribution    */
+        unsigned remaining = ((unsigned)ct_len) % (BPI * 16);
+        k = 0; /* How many blocks in ta[] need ECBing */
+        if (remaining) {
+#if (BPI == 8)
+            if (remaining >= 64) {
+                oa[0] = xor_block(offset, ctx->L[0]);
+                ta[0] = xor_block(oa[0], ctp[0]);
+                oa[1] = xor_block(oa[0], ctx->L[1]);
+                ta[1] = xor_block(oa[1], ctp[1]);
+                oa[2] = xor_block(oa[1], ctx->L[0]);
+                ta[2] = xor_block(oa[2], ctp[2]);
+                offset = oa[3] = xor_block(oa[2], ctx->L[2]);
+                ta[3] = xor_block(offset, ctp[3]);
+                remaining -= 64;
+                k = 4;
+            }
+#endif
+            if (remaining >= 32) {
+                oa[k] = xor_block(offset, ctx->L[0]);
+                ta[k] = xor_block(oa[k], ctp[k]);
+                offset = oa[k + 1] = xor_block(oa[k], ctx->L[1]);
+                ta[k + 1] = xor_block(offset, ctp[k + 1]);
+                remaining -= 32;
+                k += 2;
+            }
+            if (remaining >= 16) {
+                offset = oa[k] = xor_block(offset, ctx->L[0]);
+                ta[k] = xor_block(offset, ctp[k]);
+                remaining -= 16;
+                ++k;
+            }
+            if (remaining) {
+                block pad;
+                offset = xor_block(offset, ctx->Lstar);
+                AES_encrypt((unsigned char*)&offset, tmp.u8, &ctx->encrypt_key);
+                pad = tmp.bl;
+                memcpy(tmp.u8, ctp + k, remaining);
+                tmp.bl = xor_block(tmp.bl, pad);
+                tmp.u8[remaining] = (unsigned char)0x80u;
+                memcpy(ptp + k, tmp.u8, remaining);
+                checksum = xor_block(checksum, tmp.bl);
+            }
+        }
+        AES_ecb_decrypt_blks(ta, k, &ctx->decrypt_key);
+        switch (k) {
+#if (BPI == 8)
+        case 7:
+            ptp[6] = xor_block(ta[6], oa[6]);
+            checksum = xor_block(checksum, ptp[6]);
+        case 6:
+            ptp[5] = xor_block(ta[5], oa[5]);
+            checksum = xor_block(checksum, ptp[5]);
+        case 5:
+            ptp[4] = xor_block(ta[4], oa[4]);
+            checksum = xor_block(checksum, ptp[4]);
+        case 4:
+            ptp[3] = xor_block(ta[3], oa[3]);
+            checksum = xor_block(checksum, ptp[3]);
+#endif
+        case 3:
+            ptp[2] = xor_block(ta[2], oa[2]);
+            checksum = xor_block(checksum, ptp[2]);
+        case 2:
+            ptp[1] = xor_block(ta[1], oa[1]);
+            checksum = xor_block(checksum, ptp[1]);
+        case 1:
+            ptp[0] = xor_block(ta[0], oa[0]);
+            checksum = xor_block(checksum, ptp[0]);
+        }
+
+        /* Calculate expected tag */
+        offset = xor_block(offset, ctx->Ldollar);
+        tmp.bl = xor_block(offset, checksum);
+        AES_encrypt(tmp.u8, tmp.u8, &ctx->encrypt_key);
+        tmp.bl = xor_block(tmp.bl, ctx->ad_checksum); /* Full tag */
+
+        /* Compare with proposed tag, change ct_len if invalid */
+        if ((OCB_TAG_LEN == 16) && tag) {
+            if (unequal_blocks(tmp.bl, *(block*)tag))
+                ct_len = AE_INVALID;
+        } else {
+#if (OCB_TAG_LEN > 0)
+            int len = OCB_TAG_LEN;
+#else
+            int len = ctx->tag_len;
+#endif
+            if (tag) {
+                if (constant_time_memcmp(tag, tmp.u8, len) != 0)
+                    ct_len = AE_INVALID;
+            } else {
+                if (constant_time_memcmp((char*)ct + ct_len, tmp.u8, len) != 0)
+                    ct_len = AE_INVALID;
+            }
+        }
+    }
+    return ct_len;
+}
+
+/* ----------------------------------------------------------------------- */
+/* Simple test program                                                     */
+/* ----------------------------------------------------------------------- */
+
+#if 0
+
+#include <stdio.h>
+#include <time.h>
+
+#if __GNUC__
+#define ALIGN(n) __attribute__((aligned(n)))
+#elif _MSC_VER
+#define ALIGN(n) __declspec(align(n))
+#else /* Not GNU/Microsoft: delete alignment uses.     */
+#define ALIGN(n)
+#endif
+
+static void pbuf(void *p, unsigned len, const void *s)
+{
+    unsigned i;
+    if (s)
+        printf("%s", (char *)s);
+    for (i = 0; i < len; i++)
+        printf("%02X", (unsigned)(((unsigned char *)p)[i]));
+    printf("\n");
+}
+
+static void vectors(ae_ctx *ctx, int len)
+{
+    ALIGN(16) char pt[128];
+    ALIGN(16) char ct[144];
+    ALIGN(16) char nonce[] = {0,1,2,3,4,5,6,7,8,9,10,11};
+    int i;
+    for (i=0; i < 128; i++) pt[i] = i;
+    i = ae_encrypt(ctx,nonce,pt,len,pt,len,ct,NULL,AE_FINALIZE);
+    printf("P=%d,A=%d: ",len,len); pbuf(ct, i, NULL);
+    i = ae_encrypt(ctx,nonce,pt,0,pt,len,ct,NULL,AE_FINALIZE);
+    printf("P=%d,A=%d: ",0,len); pbuf(ct, i, NULL);
+    i = ae_encrypt(ctx,nonce,pt,len,pt,0,ct,NULL,AE_FINALIZE);
+    printf("P=%d,A=%d: ",len,0); pbuf(ct, i, NULL);
+}
+
+void validate()
+{
+    ALIGN(16) char pt[1024];
+    ALIGN(16) char ct[1024];
+    ALIGN(16) char tag[16];
+    ALIGN(16) char nonce[12] = {0,};
+    ALIGN(16) char key[32] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};
+    ae_ctx ctx;
+    char *val_buf, *next;
+    int i, len;
+
+    val_buf = (char *)malloc(22400 + 16);
+    next = val_buf = (char *)(((size_t)val_buf + 16) & ~((size_t)15));
+
+    if (0) {
+		ae_init(&ctx, key, 16, 12, 16);
+		/* pbuf(&ctx, sizeof(ctx), "CTX: "); */
+		vectors(&ctx,0);
+		vectors(&ctx,8);
+		vectors(&ctx,16);
+		vectors(&ctx,24);
+		vectors(&ctx,32);
+		vectors(&ctx,40);
+    }
+
+    memset(key,0,32);
+    memset(pt,0,128);
+    ae_init(&ctx, key, OCB_KEY_LEN, 12, OCB_TAG_LEN);
+
+    /* RFC Vector test */
+    for (i = 0; i < 128; i++) {
+        int first = ((i/3)/(BPI*16))*(BPI*16);
+        int second = first;
+        int third = i - (first + second);
+
+        nonce[11] = i;
+
+        if (0) {
+            ae_encrypt(&ctx,nonce,pt,i,pt,i,ct,NULL,AE_FINALIZE);
+            memcpy(next,ct,(size_t)i+OCB_TAG_LEN);
+            next = next+i+OCB_TAG_LEN;
+
+            ae_encrypt(&ctx,nonce,pt,i,pt,0,ct,NULL,AE_FINALIZE);
+            memcpy(next,ct,(size_t)i+OCB_TAG_LEN);
+            next = next+i+OCB_TAG_LEN;
+
+            ae_encrypt(&ctx,nonce,pt,0,pt,i,ct,NULL,AE_FINALIZE);
+            memcpy(next,ct,OCB_TAG_LEN);
+            next = next+OCB_TAG_LEN;
+        } else {
+            ae_encrypt(&ctx,nonce,pt,first,pt,first,ct,NULL,AE_PENDING);
+            ae_encrypt(&ctx,NULL,pt+first,second,pt+first,second,ct+first,NULL,AE_PENDING);
+            ae_encrypt(&ctx,NULL,pt+first+second,third,pt+first+second,third,ct+first+second,NULL,AE_FINALIZE);
+            memcpy(next,ct,(size_t)i+OCB_TAG_LEN);
+            next = next+i+OCB_TAG_LEN;
+
+            ae_encrypt(&ctx,nonce,pt,first,pt,0,ct,NULL,AE_PENDING);
+            ae_encrypt(&ctx,NULL,pt+first,second,pt,0,ct+first,NULL,AE_PENDING);
+            ae_encrypt(&ctx,NULL,pt+first+second,third,pt,0,ct+first+second,NULL,AE_FINALIZE);
+            memcpy(next,ct,(size_t)i+OCB_TAG_LEN);
+            next = next+i+OCB_TAG_LEN;
+
+            ae_encrypt(&ctx,nonce,pt,0,pt,first,ct,NULL,AE_PENDING);
+            ae_encrypt(&ctx,NULL,pt,0,pt+first,second,ct,NULL,AE_PENDING);
+            ae_encrypt(&ctx,NULL,pt,0,pt+first+second,third,ct,NULL,AE_FINALIZE);
+            memcpy(next,ct,OCB_TAG_LEN);
+            next = next+OCB_TAG_LEN;
+        }
+
+    }
+    nonce[11] = 0;
+    ae_encrypt(&ctx,nonce,NULL,0,val_buf,next-val_buf,ct,tag,AE_FINALIZE);
+    pbuf(tag,OCB_TAG_LEN,0);
+
+
+    /* Encrypt/Decrypt test */
+    for (i = 0; i < 128; i++) {
+        int first = ((i/3)/(BPI*16))*(BPI*16);
+        int second = first;
+        int third = i - (first + second);
+
+        nonce[11] = i%128;
+
+        if (1) {
+            len = ae_encrypt(&ctx,nonce,val_buf,i,val_buf,i,ct,tag,AE_FINALIZE);
+            len = ae_encrypt(&ctx,nonce,val_buf,i,val_buf,-1,ct,tag,AE_FINALIZE);
+            len = ae_decrypt(&ctx,nonce,ct,len,val_buf,-1,pt,tag,AE_FINALIZE);
+            if (len == -1) { printf("Authentication error: %d\n", i); return; }
+            if (len != i) { printf("Length error: %d\n", i); return; }
+            if (memcmp(val_buf,pt,i)) { printf("Decrypt error: %d\n", i); return; }
+        } else {
+            len = ae_encrypt(&ctx,nonce,val_buf,i,val_buf,i,ct,NULL,AE_FINALIZE);
+            ae_decrypt(&ctx,nonce,ct,first,val_buf,first,pt,NULL,AE_PENDING);
+            ae_decrypt(&ctx,NULL,ct+first,second,val_buf+first,second,pt+first,NULL,AE_PENDING);
+            len = ae_decrypt(&ctx,NULL,ct+first+second,len-(first+second),val_buf+first+second,third,pt+first+second,NULL,AE_FINALIZE);
+            if (len == -1) { printf("Authentication error: %d\n", i); return; }
+            if (memcmp(val_buf,pt,i)) { printf("Decrypt error: %d\n", i); return; }
+        }
+
+    }
+    printf("Decrypt: PASS\n");
+}
+
+int main()
+{
+    validate();
+    return 0;
+}
+#endif
+
+#if USE_AES_NI
+char infoString[] = "OCB3 (AES-NI)";
+#elif USE_REFERENCE_AES
+char infoString[] = "OCB3 (Reference)";
+#elif USE_OPENSSL_AES
+char infoString[] = "OCB3 (OpenSSL)";
+#endif
diff --git a/keymaster/ocb_utils.cpp b/keymaster/ocb_utils.cpp
new file mode 100644
index 0000000..7038da0
--- /dev/null
+++ b/keymaster/ocb_utils.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 "ocb_utils.h"
+
+#include <assert.h>
+
+#include <new>
+
+#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 (std::nothrow) 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 (std::nothrow) uint8_t[SHA256_DIGEST_LENGTH]);
+    if (!hash_buf.get())
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    Eraser hash_eraser(hash_buf.get(), SHA256_DIGEST_LENGTH);
+    UniquePtr<uint8_t[]> derived_key(new (std::nothrow) uint8_t[AES_BLOCK_SIZE]);
+    if (!derived_key.get())
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    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;
+    if (!ctx.get())
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    keymaster_error_t error =
+        InitializeKeyWrappingContext(hw_enforced, sw_enforced, hidden, master_key, &ctx);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    if (!ciphertext->Reset(plaintext.key_material_size))
+        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;
+    }
+    if (!tag->advance_write(OCB_TAG_LENGTH))
+        return KM_ERROR_UNKNOWN_ERROR;
+    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;
+    if (!ctx.get())
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    keymaster_error_t error =
+        InitializeKeyWrappingContext(hw_enforced, sw_enforced, hidden, master_key, &ctx);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    if (!plaintext->Reset(ciphertext.key_material_size))
+        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/keymaster/ocb_utils.h b/keymaster/ocb_utils.h
new file mode 100644
index 0000000..bae1e08
--- /dev/null
+++ b/keymaster/ocb_utils.h
@@ -0,0 +1,48 @@
+/*
+ * 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_OCB_UTILS_H_
+#define SYSTEM_KEYMASTER_OCB_UTILS_H_
+
+#include "ae.h"
+
+#include <hardware/keymaster_defs.h>
+
+#include <keymaster/serializable.h>
+
+namespace keymaster {
+
+class AuthorizationSet;
+struct KeymasterKeyBlob;
+
+static const int OCB_NONCE_LENGTH = 12;
+static const int OCB_TAG_LENGTH = 16;
+
+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
+
+#endif  // SYSTEM_KEYMASTER_OCB_UTILS_H_
diff --git a/keymaster/openssl_err.cpp b/keymaster/openssl_err.cpp
new file mode 100644
index 0000000..078b8e3
--- /dev/null
+++ b/keymaster/openssl_err.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 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 "openssl_err.h"
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+
+#if defined(OPENSSL_IS_BORINGSSL)
+#include <openssl/asn1.h>
+#include <openssl/cipher.h>
+#include <openssl/pkcs8.h>
+#include <openssl/x509v3.h>
+#endif
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/logger.h>
+
+namespace keymaster {
+
+static keymaster_error_t TranslateEvpError(int reason);
+#if defined(OPENSSL_IS_BORINGSSL)
+static keymaster_error_t TranslateASN1Error(int reason);
+static keymaster_error_t TranslateCipherError(int reason);
+static keymaster_error_t TranslatePKCS8Error(int reason);
+static keymaster_error_t TranslateX509v3Error(int reason);
+static keymaster_error_t TranslateRsaError(int reason);
+#endif
+
+keymaster_error_t TranslateLastOpenSslError(bool log_message) {
+    unsigned long error = ERR_peek_last_error();
+
+    if (log_message) {
+        LOG_D("%s", ERR_error_string(error, NULL));
+    }
+
+    int reason = ERR_GET_REASON(error);
+
+    /* Handle global error reasons */
+    switch (reason) {
+    case ERR_R_MALLOC_FAILURE:
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    case ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED:
+    case ERR_R_PASSED_NULL_PARAMETER:
+    case ERR_R_INTERNAL_ERROR:
+    case ERR_R_OVERFLOW:
+        return KM_ERROR_UNKNOWN_ERROR;
+    default:
+        break;
+    }
+
+    switch (ERR_GET_LIB(error)) {
+    case ERR_LIB_USER:
+        return static_cast<keymaster_error_t>(reason);
+    case ERR_LIB_EVP:
+        return TranslateEvpError(reason);
+#if defined(OPENSSL_IS_BORINGSSL)
+    case ERR_LIB_ASN1:
+        return TranslateASN1Error(reason);
+    case ERR_LIB_CIPHER:
+        return TranslateCipherError(reason);
+    case ERR_LIB_PKCS8:
+        return TranslatePKCS8Error(reason);
+    case ERR_LIB_X509V3:
+        return TranslateX509v3Error(reason);
+    case ERR_LIB_RSA:
+        return TranslateRsaError(reason);
+#else
+    case ERR_LIB_ASN1:
+        LOG_E("ASN.1 parsing error %d", reason);
+        return KM_ERROR_INVALID_ARGUMENT;
+#endif
+    }
+
+    LOG_E("Openssl error %d, %d", ERR_GET_LIB(error), reason);
+    return KM_ERROR_UNKNOWN_ERROR;
+}
+
+#if defined(OPENSSL_IS_BORINGSSL)
+
+keymaster_error_t TranslatePKCS8Error(int reason) {
+    switch (reason) {
+    case PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM:
+    case PKCS8_R_UNKNOWN_CIPHER:
+        return KM_ERROR_UNSUPPORTED_ALGORITHM;
+
+    case PKCS8_R_PRIVATE_KEY_ENCODE_ERROR:
+    case PKCS8_R_PRIVATE_KEY_DECODE_ERROR:
+        return KM_ERROR_INVALID_KEY_BLOB;
+
+    case PKCS8_R_ENCODE_ERROR:
+        return KM_ERROR_INVALID_ARGUMENT;
+
+    default:
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+}
+
+keymaster_error_t TranslateCipherError(int reason) {
+    switch (reason) {
+    case CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH:
+    case CIPHER_R_WRONG_FINAL_BLOCK_LENGTH:
+        return KM_ERROR_INVALID_INPUT_LENGTH;
+
+    case CIPHER_R_UNSUPPORTED_KEY_SIZE:
+    case CIPHER_R_BAD_KEY_LENGTH:
+        return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+
+    case CIPHER_R_BAD_DECRYPT:
+        return KM_ERROR_INVALID_ARGUMENT;
+
+    case CIPHER_R_INVALID_KEY_LENGTH:
+        return KM_ERROR_INVALID_KEY_BLOB;
+
+    default:
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+}
+
+keymaster_error_t TranslateASN1Error(int reason) {
+    switch (reason) {
+#if !defined(OPENSSL_IS_BORINGSSL)
+    case ASN1_R_UNSUPPORTED_CIPHER:
+        return KM_ERROR_UNSUPPORTED_ALGORITHM;
+
+    case ASN1_R_ERROR_LOADING_SECTION:
+        return KM_ERROR_INVALID_KEY_BLOB;
+#endif
+
+    case ASN1_R_ENCODE_ERROR:
+        return KM_ERROR_INVALID_ARGUMENT;
+
+    default:
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+}
+
+keymaster_error_t TranslateX509v3Error(int reason) {
+    switch (reason) {
+    case X509V3_R_UNKNOWN_OPTION:
+        return KM_ERROR_UNSUPPORTED_ALGORITHM;
+
+    default:
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+}
+
+keymaster_error_t TranslateRsaError(int reason) {
+    switch (reason) {
+    case RSA_R_KEY_SIZE_TOO_SMALL:
+        LOG_W("RSA key is too small to use with selected padding/digest", 0);
+        return KM_ERROR_INCOMPATIBLE_PADDING_MODE;
+    case RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE:
+    case RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE:
+        return KM_ERROR_INVALID_INPUT_LENGTH;
+    case RSA_R_DATA_TOO_LARGE_FOR_MODULUS:
+        return KM_ERROR_INVALID_ARGUMENT;
+    default:
+        return KM_ERROR_UNKNOWN_ERROR;
+    };
+}
+
+#endif  // OPENSSL_IS_BORINGSSL
+
+keymaster_error_t TranslateEvpError(int reason) {
+    switch (reason) {
+
+#if !defined(OPENSSL_IS_BORINGSSL)
+    case EVP_R_UNKNOWN_DIGEST:
+        return KM_ERROR_UNSUPPORTED_DIGEST;
+
+    case EVP_R_UNSUPPORTED_PRF:
+    case EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM:
+    case EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION:
+    case EVP_R_UNSUPPORTED_SALT_TYPE:
+    case EVP_R_UNKNOWN_PBE_ALGORITHM:
+    case EVP_R_UNSUPORTED_NUMBER_OF_ROUNDS:
+    case EVP_R_UNSUPPORTED_CIPHER:
+    case EVP_R_PKCS8_UNKNOWN_BROKEN_TYPE:
+    case EVP_R_UNKNOWN_CIPHER:
+#endif
+    case EVP_R_UNSUPPORTED_ALGORITHM:
+    case EVP_R_OPERATON_NOT_INITIALIZED:
+    case EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE:
+        return KM_ERROR_UNSUPPORTED_ALGORITHM;
+
+#if !defined(OPENSSL_IS_BORINGSSL)
+    case EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH:
+    case EVP_R_WRONG_FINAL_BLOCK_LENGTH:
+        return KM_ERROR_INVALID_INPUT_LENGTH;
+
+    case EVP_R_UNSUPPORTED_KEYLENGTH:
+    case EVP_R_BAD_KEY_LENGTH:
+        return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+#endif
+
+#if !defined(OPENSSL_IS_BORINGSSL)
+    case EVP_R_BAD_BLOCK_LENGTH:
+    case EVP_R_BN_DECODE_ERROR:
+    case EVP_R_BN_PUBKEY_ERROR:
+    case EVP_R_CIPHER_PARAMETER_ERROR:
+    case EVP_R_ERROR_LOADING_SECTION:
+    case EVP_R_EXPECTING_A_DH_KEY:
+    case EVP_R_EXPECTING_A_ECDSA_KEY:
+    case EVP_R_EXPECTING_A_EC_KEY:
+    case EVP_R_INVALID_DIGEST:
+    case EVP_R_INVALID_KEY_LENGTH:
+    case EVP_R_NO_DSA_PARAMETERS:
+    case EVP_R_PRIVATE_KEY_DECODE_ERROR:
+    case EVP_R_PRIVATE_KEY_ENCODE_ERROR:
+    case EVP_R_PUBLIC_KEY_NOT_RSA:
+    case EVP_R_WRONG_PUBLIC_KEY_TYPE:
+#endif
+    case EVP_R_BUFFER_TOO_SMALL:
+    case EVP_R_EXPECTING_AN_RSA_KEY:
+    case EVP_R_EXPECTING_A_DSA_KEY:
+    case EVP_R_MISSING_PARAMETERS:
+        return KM_ERROR_INVALID_KEY_BLOB;
+
+#if !defined(OPENSSL_IS_BORINGSSL)
+    case EVP_R_BAD_DECRYPT:
+    case EVP_R_ENCODE_ERROR:
+#endif
+    case EVP_R_DIFFERENT_PARAMETERS:
+    case EVP_R_DECODE_ERROR:
+        return KM_ERROR_INVALID_ARGUMENT;
+
+    case EVP_R_DIFFERENT_KEY_TYPES:
+        return KM_ERROR_INCOMPATIBLE_ALGORITHM;
+    }
+
+    return KM_ERROR_UNKNOWN_ERROR;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/openssl_err.h b/keymaster/openssl_err.h
new file mode 100644
index 0000000..8f97ef5
--- /dev/null
+++ b/keymaster/openssl_err.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 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_OPENSSL_ERR_H_
+#define SYSTEM_KEYMASTER_OPENSSL_ERR_H_
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/logger.h>
+
+namespace keymaster {
+
+/**
+ * Translate the last OpenSSL error to a keymaster error.  Does not remove the error from the queue.
+ */
+keymaster_error_t TranslateLastOpenSslError(bool log_message = true);
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_OPENSSL_ERR_H_
diff --git a/keymaster/openssl_utils.cpp b/keymaster/openssl_utils.cpp
new file mode 100644
index 0000000..5d2cb1c
--- /dev/null
+++ b/keymaster/openssl_utils.cpp
@@ -0,0 +1,142 @@
+/*
+ * 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 "openssl_utils.h"
+
+#include <keymaster/android_keymaster_utils.h>
+
+#include "openssl_err.h"
+
+namespace keymaster {
+
+keymaster_error_t ec_get_group_size(const EC_GROUP* group, size_t* key_size_bits) {
+    switch (EC_GROUP_get_curve_name(group)) {
+    case NID_secp224r1:
+        *key_size_bits = 224;
+        break;
+    case NID_X9_62_prime256v1:
+        *key_size_bits = 256;
+        break;
+    case NID_secp384r1:
+        *key_size_bits = 384;
+        break;
+    case NID_secp521r1:
+        *key_size_bits = 521;
+        break;
+    default:
+        return KM_ERROR_UNSUPPORTED_EC_FIELD;
+    }
+    return KM_ERROR_OK;
+}
+
+EC_GROUP* ec_get_group(keymaster_ec_curve_t curve) {
+    switch (curve) {
+    case KM_EC_CURVE_P_224:
+        return EC_GROUP_new_by_curve_name(NID_secp224r1);
+        break;
+    case KM_EC_CURVE_P_256:
+        return EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+        break;
+    case KM_EC_CURVE_P_384:
+        return EC_GROUP_new_by_curve_name(NID_secp384r1);
+        break;
+    case KM_EC_CURVE_P_521:
+        return EC_GROUP_new_by_curve_name(NID_secp521r1);
+        break;
+    default:
+        return nullptr;
+        break;
+    }
+}
+
+void convert_bn_to_blob(BIGNUM* bn, keymaster_blob_t* blob) {
+    blob->data_length = BN_num_bytes(bn);
+    blob->data = new uint8_t[blob->data_length];
+    BN_bn2bin(bn, const_cast<uint8_t*>(blob->data));
+}
+
+static int convert_to_evp(keymaster_algorithm_t algorithm) {
+    switch (algorithm) {
+    case KM_ALGORITHM_RSA:
+        return EVP_PKEY_RSA;
+    case KM_ALGORITHM_EC:
+        return EVP_PKEY_EC;
+    default:
+        return -1;
+    };
+}
+
+keymaster_error_t convert_pkcs8_blob_to_evp(const uint8_t* key_data, size_t key_length,
+                                            keymaster_algorithm_t expected_algorithm,
+                                            UniquePtr<EVP_PKEY, EVP_PKEY_Delete>* pkey) {
+    if (key_data == NULL || key_length <= 0)
+        return KM_ERROR_INVALID_KEY_BLOB;
+
+    UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> pkcs8(
+        d2i_PKCS8_PRIV_KEY_INFO(NULL, &key_data, key_length));
+    if (pkcs8.get() == NULL)
+        return TranslateLastOpenSslError(true /* log_message */);
+
+    pkey->reset(EVP_PKCS82PKEY(pkcs8.get()));
+    if (!pkey->get())
+        return TranslateLastOpenSslError(true /* log_message */);
+
+    if (EVP_PKEY_type((*pkey)->type) != convert_to_evp(expected_algorithm)) {
+        LOG_E("EVP key algorithm was %d, not the expected %d", EVP_PKEY_type((*pkey)->type),
+              convert_to_evp(expected_algorithm));
+        return KM_ERROR_INVALID_KEY_BLOB;
+    }
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t KeyMaterialToEvpKey(keymaster_key_format_t key_format,
+                                      const KeymasterKeyBlob& key_material,
+                                      keymaster_algorithm_t expected_algorithm,
+                                      UniquePtr<EVP_PKEY, EVP_PKEY_Delete>* pkey) {
+    if (key_format != KM_KEY_FORMAT_PKCS8)
+        return KM_ERROR_UNSUPPORTED_KEY_FORMAT;
+
+    return convert_pkcs8_blob_to_evp(key_material.key_material, key_material.key_material_size,
+                                     expected_algorithm, pkey);
+}
+
+keymaster_error_t 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();
+
+    if (!key_blob->Reset(key_data_size))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    uint8_t* tmp = key_blob->writable_data();
+    i2d_PrivateKey(pkey, &tmp);
+
+    return KM_ERROR_OK;
+}
+
+size_t ec_group_size_bits(EC_KEY* ec_key) {
+    const EC_GROUP* group = EC_KEY_get0_group(ec_key);
+    UniquePtr<BN_CTX, BN_CTX_Delete> bn_ctx(BN_CTX_new());
+    UniquePtr<BIGNUM, BIGNUM_Delete> order(BN_new());
+    if (!EC_GROUP_get_order(group, order.get(), bn_ctx.get())) {
+        LOG_E("Failed to get EC group order", 0);
+        return 0;
+    }
+    return BN_num_bits(order.get());
+}
+
+}  // namespace keymaster
diff --git a/keymaster/openssl_utils.h b/keymaster/openssl_utils.h
new file mode 100644
index 0000000..034b129
--- /dev/null
+++ b/keymaster/openssl_utils.h
@@ -0,0 +1,99 @@
+/*
+ * 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_OPENSSL_UTILS_H_
+#define SYSTEM_KEYMASTER_OPENSSL_UTILS_H_
+
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/engine.h>
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+#include <openssl/x509.h>
+
+#include <UniquePtr.h>
+
+#include <hardware/keymaster_defs.h>
+
+namespace keymaster {
+
+struct KeymasterKeyBlob;
+
+class EvpMdCtxCleaner {
+  public:
+    explicit EvpMdCtxCleaner(EVP_MD_CTX* ctx) : ctx_(ctx) {}
+    ~EvpMdCtxCleaner() { EVP_MD_CTX_cleanup(ctx_); }
+
+  private:
+    EVP_MD_CTX* ctx_;
+};
+
+template <typename T, void (*FreeFunc)(T*)> struct OpenSslObjectDeleter {
+    void operator()(T* p) { FreeFunc(p); }
+};
+
+#define DEFINE_OPENSSL_OBJECT_POINTER(name)                                                        \
+    typedef OpenSslObjectDeleter<name, name##_free> name##_Delete;                                 \
+    typedef UniquePtr<name, name##_Delete> name##_Ptr;
+
+DEFINE_OPENSSL_OBJECT_POINTER(ASN1_INTEGER)
+DEFINE_OPENSSL_OBJECT_POINTER(ASN1_OBJECT)
+DEFINE_OPENSSL_OBJECT_POINTER(ASN1_OCTET_STRING)
+DEFINE_OPENSSL_OBJECT_POINTER(ASN1_TIME)
+DEFINE_OPENSSL_OBJECT_POINTER(BN_CTX);
+DEFINE_OPENSSL_OBJECT_POINTER(EC_GROUP);
+DEFINE_OPENSSL_OBJECT_POINTER(EC_KEY);
+DEFINE_OPENSSL_OBJECT_POINTER(EC_POINT);
+DEFINE_OPENSSL_OBJECT_POINTER(ENGINE);
+DEFINE_OPENSSL_OBJECT_POINTER(EVP_PKEY);
+DEFINE_OPENSSL_OBJECT_POINTER(PKCS8_PRIV_KEY_INFO);
+DEFINE_OPENSSL_OBJECT_POINTER(RSA);
+DEFINE_OPENSSL_OBJECT_POINTER(X509)
+DEFINE_OPENSSL_OBJECT_POINTER(X509_EXTENSION)
+DEFINE_OPENSSL_OBJECT_POINTER(X509_NAME)
+
+typedef OpenSslObjectDeleter<BIGNUM, BN_free> BIGNUM_Delete;
+typedef UniquePtr<BIGNUM, BIGNUM_Delete> BIGNUM_Ptr;
+
+keymaster_error_t ec_get_group_size(const EC_GROUP* group, size_t* key_size_bits);
+EC_GROUP* ec_get_group(keymaster_ec_curve_t curve);
+
+/**
+ * Many OpenSSL APIs take ownership of an argument on success but don't free the argument on
+ * failure. This means we need to tell our scoped pointers when we've transferred ownership, without
+ * triggering a warning by not using the result of release().
+ */
+template <typename T, typename Delete_T>
+inline void release_because_ownership_transferred(UniquePtr<T, Delete_T>& p) {
+    T* val __attribute__((unused)) = p.release();
+}
+
+keymaster_error_t convert_pkcs8_blob_to_evp(const uint8_t* key_data, size_t key_length,
+                                            keymaster_algorithm_t expected_algorithm,
+                                            UniquePtr<EVP_PKEY, EVP_PKEY_Delete>* pkey);
+
+keymaster_error_t KeyMaterialToEvpKey(keymaster_key_format_t key_format,
+                                      const KeymasterKeyBlob& key_material,
+                                      keymaster_algorithm_t expected_algorithm,
+                                      UniquePtr<EVP_PKEY, EVP_PKEY_Delete>* evp_pkey);
+
+keymaster_error_t EvpKeyToKeyMaterial(const EVP_PKEY* evp_pkey, KeymasterKeyBlob* key_blob);
+
+size_t ec_group_size_bits(EC_KEY* ec_key);
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_OPENSSL_UTILS_H_
diff --git a/keymaster/operation.cpp b/keymaster/operation.cpp
new file mode 100644
index 0000000..410c9aa
--- /dev/null
+++ b/keymaster/operation.cpp
@@ -0,0 +1,155 @@
+/*
+ * 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 "operation.h"
+
+#include <keymaster/authorization_set.h>
+
+#include "key.h"
+
+namespace keymaster {
+
+bool OperationFactory::supported(keymaster_padding_t padding) const {
+    size_t padding_count;
+    const keymaster_padding_t* supported_paddings = SupportedPaddingModes(&padding_count);
+    for (size_t i = 0; i < padding_count; ++i)
+        if (padding == supported_paddings[i])
+            return true;
+    return false;
+}
+
+bool OperationFactory::supported(keymaster_block_mode_t block_mode) const {
+    size_t block_mode_count;
+    const keymaster_block_mode_t* supported_block_modes = SupportedBlockModes(&block_mode_count);
+    for (size_t i = 0; i < block_mode_count; ++i)
+        if (block_mode == supported_block_modes[i])
+            return true;
+    return false;
+}
+
+bool OperationFactory::supported(keymaster_digest_t digest) const {
+    size_t digest_count;
+    const keymaster_digest_t* supported_digests = SupportedDigests(&digest_count);
+    for (size_t i = 0; i < digest_count; ++i)
+        if (digest == supported_digests[i])
+            return true;
+    return false;
+}
+
+inline bool is_public_key_algorithm(keymaster_algorithm_t algorithm) {
+    switch (algorithm) {
+    case KM_ALGORITHM_HMAC:
+    case KM_ALGORITHM_AES:
+        return false;
+    case KM_ALGORITHM_RSA:
+    case KM_ALGORITHM_EC:
+        return true;
+    }
+
+    // Unreachable.
+    assert(false);
+    return false;
+}
+
+bool OperationFactory::is_public_key_operation() const {
+    KeyType key_type = registry_key();
+
+    if (!is_public_key_algorithm(key_type.algorithm))
+        return false;
+
+    switch (key_type.purpose) {
+    case KM_PURPOSE_VERIFY:
+    case KM_PURPOSE_ENCRYPT:
+        return true;
+    case KM_PURPOSE_SIGN:
+    case KM_PURPOSE_DECRYPT:
+    case KM_PURPOSE_DERIVE_KEY:
+        return false;
+    };
+
+    // Unreachable.
+    assert(false);
+    return false;
+}
+
+bool OperationFactory::GetAndValidatePadding(const AuthorizationSet& begin_params, const Key& key,
+                                             keymaster_padding_t* padding,
+                                             keymaster_error_t* error) const {
+    *error = KM_ERROR_UNSUPPORTED_PADDING_MODE;
+    if (!begin_params.GetTagValue(TAG_PADDING, padding)) {
+        LOG_E("%d padding modes specified in begin params", begin_params.GetTagCount(TAG_PADDING));
+        return false;
+    } else if (!supported(*padding)) {
+        LOG_E("Padding mode %d not supported", *padding);
+        return false;
+    } else if (
+        // If it's a public key operation, all padding modes are authorized.
+        !is_public_key_operation() &&
+        // Otherwise the key needs to authorize the specific mode.
+        !key.authorizations().Contains(TAG_PADDING, *padding) &&
+        !key.authorizations().Contains(TAG_PADDING_OLD, *padding)) {
+        LOG_E("Padding mode %d was specified, but not authorized by key", *padding);
+        *error = KM_ERROR_INCOMPATIBLE_PADDING_MODE;
+        return false;
+    }
+
+    *error = KM_ERROR_OK;
+    return true;
+}
+
+bool OperationFactory::GetAndValidateDigest(const AuthorizationSet& begin_params, const Key& key,
+                                            keymaster_digest_t* digest,
+                                            keymaster_error_t* error) const {
+    *error = KM_ERROR_UNSUPPORTED_DIGEST;
+    if (!begin_params.GetTagValue(TAG_DIGEST, digest)) {
+        LOG_E("%d digests specified in begin params", begin_params.GetTagCount(TAG_DIGEST));
+        return false;
+    } else if (!supported(*digest)) {
+        LOG_E("Digest %d not supported", *digest);
+        return false;
+    } else if (
+        // If it's a public key operation, all digests are authorized.
+        !is_public_key_operation() &&
+        // Otherwise the key needs to authorize the specific digest.
+        !key.authorizations().Contains(TAG_DIGEST, *digest) &&
+        !key.authorizations().Contains(TAG_DIGEST_OLD, *digest)) {
+        LOG_E("Digest %d was specified, but not authorized by key", *digest);
+        *error = KM_ERROR_INCOMPATIBLE_DIGEST;
+        return false;
+    }
+    *error = KM_ERROR_OK;
+    return true;
+}
+
+keymaster_error_t Operation::UpdateForFinish(const AuthorizationSet& input_params,
+                                             const Buffer& input) {
+    if (!input_params.empty() || input.available_read()) {
+        size_t input_consumed;
+        Buffer output;
+        AuthorizationSet output_params;
+        keymaster_error_t error =
+            Update(input_params, input, &output_params, &output, &input_consumed);
+        if (error != KM_ERROR_OK)
+            return error;
+        assert(input_consumed == input.available_read());
+        assert(output_params.empty());
+        assert(output.available_read() == 0);
+    }
+
+    return KM_ERROR_OK;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/operation.h b/keymaster/operation.h
new file mode 100644
index 0000000..aadc406
--- /dev/null
+++ b/keymaster/operation.h
@@ -0,0 +1,126 @@
+/*
+ * 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_OPERATION_H_
+#define SYSTEM_KEYMASTER_OPERATION_H_
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/logger.h>
+
+namespace keymaster {
+
+class AuthorizationSet;
+class Key;
+class Operation;
+
+class OperationFactory {
+  public:
+    virtual ~OperationFactory() {}
+
+    // Required for registry
+    struct KeyType {
+        KeyType(keymaster_algorithm_t alg, keymaster_purpose_t purp)
+            : algorithm(alg), purpose(purp) {}
+
+        keymaster_algorithm_t algorithm;
+        keymaster_purpose_t purpose;
+
+        bool operator==(const KeyType& rhs) const {
+            return algorithm == rhs.algorithm && purpose == rhs.purpose;
+        }
+    };
+    virtual KeyType registry_key() const = 0;
+
+    // Factory methods
+    virtual Operation* CreateOperation(const Key& key, const AuthorizationSet& begin_params,
+                                       keymaster_error_t* error) = 0;
+
+    // Informational methods.  The returned arrays reference static memory and must not be
+    // deallocated or modified.
+    virtual const keymaster_padding_t* SupportedPaddingModes(size_t* padding_count) const {
+        *padding_count = 0;
+        return NULL;
+    }
+    virtual const keymaster_block_mode_t* SupportedBlockModes(size_t* block_mode_count) const {
+        *block_mode_count = 0;
+        return NULL;
+    }
+    virtual const keymaster_digest_t* SupportedDigests(size_t* digest_count) const {
+        *digest_count = 0;
+        return NULL;
+    }
+
+    // Convenience methods
+    bool supported(keymaster_padding_t padding) const;
+    bool supported(keymaster_block_mode_t padding) const;
+    bool supported(keymaster_digest_t padding) const;
+
+    bool is_public_key_operation() const;
+
+    bool GetAndValidatePadding(const AuthorizationSet& begin_params, const Key& key,
+                               keymaster_padding_t* padding, keymaster_error_t* error) const;
+    bool GetAndValidateDigest(const AuthorizationSet& begin_params, const Key& key,
+                              keymaster_digest_t* digest, keymaster_error_t* error) const;
+};
+
+/**
+ * Abstract base for all cryptographic operations.
+ */
+class Operation {
+  public:
+    explicit Operation(keymaster_purpose_t purpose) : purpose_(purpose) {}
+    virtual ~Operation() {}
+
+    keymaster_purpose_t purpose() const { return purpose_; }
+
+    void set_key_id(uint64_t key_id) { key_id_ = key_id; }
+    uint64_t key_id() const { return key_id_; }
+
+    void SetAuthorizations(const AuthorizationSet& auths) {
+        key_auths_.Reinitialize(auths.data(), auths.size());
+    }
+    const AuthorizationSet authorizations() { return key_auths_; }
+
+    virtual keymaster_error_t Begin(const AuthorizationSet& input_params,
+                                    AuthorizationSet* output_params) = 0;
+    virtual keymaster_error_t Update(const AuthorizationSet& input_params, const Buffer& input,
+                                     AuthorizationSet* output_params, Buffer* output,
+                                     size_t* input_consumed) = 0;
+    virtual keymaster_error_t Finish(const AuthorizationSet& input_params, const Buffer& input,
+                                     const Buffer& signature, AuthorizationSet* output_params,
+                                     Buffer* output) = 0;
+    virtual keymaster_error_t Abort() = 0;
+
+protected:
+    // Helper function for implementing Finish() methods that need to call Update() to process
+    // input, but don't expect any output.
+    keymaster_error_t UpdateForFinish(const AuthorizationSet& input_params, const Buffer& input);
+
+  private:
+    const keymaster_purpose_t purpose_;
+    AuthorizationSet key_auths_;
+    uint64_t key_id_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_OPERATION_H_
diff --git a/keymaster/operation_table.cpp b/keymaster/operation_table.cpp
new file mode 100644
index 0000000..d30885e
--- /dev/null
+++ b/keymaster/operation_table.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 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 "operation_table.h"
+
+#include <new>
+
+#include <openssl/rand.h>
+
+#include "openssl_err.h"
+#include "operation.h"
+
+namespace keymaster {
+
+OperationTable::Entry::~Entry() {
+    delete operation;
+    operation = NULL;
+    handle = 0;
+}
+
+keymaster_error_t OperationTable::Add(Operation* operation,
+                                      keymaster_operation_handle_t* op_handle) {
+    if (!table_.get()) {
+        table_.reset(new (std::nothrow) Entry[table_size_]);
+        if (!table_.get())
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    UniquePtr<Operation> op(operation);
+    if (RAND_bytes(reinterpret_cast<uint8_t*>(op_handle), sizeof(*op_handle)) != 1)
+        return TranslateLastOpenSslError();
+    if (*op_handle == 0) {
+        // Statistically this is vanishingly unlikely, which means if it ever happens in practice,
+        // it indicates a broken RNG.
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+
+    for (size_t i = 0; i < table_size_; ++i) {
+        if (table_[i].operation == NULL) {
+            table_[i].operation = op.release();
+            table_[i].handle = *op_handle;
+            return KM_ERROR_OK;
+        }
+    }
+    return KM_ERROR_TOO_MANY_OPERATIONS;
+}
+
+Operation* OperationTable::Find(keymaster_operation_handle_t op_handle) {
+    if (op_handle == 0)
+        return NULL;
+
+    if (!table_.get())
+        return NULL;
+
+    for (size_t i = 0; i < table_size_; ++i) {
+        if (table_[i].handle == op_handle)
+            return table_[i].operation;
+    }
+    return NULL;
+}
+
+bool OperationTable::Delete(keymaster_operation_handle_t op_handle) {
+    if (!table_.get())
+        return false;
+
+    for (size_t i = 0; i < table_size_; ++i) {
+        if (table_[i].handle == op_handle) {
+            delete table_[i].operation;
+            table_[i].operation = NULL;
+            table_[i].handle = 0;
+            return true;
+        }
+    }
+    return false;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/operation_table.h b/keymaster/operation_table.h
new file mode 100644
index 0000000..c840ad9
--- /dev/null
+++ b/keymaster/operation_table.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 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_OPERATION_TABLE_H
+#define SYSTEM_KEYMASTER_OPERATION_TABLE_H
+
+#include <UniquePtr.h>
+
+#include <hardware/keymaster_defs.h>
+
+namespace keymaster {
+
+class Operation;
+
+class OperationTable {
+  public:
+    explicit OperationTable(size_t table_size) : table_size_(table_size) {}
+
+    struct Entry {
+        Entry() {
+            handle = 0;
+            operation = NULL;
+        };
+        ~Entry();
+        keymaster_operation_handle_t handle;
+        Operation* operation;
+    };
+
+    keymaster_error_t Add(Operation* operation, keymaster_operation_handle_t* op_handle);
+    Operation* Find(keymaster_operation_handle_t op_handle);
+    bool Delete(keymaster_operation_handle_t);
+
+  private:
+    UniquePtr<Entry[]> table_;
+    size_t table_size_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_OPERATION_TABLE_H
diff --git a/keymaster/rsa_key.cpp b/keymaster/rsa_key.cpp
new file mode 100644
index 0000000..4231953
--- /dev/null
+++ b/keymaster/rsa_key.cpp
@@ -0,0 +1,70 @@
+/*
+ * 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 "rsa_key.h"
+
+#include <keymaster/keymaster_context.h>
+
+#include "openssl_err.h"
+#include "openssl_utils.h"
+#include "rsa_operation.h"
+
+namespace keymaster {
+
+bool RsaKey::EvpToInternal(const EVP_PKEY* pkey) {
+    rsa_key_.reset(EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>(pkey)));
+    return rsa_key_.get() != NULL;
+}
+
+bool RsaKey::InternalToEvp(EVP_PKEY* pkey) const {
+    return EVP_PKEY_set1_RSA(pkey, rsa_key_.get()) == 1;
+}
+
+bool RsaKey::SupportedMode(keymaster_purpose_t purpose, keymaster_padding_t padding) {
+    switch (purpose) {
+    case KM_PURPOSE_SIGN:
+    case KM_PURPOSE_VERIFY:
+        return padding == KM_PAD_NONE || padding == KM_PAD_RSA_PSS ||
+               padding == KM_PAD_RSA_PKCS1_1_5_SIGN;
+
+    case KM_PURPOSE_ENCRYPT:
+    case KM_PURPOSE_DECRYPT:
+        return padding == KM_PAD_RSA_OAEP || padding == KM_PAD_RSA_PKCS1_1_5_ENCRYPT;
+
+    case KM_PURPOSE_DERIVE_KEY:
+        return false;
+    };
+    return false;
+}
+
+bool RsaKey::SupportedMode(keymaster_purpose_t purpose, keymaster_digest_t digest) {
+    switch (purpose) {
+    case KM_PURPOSE_SIGN:
+    case KM_PURPOSE_VERIFY:
+        return digest == KM_DIGEST_NONE || digest == KM_DIGEST_SHA_2_256;
+
+    case KM_PURPOSE_ENCRYPT:
+    case KM_PURPOSE_DECRYPT:
+        /* Don't care */
+        break;
+
+    case KM_PURPOSE_DERIVE_KEY:
+        return false;
+    };
+    return true;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/rsa_key.h b/keymaster/rsa_key.h
new file mode 100644
index 0000000..502f28a
--- /dev/null
+++ b/keymaster/rsa_key.h
@@ -0,0 +1,55 @@
+/*
+ * 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_RSA_KEY_H_
+#define SYSTEM_KEYMASTER_RSA_KEY_H_
+
+#include <openssl/rsa.h>
+
+#include "asymmetric_key.h"
+
+namespace keymaster {
+
+class RsaKey : public AsymmetricKey {
+  public:
+    RsaKey(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+           keymaster_error_t* error)
+        : AsymmetricKey(hw_enforced, sw_enforced, error) {}
+
+    bool InternalToEvp(EVP_PKEY* pkey) const override;
+    bool EvpToInternal(const EVP_PKEY* pkey) override;
+
+    bool SupportedMode(keymaster_purpose_t purpose, keymaster_padding_t padding);
+    bool SupportedMode(keymaster_purpose_t purpose, keymaster_digest_t digest);
+
+    struct RSA_Delete {
+        void operator()(RSA* p) { RSA_free(p); }
+    };
+
+    RSA* key() const { return rsa_key_.get(); }
+
+  protected:
+    RsaKey(RSA* rsa, const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+           keymaster_error_t* error)
+        : AsymmetricKey(hw_enforced, sw_enforced, error), rsa_key_(rsa) {}
+
+  private:
+    UniquePtr<RSA, RSA_Delete> rsa_key_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_RSA_KEY_H_
diff --git a/keymaster/rsa_key_factory.cpp b/keymaster/rsa_key_factory.cpp
new file mode 100644
index 0000000..e6c3f8c
--- /dev/null
+++ b/keymaster/rsa_key_factory.cpp
@@ -0,0 +1,180 @@
+/*
+ * 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/rsa_key_factory.h>
+
+#include <new>
+
+#include <keymaster/keymaster_context.h>
+
+#include "openssl_err.h"
+#include "openssl_utils.h"
+#include "rsa_key.h"
+#include "rsa_operation.h"
+
+namespace keymaster {
+
+const int kMaximumRsaKeySize = 16 * 1024;  // 16kbits should be enough for anyone.
+
+static RsaSigningOperationFactory sign_factory;
+static RsaVerificationOperationFactory verify_factory;
+static RsaEncryptionOperationFactory encrypt_factory;
+static RsaDecryptionOperationFactory decrypt_factory;
+
+OperationFactory* RsaKeyFactory::GetOperationFactory(keymaster_purpose_t purpose) const {
+    switch (purpose) {
+    case KM_PURPOSE_SIGN:
+        return &sign_factory;
+    case KM_PURPOSE_VERIFY:
+        return &verify_factory;
+    case KM_PURPOSE_ENCRYPT:
+        return &encrypt_factory;
+    case KM_PURPOSE_DECRYPT:
+        return &decrypt_factory;
+    default:
+        return nullptr;
+    }
+}
+
+keymaster_error_t RsaKeyFactory::GenerateKey(const AuthorizationSet& key_description,
+                                             KeymasterKeyBlob* key_blob,
+                                             AuthorizationSet* hw_enforced,
+                                             AuthorizationSet* sw_enforced) const {
+    if (!key_blob || !hw_enforced || !sw_enforced)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    const 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");
+        return KM_ERROR_INVALID_ARGUMENT;
+    }
+
+    uint32_t key_size;
+    if (!authorizations.GetTagValue(TAG_KEY_SIZE, &key_size)) {
+        LOG_E("No key size specified for RSA key generation", 0);
+        return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+    }
+    if (key_size % 8 != 0 || key_size > kMaximumRsaKeySize) {
+        LOG_E("Invalid key size of %u bits specified for RSA key generation", key_size);
+        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)
+        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 */))
+        return TranslateLastOpenSslError();
+
+    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);
+}
+
+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) const {
+    if (!output_key_blob || !hw_enforced || !sw_enforced)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    AuthorizationSet authorizations;
+    uint64_t public_exponent;
+    uint32_t key_size;
+    keymaster_error_t error =
+        UpdateImportKeyDescription(key_description, input_key_material_format, input_key_material,
+                                   &authorizations, &public_exponent, &key_size);
+    if (error != KM_ERROR_OK)
+        return error;
+    return context_->CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material,
+                                   output_key_blob, hw_enforced, sw_enforced);
+}
+
+keymaster_error_t RsaKeyFactory::UpdateImportKeyDescription(const AuthorizationSet& key_description,
+                                                            keymaster_key_format_t key_format,
+                                                            const KeymasterKeyBlob& key_material,
+                                                            AuthorizationSet* updated_description,
+                                                            uint64_t* public_exponent,
+                                                            uint32_t* key_size) const {
+    if (!updated_description || !public_exponent || !key_size)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey;
+    keymaster_error_t error =
+        KeyMaterialToEvpKey(key_format, key_material, keymaster_key_type(), &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())
+        return TranslateLastOpenSslError();
+
+    updated_description->Reinitialize(key_description);
+
+    *public_exponent = BN_get_word(rsa_key->e);
+    if (*public_exponent == 0xffffffffL)
+        return KM_ERROR_INVALID_KEY_BLOB;
+    if (!updated_description->GetTagValue(TAG_RSA_PUBLIC_EXPONENT, public_exponent))
+        updated_description->push_back(TAG_RSA_PUBLIC_EXPONENT, *public_exponent);
+    if (*public_exponent != BN_get_word(rsa_key->e)) {
+        LOG_E("Imported public exponent (%u) does not match specified public exponent (%u)",
+              *public_exponent, BN_get_word(rsa_key->e));
+        return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+    }
+
+    *key_size = RSA_size(rsa_key.get()) * 8;
+    if (!updated_description->GetTagValue(TAG_KEY_SIZE, key_size))
+        updated_description->push_back(TAG_KEY_SIZE, *key_size);
+    if (RSA_size(rsa_key.get()) * 8 != *key_size) {
+        LOG_E("Imported key size (%u bits) does not match specified key size (%u bits)",
+              RSA_size(rsa_key.get()) * 8, *key_size);
+        return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+    }
+
+    keymaster_algorithm_t algorithm = KM_ALGORITHM_RSA;
+    if (!updated_description->GetTagValue(TAG_ALGORITHM, &algorithm))
+        updated_description->push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
+    if (algorithm != KM_ALGORITHM_RSA)
+        return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaKeyFactory::CreateEmptyKey(const AuthorizationSet& hw_enforced,
+                                                const AuthorizationSet& sw_enforced,
+                                                UniquePtr<AsymmetricKey>* key) const {
+    keymaster_error_t error;
+    key->reset(new (std::nothrow) RsaKey(hw_enforced, sw_enforced, &error));
+    if (!key->get())
+        error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    return error;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/rsa_keymaster0_key.cpp b/keymaster/rsa_keymaster0_key.cpp
new file mode 100644
index 0000000..6e5c083
--- /dev/null
+++ b/keymaster/rsa_keymaster0_key.cpp
@@ -0,0 +1,128 @@
+/*
+ * 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 "rsa_keymaster0_key.h"
+
+#include <memory>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/logger.h>
+#include <keymaster/soft_keymaster_context.h>
+
+#include "keymaster0_engine.h"
+#include "openssl_utils.h"
+
+using std::unique_ptr;
+
+namespace keymaster {
+
+RsaKeymaster0KeyFactory::RsaKeymaster0KeyFactory(const SoftKeymasterContext* context,
+                                                 const Keymaster0Engine* engine)
+    : RsaKeyFactory(context), engine_(engine) {}
+
+keymaster_error_t RsaKeymaster0KeyFactory::GenerateKey(const AuthorizationSet& key_description,
+                                                       KeymasterKeyBlob* key_blob,
+                                                       AuthorizationSet* hw_enforced,
+                                                       AuthorizationSet* sw_enforced) const {
+    if (!key_blob || !hw_enforced || !sw_enforced)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    uint64_t public_exponent;
+    if (!key_description.GetTagValue(TAG_RSA_PUBLIC_EXPONENT, &public_exponent)) {
+        LOG_E("%s", "No public exponent specified for RSA key generation");
+        return KM_ERROR_INVALID_ARGUMENT;
+    }
+
+    uint32_t key_size;
+    if (!key_description.GetTagValue(TAG_KEY_SIZE, &key_size)) {
+        LOG_E("%s", "No key size specified for RSA key generation");
+        return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+    }
+
+    KeymasterKeyBlob key_material;
+    if (!engine_->GenerateRsaKey(public_exponent, key_size, &key_material))
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    // These tags are hardware-enforced.  Putting them in the hw_enforced set here will ensure that
+    // context_->CreateKeyBlob doesn't put them in sw_enforced.
+    hw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
+    hw_enforced->push_back(TAG_RSA_PUBLIC_EXPONENT, public_exponent);
+    hw_enforced->push_back(TAG_KEY_SIZE, key_size);
+    hw_enforced->push_back(TAG_ORIGIN, KM_ORIGIN_UNKNOWN);
+
+    return context_->CreateKeyBlob(key_description, KM_ORIGIN_UNKNOWN, key_material, key_blob,
+                                   hw_enforced, sw_enforced);
+}
+
+keymaster_error_t RsaKeymaster0KeyFactory::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) const {
+    if (!output_key_blob || !hw_enforced || !sw_enforced)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    AuthorizationSet authorizations;
+    uint64_t public_exponent;
+    uint32_t key_size;
+    keymaster_error_t error =
+        UpdateImportKeyDescription(key_description, input_key_material_format, input_key_material,
+                                   &authorizations, &public_exponent, &key_size);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    KeymasterKeyBlob imported_hw_key;
+    if (!engine_->ImportKey(input_key_material_format, input_key_material, &imported_hw_key))
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    // These tags are hardware-enforced.  Putting them in the hw_enforced set here will ensure that
+    // context_->CreateKeyBlob doesn't put them in sw_enforced.
+    hw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
+    hw_enforced->push_back(TAG_RSA_PUBLIC_EXPONENT, public_exponent);
+    hw_enforced->push_back(TAG_KEY_SIZE, key_size);
+    hw_enforced->push_back(TAG_ORIGIN, KM_ORIGIN_UNKNOWN);
+
+    return context_->CreateKeyBlob(authorizations, KM_ORIGIN_UNKNOWN, imported_hw_key,
+                                   output_key_blob, hw_enforced, sw_enforced);
+}
+
+keymaster_error_t RsaKeymaster0KeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+                                                   const AuthorizationSet& additional_params,
+                                                   const AuthorizationSet& hw_enforced,
+                                                   const AuthorizationSet& sw_enforced,
+                                                   UniquePtr<Key>* key) const {
+    if (!key)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    if (sw_enforced.GetTagCount(TAG_ALGORITHM) == 1)
+        return super::LoadKey(key_material, additional_params, hw_enforced, sw_enforced, key);
+
+    unique_ptr<RSA, RSA_Delete> rsa(engine_->BlobToRsaKey(key_material));
+    if (!rsa)
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    keymaster_error_t error;
+    key->reset(new (std::nothrow)
+                   RsaKeymaster0Key(rsa.release(), hw_enforced, sw_enforced, &error));
+    if (!key->get())
+        error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    if (error != KM_ERROR_OK)
+        return error;
+
+    return KM_ERROR_OK;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/rsa_keymaster0_key.h b/keymaster/rsa_keymaster0_key.h
new file mode 100644
index 0000000..261448f
--- /dev/null
+++ b/keymaster/rsa_keymaster0_key.h
@@ -0,0 +1,70 @@
+/*
+ * 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_RSA_KEYMASTER0_KEY_H_
+#define SYSTEM_KEYMASTER_RSA_KEYMASTER0_KEY_H_
+
+#include <openssl/rsa.h>
+
+#include <keymaster/rsa_key_factory.h>
+
+#include "rsa_key.h"
+
+namespace keymaster {
+
+class Keymaster0Engine;
+class SoftKeymasterContext;
+
+/**
+ * An RsaKeyFactory which can delegate key generation, importing and loading operations to a
+ * keymaster0-backed OpenSSL engine.
+ */
+class RsaKeymaster0KeyFactory : public RsaKeyFactory {
+    typedef RsaKeyFactory super;
+
+  public:
+    RsaKeymaster0KeyFactory(const SoftKeymasterContext* context, const Keymaster0Engine* engine);
+
+    keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+                                  KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
+                                  AuthorizationSet* sw_enforced) const 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) const override;
+
+    keymaster_error_t LoadKey(const KeymasterKeyBlob& key_material,
+                              const AuthorizationSet& additional_params,
+                              const AuthorizationSet& hw_enforced,
+                              const AuthorizationSet& sw_enforced,
+                              UniquePtr<Key>* key) const override;
+
+  private:
+    const Keymaster0Engine* engine_;
+};
+
+class RsaKeymaster0Key : public RsaKey {
+  public:
+    RsaKeymaster0Key(RSA* rsa_key, const AuthorizationSet& hw_enforced,
+                     const AuthorizationSet& sw_enforced, keymaster_error_t* error)
+        : RsaKey(rsa_key, hw_enforced, sw_enforced, error) {}
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_RSA_KEYMASTER0_KEY_H_
diff --git a/keymaster/rsa_keymaster1_key.cpp b/keymaster/rsa_keymaster1_key.cpp
new file mode 100644
index 0000000..7d8a33f
--- /dev/null
+++ b/keymaster/rsa_keymaster1_key.cpp
@@ -0,0 +1,144 @@
+/*
+ * 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 "rsa_keymaster1_key.h"
+
+#include <memory>
+
+#include <keymaster/logger.h>
+#include <keymaster/soft_keymaster_context.h>
+
+#include "rsa_keymaster1_operation.h"
+
+using std::unique_ptr;
+
+namespace keymaster {
+
+RsaKeymaster1KeyFactory::RsaKeymaster1KeyFactory(const SoftKeymasterContext* context,
+                                                 const Keymaster1Engine* engine)
+    : RsaKeyFactory(context), engine_(engine),
+      sign_factory_(new RsaKeymaster1OperationFactory(KM_PURPOSE_SIGN, engine)),
+      decrypt_factory_(new RsaKeymaster1OperationFactory(KM_PURPOSE_DECRYPT, engine)),
+      // For pubkey ops we can use the normal operation factories.
+      verify_factory_(new RsaVerificationOperationFactory),
+      encrypt_factory_(new RsaEncryptionOperationFactory) {}
+
+static bool is_supported(uint32_t digest) {
+    return digest == KM_DIGEST_NONE || digest == KM_DIGEST_SHA_2_256;
+}
+
+static void UpdateToWorkAroundUnsupportedDigests(const AuthorizationSet& key_description,
+                                                 AuthorizationSet* new_description) {
+    bool have_unsupported_digests = false;
+    bool have_digest_none = false;
+    bool have_pad_none = false;
+    bool have_padding_requiring_digest = false;
+    for (const keymaster_key_param_t& entry : key_description) {
+        new_description->push_back(entry);
+
+        if (entry.tag == TAG_DIGEST) {
+            if (entry.enumerated == KM_DIGEST_NONE) {
+                have_digest_none = true;
+            } else if (!is_supported(entry.enumerated)) {
+                LOG_D("Found request for unsupported digest %u", entry.enumerated);
+                have_unsupported_digests = true;
+            }
+        }
+
+        if (entry.tag == TAG_PADDING) {
+            switch (entry.enumerated) {
+            case KM_PAD_RSA_PSS:
+            case KM_PAD_RSA_OAEP:
+                have_padding_requiring_digest = true;
+                break;
+            case KM_PAD_NONE:
+                have_pad_none = true;
+                break;
+            }
+        }
+    }
+
+    if (have_unsupported_digests && !have_digest_none) {
+        LOG_I("Adding KM_DIGEST_NONE to key authorization, to enable software digesting", 0);
+        new_description->push_back(TAG_DIGEST, KM_DIGEST_NONE);
+    }
+
+    if (have_unsupported_digests && have_padding_requiring_digest && !have_pad_none) {
+        LOG_I("Adding KM_PAD_NONE to key authorization, to enable PSS or OAEP software padding", 0);
+        new_description->push_back(TAG_PADDING, KM_PAD_NONE);
+    }
+}
+
+keymaster_error_t RsaKeymaster1KeyFactory::GenerateKey(const AuthorizationSet& key_description,
+                                                       KeymasterKeyBlob* key_blob,
+                                                       AuthorizationSet* hw_enforced,
+                                                       AuthorizationSet* sw_enforced) const {
+    AuthorizationSet key_params_copy;
+    UpdateToWorkAroundUnsupportedDigests(key_description, &key_params_copy);
+    return engine_->GenerateKey(key_params_copy, key_blob, hw_enforced, sw_enforced);
+}
+
+keymaster_error_t RsaKeymaster1KeyFactory::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) const {
+    AuthorizationSet key_params_copy;
+    UpdateToWorkAroundUnsupportedDigests(key_description, &key_params_copy);
+    return engine_->ImportKey(key_params_copy, input_key_material_format, input_key_material,
+                              output_key_blob, hw_enforced, sw_enforced);
+}
+
+keymaster_error_t RsaKeymaster1KeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+                                                   const AuthorizationSet& additional_params,
+                                                   const AuthorizationSet& hw_enforced,
+                                                   const AuthorizationSet& sw_enforced,
+                                                   UniquePtr<Key>* key) const {
+    if (!key)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    keymaster_error_t error;
+    unique_ptr<RSA, RSA_Delete> rsa(engine_->BuildRsaKey(key_material, additional_params, &error));
+    if (!rsa)
+        return error;
+
+    key->reset(new (std::nothrow)
+                   RsaKeymaster1Key(rsa.release(), hw_enforced, sw_enforced, &error));
+    if (!key->get())
+        error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    if (error != KM_ERROR_OK)
+        return error;
+
+    return KM_ERROR_OK;
+}
+
+OperationFactory* RsaKeymaster1KeyFactory::GetOperationFactory(keymaster_purpose_t purpose) const {
+    switch (purpose) {
+    case KM_PURPOSE_SIGN:
+        return sign_factory_.get();
+    case KM_PURPOSE_VERIFY:
+        return verify_factory_.get();
+    case KM_PURPOSE_ENCRYPT:
+        return encrypt_factory_.get();
+    case KM_PURPOSE_DECRYPT:
+        return decrypt_factory_.get();
+    case KM_PURPOSE_DERIVE_KEY:
+        break;
+    }
+    return nullptr;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/rsa_keymaster1_key.h b/keymaster/rsa_keymaster1_key.h
new file mode 100644
index 0000000..dd543dd
--- /dev/null
+++ b/keymaster/rsa_keymaster1_key.h
@@ -0,0 +1,81 @@
+/*
+ * 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_RSA_KEYMASTER1_KEY_H_
+#define SYSTEM_KEYMASTER_RSA_KEYMASTER1_KEY_H_
+
+#include <openssl/rsa.h>
+
+#include <keymaster/rsa_key_factory.h>
+
+#include "keymaster1_engine.h"
+#include "rsa_key.h"
+
+namespace keymaster {
+
+class SoftKeymasterContext;
+
+/**
+ * RsaKeymaster1KeyFactory is a KeyFactory that creates and loads keys which are actually backed by
+ * a hardware keymaster1 module, but which does not support all keymaster1 digests.  If unsupported
+ * digests are found during generation or import, KM_DIGEST_NONE is added to the key description,
+ * then the operations handle the unsupported digests in software.
+ *
+ * If unsupported digests are requested and KM_PAD_RSA_PSS or KM_PAD_RSA_OAEP is also requested, but
+ * KM_PAD_NONE is not present KM_PAD_NONE will be added to the description, to allow for
+ * software padding as well as software digesting.
+ */
+class RsaKeymaster1KeyFactory : public RsaKeyFactory {
+  public:
+    RsaKeymaster1KeyFactory(const SoftKeymasterContext* context, const Keymaster1Engine* engine);
+
+    keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+                                  KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
+                                  AuthorizationSet* sw_enforced) const 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) const override;
+
+    keymaster_error_t LoadKey(const KeymasterKeyBlob& key_material,
+                              const AuthorizationSet& additional_params,
+                              const AuthorizationSet& hw_enforced,
+                              const AuthorizationSet& sw_enforced,
+                              UniquePtr<Key>* key) const override;
+
+    OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const override;
+
+  private:
+    const Keymaster1Engine* engine_;
+
+    std::unique_ptr<OperationFactory> sign_factory_;
+    std::unique_ptr<OperationFactory> decrypt_factory_;
+    std::unique_ptr<OperationFactory> verify_factory_;
+    std::unique_ptr<OperationFactory> encrypt_factory_;
+};
+
+class RsaKeymaster1Key : public RsaKey {
+  public:
+    RsaKeymaster1Key(RSA* rsa_key, const AuthorizationSet& hw_enforced,
+                     const AuthorizationSet& sw_enforced, keymaster_error_t* error)
+        : RsaKey(rsa_key, hw_enforced, sw_enforced, error) {}
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_RSA_KEYMASTER1_KEY_H_
diff --git a/keymaster/rsa_keymaster1_operation.cpp b/keymaster/rsa_keymaster1_operation.cpp
new file mode 100644
index 0000000..002930e
--- /dev/null
+++ b/keymaster/rsa_keymaster1_operation.cpp
@@ -0,0 +1,180 @@
+/*
+ * 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 "rsa_keymaster1_operation.h"
+
+#include <memory>
+
+#include <keymaster/android_keymaster_utils.h>
+
+#include "openssl_err.h"
+#include "openssl_utils.h"
+#include "rsa_keymaster1_key.h"
+
+using std::unique_ptr;
+
+namespace keymaster {
+
+keymaster_error_t RsaKeymaster1WrappedOperation::Begin(EVP_PKEY* rsa_key,
+                                                       const AuthorizationSet& input_params) {
+    Keymaster1Engine::KeyData* key_data = engine_->GetData(rsa_key);
+    if (!key_data)
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    // Copy the input params and substitute KM_DIGEST_NONE for whatever was specified.  Also change
+    // KM_PAD_RSA_PSS and KM_PAD_OAEP to KM_PAD_NONE, if necessary. These are the params we'll pass
+    // to the hardware module.  The regular Rsa*Operation classes will do software digesting and
+    // padding where we've told the HW not to.
+    //
+    // The reason we don't change KM_PAD_RSA_PKCS1_1_5_SIGN or KM_PAD_RSA_PKCS1_1_5_ENCRYPT to
+    // KM_PAD_NONE is because the hardware can perform those padding modes, since they don't involve
+    // digesting.
+    //
+    // We also cache in the key the padding value that we expect to be passed to the engine crypto
+    // operation.  This just allows us to double-check that the correct padding value is reaching
+    // that layer.
+    AuthorizationSet begin_params(input_params);
+    int pos = begin_params.find(TAG_DIGEST);
+    if (pos == -1)
+        return KM_ERROR_UNSUPPORTED_DIGEST;
+    begin_params[pos].enumerated = KM_DIGEST_NONE;
+
+    pos = begin_params.find(TAG_PADDING);
+    if (pos == -1)
+        return KM_ERROR_UNSUPPORTED_PADDING_MODE;
+    switch (begin_params[pos].enumerated) {
+
+    case KM_PAD_RSA_PSS:
+    case KM_PAD_RSA_OAEP:
+        key_data->expected_openssl_padding = RSA_NO_PADDING;
+        begin_params[pos].enumerated = KM_PAD_NONE;
+        break;
+
+    case KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
+    case KM_PAD_RSA_PKCS1_1_5_SIGN:
+        key_data->expected_openssl_padding = RSA_PKCS1_PADDING;
+        break;
+    }
+
+    return engine_->device()->begin(engine_->device(), purpose_, &key_data->key_material,
+                                    &begin_params, nullptr /* out_params */, &operation_handle_);
+}
+
+keymaster_error_t
+RsaKeymaster1WrappedOperation::PrepareFinish(EVP_PKEY* rsa_key,
+                                             const AuthorizationSet& input_params) {
+    Keymaster1Engine::KeyData* key_data = engine_->GetData(rsa_key);
+    if (!key_data) {
+        LOG_E("Could not get extended key data... not a Keymaster1Engine key?", 0);
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+    key_data->op_handle = operation_handle_;
+    key_data->finish_params.Reinitialize(input_params);
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaKeymaster1WrappedOperation::Abort() {
+    return engine_->device()->abort(engine_->device(), operation_handle_);
+}
+
+keymaster_error_t RsaKeymaster1WrappedOperation::GetError(EVP_PKEY* rsa_key) {
+    Keymaster1Engine::KeyData* key_data = engine_->GetData(rsa_key);  // key_data is owned by rsa
+    if (!key_data)
+        return KM_ERROR_UNKNOWN_ERROR;
+    return key_data->error;
+}
+
+static EVP_PKEY* GetEvpKey(const RsaKeymaster1Key& key, keymaster_error_t* error) {
+    if (!key.key()) {
+        *error = KM_ERROR_UNKNOWN_ERROR;
+        return nullptr;
+    }
+
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
+    if (!key.InternalToEvp(pkey.get())) {
+        *error = KM_ERROR_UNKNOWN_ERROR;
+        return nullptr;
+    }
+    return pkey.release();
+}
+
+Operation* RsaKeymaster1OperationFactory::CreateOperation(const Key& key,
+                                                          const AuthorizationSet& begin_params,
+                                                          keymaster_error_t* error) {
+    keymaster_digest_t digest;
+    if (!GetAndValidateDigest(begin_params, key, &digest, error))
+        return nullptr;
+
+    keymaster_padding_t padding;
+    if (!GetAndValidatePadding(begin_params, key, &padding, error))
+        return nullptr;
+
+    const RsaKeymaster1Key& rsa_km1_key(static_cast<const RsaKeymaster1Key&>(key));
+    unique_ptr<EVP_PKEY, EVP_PKEY_Delete> rsa(GetEvpKey(rsa_km1_key, error));
+    if (!rsa)
+        return nullptr;
+
+    switch (purpose_) {
+    case KM_PURPOSE_SIGN:
+        return new RsaKeymaster1Operation<RsaSignOperation>(digest, padding, rsa.release(),
+                                                            engine_);
+    case KM_PURPOSE_DECRYPT:
+        return new RsaKeymaster1Operation<RsaDecryptOperation>(digest, padding, rsa.release(),
+                                                               engine_);
+    default:
+        LOG_E("Bug: Pubkey operation requested.  Those should be handled by normal RSA operations.",
+              0);
+        *error = KM_ERROR_UNSUPPORTED_PURPOSE;
+        return nullptr;
+    }
+}
+
+static const keymaster_digest_t supported_digests[] = {
+    KM_DIGEST_NONE,      KM_DIGEST_MD5,       KM_DIGEST_SHA1,     KM_DIGEST_SHA_2_224,
+    KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512};
+
+const keymaster_digest_t*
+RsaKeymaster1OperationFactory::SupportedDigests(size_t* digest_count) const {
+    *digest_count = array_length(supported_digests);
+    return supported_digests;
+}
+
+static const keymaster_padding_t supported_sig_padding[] = {
+    KM_PAD_NONE, KM_PAD_RSA_PKCS1_1_5_SIGN, KM_PAD_RSA_PSS,
+};
+static const keymaster_padding_t supported_crypt_padding[] = {
+    KM_PAD_NONE, KM_PAD_RSA_PKCS1_1_5_ENCRYPT, KM_PAD_RSA_OAEP,
+};
+
+const keymaster_padding_t*
+RsaKeymaster1OperationFactory::SupportedPaddingModes(size_t* padding_mode_count) const {
+    switch (purpose_) {
+    case KM_PURPOSE_SIGN:
+    case KM_PURPOSE_VERIFY:
+        *padding_mode_count = array_length(supported_sig_padding);
+        return supported_sig_padding;
+    case KM_PURPOSE_ENCRYPT:
+    case KM_PURPOSE_DECRYPT:
+        *padding_mode_count = array_length(supported_crypt_padding);
+        return supported_crypt_padding;
+    default:
+        *padding_mode_count = 0;
+        return nullptr;
+    }
+}
+
+}  // namespace keymaster
diff --git a/keymaster/rsa_keymaster1_operation.h b/keymaster/rsa_keymaster1_operation.h
new file mode 100644
index 0000000..30123f0
--- /dev/null
+++ b/keymaster/rsa_keymaster1_operation.h
@@ -0,0 +1,120 @@
+/*
+ * 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_RSA_KEYMASTER1_OPERATION_H_
+#define SYSTEM_KEYMASTER_RSA_KEYMASTER1_OPERATION_H_
+
+#include <openssl/evp.h>
+
+#include <hardware/keymaster1.h>
+#include <keymaster/android_keymaster_utils.h>
+
+#include "keymaster1_engine.h"
+#include "rsa_operation.h"
+
+namespace keymaster {
+
+class RsaKeymaster1WrappedOperation {
+  public:
+    RsaKeymaster1WrappedOperation(keymaster_purpose_t purpose, const Keymaster1Engine* engine)
+        : purpose_(purpose), operation_handle_(0), engine_(engine) {}
+    ~RsaKeymaster1WrappedOperation() {
+        if (operation_handle_)
+            Abort();
+    }
+
+    keymaster_error_t Begin(EVP_PKEY* rsa_key, const AuthorizationSet& input_params);
+    keymaster_error_t PrepareFinish(EVP_PKEY* rsa_key, const AuthorizationSet& input_params);
+    void Finish() { operation_handle_ = 0; }
+    keymaster_error_t Abort();
+
+    keymaster_error_t GetError(EVP_PKEY* rsa_key);
+
+  protected:
+    keymaster_purpose_t purpose_;
+    keymaster_operation_handle_t operation_handle_;
+    const Keymaster1Engine* engine_;
+};
+
+template <typename BaseOperation> class RsaKeymaster1Operation : public BaseOperation {
+    typedef BaseOperation super;
+
+  public:
+    RsaKeymaster1Operation(keymaster_digest_t digest, keymaster_padding_t padding, EVP_PKEY* key,
+                           const Keymaster1Engine* engine)
+        : BaseOperation(digest, padding, key), wrapped_operation_(super::purpose(), engine) {
+        // Shouldn't be instantiated for public key operations.
+        assert(super::purpose() != KM_PURPOSE_VERIFY);
+        assert(super::purpose() != KM_PURPOSE_ENCRYPT);
+    }
+
+    keymaster_error_t Begin(const AuthorizationSet& input_params,
+                            AuthorizationSet* output_params) override {
+        keymaster_error_t error = wrapped_operation_.Begin(super::rsa_key_, input_params);
+        if (error != KM_ERROR_OK)
+            return error;
+        return super::Begin(input_params, output_params);
+    }
+
+    keymaster_error_t Finish(const AuthorizationSet& input_params, const Buffer& input,
+                             const Buffer& signature, AuthorizationSet* output_params,
+                             Buffer* output) override {
+        keymaster_error_t error = wrapped_operation_.PrepareFinish(super::rsa_key_, input_params);
+        if (error != KM_ERROR_OK)
+            return error;
+        error = super::Finish(input_params, input, signature, output_params, output);
+        if (wrapped_operation_.GetError(super::rsa_key_) != KM_ERROR_OK)
+            error = wrapped_operation_.GetError(super::rsa_key_);
+        if (error == KM_ERROR_OK)
+            wrapped_operation_.Finish();
+        return error;
+    }
+
+    keymaster_error_t Abort() override {
+        keymaster_error_t error = wrapped_operation_.Abort();
+        if (error != KM_ERROR_OK)
+            return error;
+        return super::Abort();
+    }
+
+  private:
+    RsaKeymaster1WrappedOperation wrapped_operation_;
+};
+
+/**
+ * Factory that produces RsaKeymaster1Operations.  This is instantiated and
+ * provided by RsaKeymaster1KeyFactory.
+ */
+class RsaKeymaster1OperationFactory : public OperationFactory {
+  public:
+    RsaKeymaster1OperationFactory(keymaster_purpose_t purpose, const Keymaster1Engine* engine)
+        : purpose_(purpose), engine_(engine) {}
+    KeyType registry_key() const override { return KeyType(KM_ALGORITHM_RSA, purpose_); }
+
+    Operation* CreateOperation(const Key& key, const AuthorizationSet& begin_params,
+                               keymaster_error_t* error) override;
+
+    const keymaster_digest_t* SupportedDigests(size_t* digest_count) const override;
+    const keymaster_padding_t* SupportedPaddingModes(size_t* padding_mode_count) const override;
+
+  private:
+    keymaster_purpose_t purpose_;
+    const Keymaster1Engine* engine_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_RSA_KEYMASTER1_OPERATION_H_
diff --git a/keymaster/rsa_operation.cpp b/keymaster/rsa_operation.cpp
new file mode 100644
index 0000000..2046a64
--- /dev/null
+++ b/keymaster/rsa_operation.cpp
@@ -0,0 +1,619 @@
+/*
+ * 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 "rsa_operation.h"
+
+#include <limits.h>
+
+#include <new>
+
+#include <openssl/err.h>
+
+#include <keymaster/logger.h>
+
+#include "openssl_err.h"
+#include "openssl_utils.h"
+#include "rsa_key.h"
+
+namespace keymaster {
+
+const size_t kPssOverhead = 2;
+const size_t kMinPssSaltSize = 20;
+
+// Overhead for PKCS#1 v1.5 signature padding of undigested messages.  Digested messages have
+// additional overhead, for the digest algorithmIdentifier required by PKCS#1.
+const size_t kPkcs1UndigestedSignaturePaddingOverhead = 11;
+
+/* static */
+EVP_PKEY* RsaOperationFactory::GetRsaKey(const Key& key, keymaster_error_t* error) {
+    const RsaKey* rsa_key = static_cast<const RsaKey*>(&key);
+    assert(rsa_key);
+    if (!rsa_key || !rsa_key->key()) {
+        *error = KM_ERROR_UNKNOWN_ERROR;
+        return nullptr;
+    }
+
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
+    if (!rsa_key->InternalToEvp(pkey.get())) {
+        *error = KM_ERROR_UNKNOWN_ERROR;
+        return nullptr;
+    }
+    return pkey.release();
+}
+
+static const keymaster_digest_t supported_digests[] = {
+    KM_DIGEST_NONE,      KM_DIGEST_MD5,       KM_DIGEST_SHA1,     KM_DIGEST_SHA_2_224,
+    KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512};
+
+const keymaster_digest_t* RsaOperationFactory::SupportedDigests(size_t* digest_count) const {
+    *digest_count = array_length(supported_digests);
+    return supported_digests;
+}
+
+RsaOperation* RsaOperationFactory::CreateRsaOperation(const Key& key,
+                                                      const AuthorizationSet& begin_params,
+                                                      keymaster_error_t* error) {
+    keymaster_padding_t padding;
+    if (!GetAndValidatePadding(begin_params, key, &padding, error))
+        return nullptr;
+
+    bool require_digest = (purpose() == KM_PURPOSE_SIGN || purpose() == KM_PURPOSE_VERIFY ||
+                           padding == KM_PAD_RSA_OAEP);
+
+    keymaster_digest_t digest = KM_DIGEST_NONE;
+    if (require_digest && !GetAndValidateDigest(begin_params, key, &digest, error))
+        return nullptr;
+
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> rsa(GetRsaKey(key, error));
+    if (!rsa.get())
+        return nullptr;
+
+    RsaOperation* op = InstantiateOperation(digest, padding, rsa.release());
+    if (!op)
+        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    return op;
+}
+
+static const keymaster_padding_t supported_sig_padding[] = {KM_PAD_NONE, KM_PAD_RSA_PKCS1_1_5_SIGN,
+                                                            KM_PAD_RSA_PSS};
+const keymaster_padding_t*
+RsaDigestingOperationFactory::SupportedPaddingModes(size_t* padding_mode_count) const {
+    *padding_mode_count = array_length(supported_sig_padding);
+    return supported_sig_padding;
+}
+
+RsaOperation* RsaCryptingOperationFactory::CreateRsaOperation(const Key& key,
+                                                              const AuthorizationSet& begin_params,
+                                                              keymaster_error_t* error) {
+    UniquePtr<RsaOperation> op(RsaOperationFactory::CreateRsaOperation(key, begin_params, error));
+    if (op.get()) {
+        switch (op->padding()) {
+        case KM_PAD_NONE:
+        case KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
+            if (op->digest() != KM_DIGEST_NONE) {
+                *error = KM_ERROR_INCOMPATIBLE_DIGEST;
+                return nullptr;
+            }
+            break;
+
+        case KM_PAD_RSA_OAEP:
+            if (op->digest() == KM_DIGEST_NONE) {
+                *error = KM_ERROR_INCOMPATIBLE_DIGEST;
+                return nullptr;
+            }
+            break;
+
+        default:
+            *error = KM_ERROR_UNSUPPORTED_PADDING_MODE;
+            return nullptr;
+        }
+    }
+    return op.release();
+}
+
+static const keymaster_padding_t supported_crypt_padding[] = {KM_PAD_NONE, KM_PAD_RSA_OAEP,
+                                                              KM_PAD_RSA_PKCS1_1_5_ENCRYPT};
+const keymaster_padding_t*
+RsaCryptingOperationFactory::SupportedPaddingModes(size_t* padding_mode_count) const {
+    *padding_mode_count = array_length(supported_crypt_padding);
+    return supported_crypt_padding;
+}
+
+RsaOperation::~RsaOperation() {
+    if (rsa_key_ != NULL)
+        EVP_PKEY_free(rsa_key_);
+}
+
+keymaster_error_t RsaOperation::Begin(const AuthorizationSet& /* input_params */,
+                                      AuthorizationSet* /* output_params */) {
+    return InitDigest();
+}
+
+keymaster_error_t RsaOperation::Update(const AuthorizationSet& /* additional_params */,
+                                       const Buffer& input, AuthorizationSet* /* output_params */,
+                                       Buffer* /* output */, size_t* input_consumed) {
+    assert(input_consumed);
+    switch (purpose()) {
+    default:
+        return KM_ERROR_UNIMPLEMENTED;
+    case KM_PURPOSE_SIGN:
+    case KM_PURPOSE_VERIFY:
+    case KM_PURPOSE_ENCRYPT:
+    case KM_PURPOSE_DECRYPT:
+        return StoreData(input, input_consumed);
+    }
+}
+
+keymaster_error_t RsaOperation::StoreData(const Buffer& input, size_t* input_consumed) {
+    assert(input_consumed);
+
+    if (!data_.reserve(EVP_PKEY_size(rsa_key_)))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    // If the write fails, it's because input length exceeds key size.
+    if (!data_.write(input.peek_read(), input.available_read())) {
+        LOG_E("Input too long: cannot operate on %u bytes of data with %u-byte RSA key",
+              input.available_read() + data_.available_read(), EVP_PKEY_size(rsa_key_));
+        return KM_ERROR_INVALID_INPUT_LENGTH;
+    }
+
+    *input_consumed = input.available_read();
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaOperation::SetRsaPaddingInEvpContext(EVP_PKEY_CTX* pkey_ctx) {
+    keymaster_error_t error;
+    int openssl_padding = GetOpensslPadding(&error);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, openssl_padding) <= 0)
+        return TranslateLastOpenSslError();
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaOperation::InitDigest() {
+    if (digest_ == KM_DIGEST_NONE) {
+        if (require_digest())
+            return KM_ERROR_INCOMPATIBLE_DIGEST;
+        return KM_ERROR_OK;
+    }
+
+    switch (digest_) {
+    case KM_DIGEST_NONE:
+        return KM_ERROR_OK;
+    case KM_DIGEST_MD5:
+        digest_algorithm_ = EVP_md5();
+        return KM_ERROR_OK;
+    case KM_DIGEST_SHA1:
+        digest_algorithm_ = EVP_sha1();
+        return KM_ERROR_OK;
+    case KM_DIGEST_SHA_2_224:
+        digest_algorithm_ = EVP_sha224();
+        return KM_ERROR_OK;
+    case KM_DIGEST_SHA_2_256:
+        digest_algorithm_ = EVP_sha256();
+        return KM_ERROR_OK;
+    case KM_DIGEST_SHA_2_384:
+        digest_algorithm_ = EVP_sha384();
+        return KM_ERROR_OK;
+    case KM_DIGEST_SHA_2_512:
+        digest_algorithm_ = EVP_sha512();
+        return KM_ERROR_OK;
+    default:
+        return KM_ERROR_UNSUPPORTED_DIGEST;
+    }
+}
+
+RsaDigestingOperation::RsaDigestingOperation(keymaster_purpose_t purpose, keymaster_digest_t digest,
+                                             keymaster_padding_t padding, EVP_PKEY* key)
+    : RsaOperation(purpose, digest, padding, key) {
+    EVP_MD_CTX_init(&digest_ctx_);
+}
+RsaDigestingOperation::~RsaDigestingOperation() {
+    EVP_MD_CTX_cleanup(&digest_ctx_);
+}
+
+int RsaDigestingOperation::GetOpensslPadding(keymaster_error_t* error) {
+    *error = KM_ERROR_OK;
+    switch (padding_) {
+    case KM_PAD_NONE:
+        return RSA_NO_PADDING;
+    case KM_PAD_RSA_PKCS1_1_5_SIGN:
+        return RSA_PKCS1_PADDING;
+    case KM_PAD_RSA_PSS:
+        if (digest_ == KM_DIGEST_NONE) {
+            *error = KM_ERROR_INCOMPATIBLE_PADDING_MODE;
+            return -1;
+        }
+        if (EVP_MD_size(digest_algorithm_) + kPssOverhead + kMinPssSaltSize >
+            (size_t)EVP_PKEY_size(rsa_key_)) {
+            LOG_E("Input too long: %d-byte digest cannot be used with %d-byte RSA key in PSS "
+                  "padding mode",
+                  EVP_MD_size(digest_algorithm_), EVP_PKEY_size(rsa_key_));
+            *error = KM_ERROR_INCOMPATIBLE_DIGEST;
+            return -1;
+        }
+        return RSA_PKCS1_PSS_PADDING;
+    default:
+        return -1;
+    }
+}
+
+keymaster_error_t RsaSignOperation::Begin(const AuthorizationSet& input_params,
+                                          AuthorizationSet* output_params) {
+    keymaster_error_t error = RsaDigestingOperation::Begin(input_params, output_params);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    if (digest_ == KM_DIGEST_NONE)
+        return KM_ERROR_OK;
+
+    EVP_PKEY_CTX* pkey_ctx;
+    if (EVP_DigestSignInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, nullptr /* engine */,
+                           rsa_key_) != 1)
+        return TranslateLastOpenSslError();
+    return SetRsaPaddingInEvpContext(pkey_ctx);
+}
+
+keymaster_error_t RsaSignOperation::Update(const AuthorizationSet& additional_params,
+                                           const Buffer& input, AuthorizationSet* output_params,
+                                           Buffer* output, size_t* input_consumed) {
+    if (digest_ == KM_DIGEST_NONE)
+        // Just buffer the data.
+        return RsaOperation::Update(additional_params, input, output_params, output,
+                                    input_consumed);
+
+    if (EVP_DigestSignUpdate(&digest_ctx_, input.peek_read(), input.available_read()) != 1)
+        return TranslateLastOpenSslError();
+    *input_consumed = input.available_read();
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaSignOperation::Finish(const AuthorizationSet& additional_params,
+                                           const Buffer& input, const Buffer& /* signature */,
+                                           AuthorizationSet* /* output_params */, Buffer* output) {
+    assert(output);
+
+    keymaster_error_t error = UpdateForFinish(additional_params, input);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    if (digest_ == KM_DIGEST_NONE)
+        return SignUndigested(output);
+    else
+        return SignDigested(output);
+}
+
+static keymaster_error_t zero_pad_left(UniquePtr<uint8_t[]>* dest, size_t padded_len, Buffer& src) {
+    assert(padded_len > src.available_read());
+
+    dest->reset(new uint8_t[padded_len]);
+    if (!dest->get())
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    size_t padding_len = padded_len - src.available_read();
+    memset(dest->get(), 0, padding_len);
+    if (!src.read(dest->get() + padding_len, src.available_read()))
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaSignOperation::SignUndigested(Buffer* output) {
+    UniquePtr<RSA, RSA_Delete> rsa(EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>(rsa_key_)));
+    if (!rsa.get())
+        return TranslateLastOpenSslError();
+
+    if (!output->Reinitialize(RSA_size(rsa.get())))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    size_t key_len = EVP_PKEY_size(rsa_key_);
+    int bytes_encrypted;
+    switch (padding_) {
+    case KM_PAD_NONE: {
+        const uint8_t* to_encrypt = data_.peek_read();
+        UniquePtr<uint8_t[]> zero_padded;
+        if (data_.available_read() > key_len) {
+            return KM_ERROR_INVALID_INPUT_LENGTH;
+        } else if (data_.available_read() < key_len) {
+            keymaster_error_t error = zero_pad_left(&zero_padded, key_len, data_);
+            if (error != KM_ERROR_OK)
+                return error;
+            to_encrypt = zero_padded.get();
+        }
+        bytes_encrypted = RSA_private_encrypt(key_len, to_encrypt, output->peek_write(), rsa.get(),
+                                              RSA_NO_PADDING);
+        break;
+    }
+    case KM_PAD_RSA_PKCS1_1_5_SIGN:
+        // Does PKCS1 padding without digesting even make sense?  Dunno.  We'll support it.
+        if (data_.available_read() + kPkcs1UndigestedSignaturePaddingOverhead > key_len) {
+            LOG_E("Input too long: cannot sign %u-byte message with PKCS1 padding with %u-bit key",
+                  data_.available_read(), EVP_PKEY_size(rsa_key_) * 8);
+            return KM_ERROR_INVALID_INPUT_LENGTH;
+        }
+        bytes_encrypted = RSA_private_encrypt(data_.available_read(), data_.peek_read(),
+                                              output->peek_write(), rsa.get(), RSA_PKCS1_PADDING);
+        break;
+
+    default:
+        return KM_ERROR_UNSUPPORTED_PADDING_MODE;
+    }
+
+    if (bytes_encrypted <= 0)
+        return TranslateLastOpenSslError();
+    if (!output->advance_write(bytes_encrypted))
+        return KM_ERROR_UNKNOWN_ERROR;
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaSignOperation::SignDigested(Buffer* output) {
+    size_t siglen;
+    if (EVP_DigestSignFinal(&digest_ctx_, nullptr /* signature */, &siglen) != 1)
+        return TranslateLastOpenSslError();
+
+    if (!output->Reinitialize(siglen))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    if (EVP_DigestSignFinal(&digest_ctx_, output->peek_write(), &siglen) <= 0)
+        return TranslateLastOpenSslError();
+    if (!output->advance_write(siglen))
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaVerifyOperation::Begin(const AuthorizationSet& input_params,
+                                            AuthorizationSet* output_params) {
+    keymaster_error_t error = RsaDigestingOperation::Begin(input_params, output_params);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    if (digest_ == KM_DIGEST_NONE)
+        return KM_ERROR_OK;
+
+    EVP_PKEY_CTX* pkey_ctx;
+    if (EVP_DigestVerifyInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, NULL, rsa_key_) != 1)
+        return TranslateLastOpenSslError();
+    return SetRsaPaddingInEvpContext(pkey_ctx);
+}
+
+keymaster_error_t RsaVerifyOperation::Update(const AuthorizationSet& additional_params,
+                                             const Buffer& input, AuthorizationSet* output_params,
+                                             Buffer* output, size_t* input_consumed) {
+    if (digest_ == KM_DIGEST_NONE)
+        // Just buffer the data.
+        return RsaOperation::Update(additional_params, input, output_params, output,
+                                    input_consumed);
+
+    if (EVP_DigestVerifyUpdate(&digest_ctx_, input.peek_read(), input.available_read()) != 1)
+        return TranslateLastOpenSslError();
+    *input_consumed = input.available_read();
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaVerifyOperation::Finish(const AuthorizationSet& additional_params,
+                                             const Buffer& input, const Buffer& signature,
+                                             AuthorizationSet* /* output_params */,
+                                             Buffer* /* output */) {
+    keymaster_error_t error = UpdateForFinish(additional_params, input);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    if (digest_ == KM_DIGEST_NONE)
+        return VerifyUndigested(signature);
+    else
+        return VerifyDigested(signature);
+}
+
+keymaster_error_t RsaVerifyOperation::VerifyUndigested(const Buffer& signature) {
+    UniquePtr<RSA, RSA_Delete> rsa(EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>(rsa_key_)));
+    if (!rsa.get())
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    size_t key_len = RSA_size(rsa.get());
+    int openssl_padding;
+    switch (padding_) {
+    case KM_PAD_NONE:
+        if (data_.available_read() > key_len)
+            return KM_ERROR_INVALID_INPUT_LENGTH;
+        if (key_len != signature.available_read())
+            return KM_ERROR_VERIFICATION_FAILED;
+        openssl_padding = RSA_NO_PADDING;
+        break;
+    case KM_PAD_RSA_PKCS1_1_5_SIGN:
+        if (data_.available_read() + kPkcs1UndigestedSignaturePaddingOverhead > key_len) {
+            LOG_E("Input too long: cannot verify %u-byte message with PKCS1 padding && %u-bit key",
+                  data_.available_read(), key_len * 8);
+            return KM_ERROR_INVALID_INPUT_LENGTH;
+        }
+        openssl_padding = RSA_PKCS1_PADDING;
+        break;
+    default:
+        return KM_ERROR_UNSUPPORTED_PADDING_MODE;
+    }
+
+    UniquePtr<uint8_t[]> decrypted_data(new (std::nothrow) uint8_t[key_len]);
+    if (!decrypted_data.get())
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    int bytes_decrypted = RSA_public_decrypt(signature.available_read(), signature.peek_read(),
+                                             decrypted_data.get(), rsa.get(), openssl_padding);
+    if (bytes_decrypted < 0)
+        return KM_ERROR_VERIFICATION_FAILED;
+
+    const uint8_t* compare_pos = decrypted_data.get();
+    size_t bytes_to_compare = bytes_decrypted;
+    uint8_t zero_check_result = 0;
+    if (padding_ == KM_PAD_NONE && data_.available_read() < bytes_to_compare) {
+        // If the data is short, for "unpadded" signing we zero-pad to the left.  So during
+        // verification we should have zeros on the left of the decrypted data.  Do a constant-time
+        // check.
+        const uint8_t* zero_end = compare_pos + bytes_to_compare - data_.available_read();
+        while (compare_pos < zero_end)
+            zero_check_result |= *compare_pos++;
+        bytes_to_compare = data_.available_read();
+    }
+    if (memcmp_s(compare_pos, data_.peek_read(), bytes_to_compare) != 0 || zero_check_result != 0)
+        return KM_ERROR_VERIFICATION_FAILED;
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaVerifyOperation::VerifyDigested(const Buffer& signature) {
+    if (!EVP_DigestVerifyFinal(&digest_ctx_, signature.peek_read(), signature.available_read()))
+        return KM_ERROR_VERIFICATION_FAILED;
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaCryptOperation::SetOaepDigestIfRequired(EVP_PKEY_CTX* pkey_ctx) {
+    if (padding() != KM_PAD_RSA_OAEP)
+        return KM_ERROR_OK;
+
+    assert(digest_algorithm_ != nullptr);
+    if (!EVP_PKEY_CTX_set_rsa_oaep_md(pkey_ctx, digest_algorithm_))
+        return TranslateLastOpenSslError();
+
+    // MGF1 MD is always SHA1.
+    if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha1()))
+        return TranslateLastOpenSslError();
+
+    return KM_ERROR_OK;
+}
+
+int RsaCryptOperation::GetOpensslPadding(keymaster_error_t* error) {
+    *error = KM_ERROR_OK;
+    switch (padding_) {
+    case KM_PAD_NONE:
+        return RSA_NO_PADDING;
+    case KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
+        return RSA_PKCS1_PADDING;
+    case KM_PAD_RSA_OAEP:
+        return RSA_PKCS1_OAEP_PADDING;
+    default:
+        return -1;
+    }
+}
+
+struct EVP_PKEY_CTX_Delete {
+    void operator()(EVP_PKEY_CTX* p) { EVP_PKEY_CTX_free(p); }
+};
+
+keymaster_error_t RsaEncryptOperation::Finish(const AuthorizationSet& additional_params,
+                                              const Buffer& input, const Buffer& /* signature */,
+                                              AuthorizationSet* /* output_params */,
+                                              Buffer* output) {
+    if (!output)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    keymaster_error_t error = UpdateForFinish(additional_params, input);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(
+        EVP_PKEY_CTX_new(rsa_key_, nullptr /* engine */));
+    if (!ctx.get())
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    if (EVP_PKEY_encrypt_init(ctx.get()) <= 0)
+        return TranslateLastOpenSslError();
+
+    error = SetRsaPaddingInEvpContext(ctx.get());
+    if (error != KM_ERROR_OK)
+        return error;
+    error = SetOaepDigestIfRequired(ctx.get());
+    if (error != KM_ERROR_OK)
+        return error;
+
+    size_t outlen;
+    if (EVP_PKEY_encrypt(ctx.get(), nullptr /* out */, &outlen, data_.peek_read(),
+                         data_.available_read()) <= 0)
+        return TranslateLastOpenSslError();
+
+    if (!output->Reinitialize(outlen))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    const uint8_t* to_encrypt = data_.peek_read();
+    size_t to_encrypt_len = data_.available_read();
+    UniquePtr<uint8_t[]> zero_padded;
+    if (padding_ == KM_PAD_NONE && to_encrypt_len < outlen) {
+        keymaster_error_t error = zero_pad_left(&zero_padded, outlen, data_);
+        if (error != KM_ERROR_OK)
+            return error;
+        to_encrypt = zero_padded.get();
+        to_encrypt_len = outlen;
+    }
+
+    if (EVP_PKEY_encrypt(ctx.get(), output->peek_write(), &outlen, to_encrypt, to_encrypt_len) <= 0)
+        return TranslateLastOpenSslError();
+    if (!output->advance_write(outlen))
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaDecryptOperation::Finish(const AuthorizationSet& additional_params,
+                                              const Buffer& input, const Buffer& /* signature */,
+                                              AuthorizationSet* /* output_params */,
+                                              Buffer* output) {
+    if (!output)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    keymaster_error_t error = UpdateForFinish(additional_params, input);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(
+        EVP_PKEY_CTX_new(rsa_key_, nullptr /* engine */));
+    if (!ctx.get())
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    if (EVP_PKEY_decrypt_init(ctx.get()) <= 0)
+        return TranslateLastOpenSslError();
+
+    error = SetRsaPaddingInEvpContext(ctx.get());
+    if (error != KM_ERROR_OK)
+        return error;
+    error = SetOaepDigestIfRequired(ctx.get());
+    if (error != KM_ERROR_OK)
+        return error;
+
+    size_t outlen;
+    if (EVP_PKEY_decrypt(ctx.get(), nullptr /* out */, &outlen, data_.peek_read(),
+                         data_.available_read()) <= 0)
+        return TranslateLastOpenSslError();
+
+    if (!output->Reinitialize(outlen))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    const uint8_t* to_decrypt = data_.peek_read();
+    size_t to_decrypt_len = data_.available_read();
+    UniquePtr<uint8_t[]> zero_padded;
+    if (padding_ == KM_PAD_NONE && to_decrypt_len < outlen) {
+        keymaster_error_t error = zero_pad_left(&zero_padded, outlen, data_);
+        if (error != KM_ERROR_OK)
+            return error;
+        to_decrypt = zero_padded.get();
+        to_decrypt_len = outlen;
+    }
+
+    if (EVP_PKEY_decrypt(ctx.get(), output->peek_write(), &outlen, to_decrypt, to_decrypt_len) <= 0)
+        return TranslateLastOpenSslError();
+    if (!output->advance_write(outlen))
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    return KM_ERROR_OK;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/rsa_operation.h b/keymaster/rsa_operation.h
new file mode 100644
index 0000000..8283f2e
--- /dev/null
+++ b/keymaster/rsa_operation.h
@@ -0,0 +1,261 @@
+/*
+ * 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_RSA_OPERATION_H_
+#define SYSTEM_KEYMASTER_RSA_OPERATION_H_
+
+#include <UniquePtr.h>
+
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+
+#include "operation.h"
+
+namespace keymaster {
+
+/**
+ * Base class for all RSA operations.
+ *
+ * This class provides RSA key management, plus buffering of data for non-digesting modes.
+ */
+class RsaOperation : public Operation {
+  public:
+    RsaOperation(keymaster_purpose_t purpose, keymaster_digest_t digest,
+                 keymaster_padding_t padding, EVP_PKEY* key)
+        : Operation(purpose), rsa_key_(key), padding_(padding), digest_(digest),
+          digest_algorithm_(nullptr) {}
+    ~RsaOperation();
+
+    keymaster_error_t Begin(const AuthorizationSet& input_params,
+                            AuthorizationSet* output_params) override;
+    keymaster_error_t Update(const AuthorizationSet& additional_params, const Buffer& input,
+                             AuthorizationSet* output_params, Buffer* output,
+                             size_t* input_consumed) override;
+    keymaster_error_t Abort() override { return KM_ERROR_OK; }
+
+    keymaster_padding_t padding() const { return padding_; }
+    keymaster_digest_t digest() const { return digest_; }
+
+  protected:
+    virtual int GetOpensslPadding(keymaster_error_t* error) = 0;
+    virtual bool require_digest() const = 0;
+
+    keymaster_error_t StoreData(const Buffer& input, size_t* input_consumed);
+    keymaster_error_t SetRsaPaddingInEvpContext(EVP_PKEY_CTX* pkey_ctx);
+    keymaster_error_t InitDigest();
+
+    EVP_PKEY* rsa_key_;
+    const keymaster_padding_t padding_;
+    Buffer data_;
+    const keymaster_digest_t digest_;
+    const EVP_MD* digest_algorithm_;
+};
+
+/**
+ * Base class for all digesting RSA operations.
+ *
+ * This class adds digesting support, for digesting modes.  For non-digesting modes, it falls back
+ * on the RsaOperation input buffering.
+ */
+class RsaDigestingOperation : public RsaOperation {
+  public:
+    RsaDigestingOperation(keymaster_purpose_t purpose, keymaster_digest_t digest,
+                          keymaster_padding_t padding, EVP_PKEY* key);
+    ~RsaDigestingOperation();
+
+  protected:
+    int GetOpensslPadding(keymaster_error_t* error) override;
+    bool require_digest() const override { return padding_ == KM_PAD_RSA_PSS; }
+    EVP_MD_CTX digest_ctx_;
+};
+
+/**
+ * RSA private key signing operation.
+ */
+class RsaSignOperation : public RsaDigestingOperation {
+  public:
+    RsaSignOperation(keymaster_digest_t digest, keymaster_padding_t padding, EVP_PKEY* key)
+        : RsaDigestingOperation(KM_PURPOSE_SIGN, digest, padding, key) {}
+
+    keymaster_error_t Begin(const AuthorizationSet& input_params,
+                            AuthorizationSet* output_params) override;
+    keymaster_error_t Update(const AuthorizationSet& additional_params, const Buffer& input,
+                             AuthorizationSet* output_params, Buffer* output,
+                             size_t* input_consumed) override;
+    keymaster_error_t Finish(const AuthorizationSet& additional_params, const Buffer& input,
+                             const Buffer& signature, AuthorizationSet* output_params,
+                             Buffer* output) override;
+
+  private:
+    keymaster_error_t SignUndigested(Buffer* output);
+    keymaster_error_t SignDigested(Buffer* output);
+};
+
+/**
+ * RSA public key verification operation.
+ */
+class RsaVerifyOperation : public RsaDigestingOperation {
+  public:
+    RsaVerifyOperation(keymaster_digest_t digest, keymaster_padding_t padding, EVP_PKEY* key)
+        : RsaDigestingOperation(KM_PURPOSE_VERIFY, digest, padding, key) {}
+
+    keymaster_error_t Begin(const AuthorizationSet& input_params,
+                            AuthorizationSet* output_params) override;
+    keymaster_error_t Update(const AuthorizationSet& additional_params, const Buffer& input,
+                             AuthorizationSet* output_params, Buffer* output,
+                             size_t* input_consumed) override;
+    keymaster_error_t Finish(const AuthorizationSet& additional_params, const Buffer& input,
+                             const Buffer& signature, AuthorizationSet* output_params,
+                             Buffer* output) override;
+
+  private:
+    keymaster_error_t VerifyUndigested(const Buffer& signature);
+    keymaster_error_t VerifyDigested(const Buffer& signature);
+};
+
+/**
+ * Base class for RSA crypting operations.
+ */
+class RsaCryptOperation : public RsaOperation {
+  public:
+    RsaCryptOperation(keymaster_purpose_t purpose, keymaster_digest_t digest,
+                      keymaster_padding_t padding, EVP_PKEY* key)
+        : RsaOperation(purpose, digest, padding, key) {}
+
+  protected:
+    keymaster_error_t SetOaepDigestIfRequired(EVP_PKEY_CTX* pkey_ctx);
+
+  private:
+    int GetOpensslPadding(keymaster_error_t* error) override;
+    bool require_digest() const override { return padding_ == KM_PAD_RSA_OAEP; }
+};
+
+/**
+ * RSA public key encryption operation.
+ */
+class RsaEncryptOperation : public RsaCryptOperation {
+  public:
+    RsaEncryptOperation(keymaster_digest_t digest, keymaster_padding_t padding, EVP_PKEY* key)
+        : RsaCryptOperation(KM_PURPOSE_ENCRYPT, digest, padding, key) {}
+    keymaster_error_t Finish(const AuthorizationSet& additional_params, const Buffer& input,
+                             const Buffer& signature, AuthorizationSet* output_params,
+                             Buffer* output) override;
+};
+
+/**
+ * RSA private key decryption operation.
+ */
+class RsaDecryptOperation : public RsaCryptOperation {
+  public:
+    RsaDecryptOperation(keymaster_digest_t digest, keymaster_padding_t padding, EVP_PKEY* key)
+        : RsaCryptOperation(KM_PURPOSE_DECRYPT, digest, padding, key) {}
+    keymaster_error_t Finish(const AuthorizationSet& additional_params, const Buffer& input,
+                             const Buffer& signature, AuthorizationSet* output_params,
+                             Buffer* output) override;
+};
+
+/**
+ * Abstract base for all RSA operation factories.  This class exists mainly to centralize some code
+ * common to all RSA operation factories.
+ */
+class RsaOperationFactory : public OperationFactory {
+  public:
+    KeyType registry_key() const override { return KeyType(KM_ALGORITHM_RSA, purpose()); }
+    virtual keymaster_purpose_t purpose() const = 0;
+
+    Operation* CreateOperation(const Key& key, const AuthorizationSet& begin_params,
+                               keymaster_error_t* error) override {
+        return CreateRsaOperation(key, begin_params, error);
+    }
+    const keymaster_digest_t* SupportedDigests(size_t* digest_count) const override;
+
+  protected:
+    static EVP_PKEY* GetRsaKey(const Key& key, keymaster_error_t* error);
+    virtual RsaOperation* CreateRsaOperation(const Key& key, const AuthorizationSet& begin_params,
+                                             keymaster_error_t* error);
+
+  private:
+    virtual RsaOperation* InstantiateOperation(keymaster_digest_t digest,
+                                               keymaster_padding_t padding, EVP_PKEY* key) = 0;
+};
+
+/**
+ * Abstract base for RSA operations that digest their input (signing and verification).
+ */
+class RsaDigestingOperationFactory : public RsaOperationFactory {
+  public:
+    const keymaster_padding_t* SupportedPaddingModes(size_t* padding_mode_count) const override;
+};
+
+/**
+ * Abstract base for en/de-crypting RSA operation factories.  This class does most of the work of
+ * creating such operations, delegating only the actual operation instantiation.
+ */
+class RsaCryptingOperationFactory : public RsaOperationFactory {
+  public:
+    RsaOperation* CreateRsaOperation(const Key& key, const AuthorizationSet& begin_params,
+                                     keymaster_error_t* error) override;
+    const keymaster_padding_t* SupportedPaddingModes(size_t* padding_mode_count) const override;
+};
+
+/**
+ * Concrete factory for RSA signing operations.
+ */
+class RsaSigningOperationFactory : public RsaDigestingOperationFactory {
+  public:
+    keymaster_purpose_t purpose() const override { return KM_PURPOSE_SIGN; }
+    RsaOperation* InstantiateOperation(keymaster_digest_t digest, keymaster_padding_t padding,
+                                       EVP_PKEY* key) override {
+        return new (std::nothrow) RsaSignOperation(digest, padding, key);
+    }
+};
+
+/**
+ * Concrete factory for RSA signing operations.
+ */
+class RsaVerificationOperationFactory : public RsaDigestingOperationFactory {
+    keymaster_purpose_t purpose() const override { return KM_PURPOSE_VERIFY; }
+    RsaOperation* InstantiateOperation(keymaster_digest_t digest, keymaster_padding_t padding,
+                                       EVP_PKEY* key) override {
+        return new (std::nothrow) RsaVerifyOperation(digest, padding, key);
+    }
+};
+
+/**
+ * Concrete factory for RSA signing operations.
+ */
+class RsaEncryptionOperationFactory : public RsaCryptingOperationFactory {
+    keymaster_purpose_t purpose() const override { return KM_PURPOSE_ENCRYPT; }
+    RsaOperation* InstantiateOperation(keymaster_digest_t digest, keymaster_padding_t padding,
+                                       EVP_PKEY* key) override {
+        return new (std::nothrow) RsaEncryptOperation(digest, padding, key);
+    }
+};
+
+/**
+ * Concrete factory for RSA signing operations.
+ */
+class RsaDecryptionOperationFactory : public RsaCryptingOperationFactory {
+    keymaster_purpose_t purpose() const override { return KM_PURPOSE_DECRYPT; }
+    RsaOperation* InstantiateOperation(keymaster_digest_t digest, keymaster_padding_t padding,
+                                       EVP_PKEY* key) override {
+        return new (std::nothrow) RsaDecryptOperation(digest, padding, key);
+    }
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_RSA_OPERATION_H_
diff --git a/keymaster/rsa_privkey_pk8.der b/keymaster/rsa_privkey_pk8.der
new file mode 100644
index 0000000..0336f80
--- /dev/null
+++ b/keymaster/rsa_privkey_pk8.der
Binary files differ
diff --git a/keymaster/serializable.cpp b/keymaster/serializable.cpp
new file mode 100644
index 0000000..5db64f8
--- /dev/null
+++ b/keymaster/serializable.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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 <keymaster/serializable.h>
+
+#include <assert.h>
+
+#include <new>
+
+#include <keymaster/android_keymaster_utils.h>
+
+namespace keymaster {
+
+uint8_t* append_to_buf(uint8_t* buf, const uint8_t* end, const void* data, size_t data_len) {
+    if (buf + data_len < buf)  // Pointer wrap check
+        return buf;
+
+    if (buf + data_len <= end) {
+        memcpy(buf, data, data_len);
+        return buf + data_len;
+    }
+    return buf;
+}
+
+bool copy_from_buf(const uint8_t** buf_ptr, const uint8_t* end, void* dest, size_t size) {
+    if (*buf_ptr + size < *buf_ptr)  // Pointer wrap check
+        return false;
+
+    if (end < *buf_ptr + size)
+        return false;
+    memcpy(dest, *buf_ptr, size);
+    *buf_ptr += size;
+    return true;
+}
+
+bool copy_size_and_data_from_buf(const uint8_t** buf_ptr, const uint8_t* end, size_t* size,
+                                 UniquePtr<uint8_t[]>* dest) {
+    if (!copy_uint32_from_buf(buf_ptr, end, size))
+        return false;
+
+    if (*buf_ptr + *size < *buf_ptr)  // Pointer wrap check
+        return false;
+
+    if (*buf_ptr + *size > end)
+        return false;
+
+    if (*size == 0) {
+        dest->reset();
+        return true;
+    }
+    dest->reset(new (std::nothrow) uint8_t[*size]);
+    if (!dest->get())
+        return false;
+    return copy_from_buf(buf_ptr, end, dest->get(), *size);
+}
+
+bool Buffer::reserve(size_t size) {
+    if (available_write() < size) {
+        size_t new_size = buffer_size_ + size - available_write();
+        uint8_t* new_buffer = new (std::nothrow) uint8_t[new_size];
+        if (!new_buffer)
+            return false;
+        memcpy(new_buffer, buffer_.get() + read_position_, available_read());
+        memset_s(buffer_.get(), 0, buffer_size_);
+        buffer_.reset(new_buffer);
+        buffer_size_ = new_size;
+        write_position_ -= read_position_;
+        read_position_ = 0;
+    }
+    return true;
+}
+
+bool Buffer::Reinitialize(size_t size) {
+    Clear();
+    buffer_.reset(new (std::nothrow) uint8_t[size]);
+    if (!buffer_.get())
+        return false;
+    buffer_size_ = size;
+    read_position_ = 0;
+    write_position_ = 0;
+    return true;
+}
+
+bool Buffer::Reinitialize(const void* data, size_t data_len) {
+    Clear();
+    if (static_cast<const uint8_t*>(data) + data_len < data)  // Pointer wrap check
+        return false;
+    buffer_.reset(new (std::nothrow) uint8_t[data_len]);
+    if (!buffer_.get())
+        return false;
+    buffer_size_ = data_len;
+    memcpy(buffer_.get(), data, data_len);
+    read_position_ = 0;
+    write_position_ = buffer_size_;
+    return true;
+}
+
+size_t Buffer::available_write() const {
+    assert(buffer_size_ >= write_position_);
+    return buffer_size_ - write_position_;
+}
+
+size_t Buffer::available_read() const {
+    assert(buffer_size_ >= write_position_);
+    assert(write_position_ >= read_position_);
+    return write_position_ - read_position_;
+}
+
+bool Buffer::write(const uint8_t* src, size_t write_length) {
+    if (available_write() < write_length)
+        return false;
+    memcpy(buffer_.get() + write_position_, src, write_length);
+    write_position_ += write_length;
+    return true;
+}
+
+bool Buffer::read(uint8_t* dest, size_t read_length) {
+    if (available_read() < read_length)
+        return false;
+    memcpy(dest, buffer_.get() + read_position_, read_length);
+    read_position_ += read_length;
+    return true;
+}
+
+size_t Buffer::SerializedSize() const {
+    return sizeof(uint32_t) + available_read();
+}
+
+uint8_t* Buffer::Serialize(uint8_t* buf, const uint8_t* end) const {
+    return append_size_and_data_to_buf(buf, end, peek_read(), available_read());
+}
+
+bool Buffer::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    Clear();
+    if (!copy_size_and_data_from_buf(buf_ptr, end, &buffer_size_, &buffer_)) {
+        buffer_.reset();
+        buffer_size_ = 0;
+        return false;
+    }
+    write_position_ = buffer_size_;
+    return true;
+}
+
+void Buffer::Clear() {
+    memset_s(buffer_.get(), 0, buffer_size_);
+    buffer_.reset();
+    read_position_ = 0;
+    write_position_ = 0;
+    buffer_size_ = 0;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/soft_keymaster_context.cpp b/keymaster/soft_keymaster_context.cpp
new file mode 100644
index 0000000..a143245
--- /dev/null
+++ b/keymaster/soft_keymaster_context.cpp
@@ -0,0 +1,883 @@
+/*
+ * 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 <memory>
+#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_keymaster0_key.h"
+#include "ec_keymaster1_key.h"
+#include "hmac_key.h"
+#include "integrity_assured_key_blob.h"
+#include "keymaster0_engine.h"
+#include "ocb_utils.h"
+#include "openssl_err.h"
+#include "rsa_keymaster0_key.h"
+#include "rsa_keymaster1_key.h"
+
+using std::unique_ptr;
+
+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 KeymasterKeyBlob MASTER_KEY(master_key_bytes, array_length(master_key_bytes));
+
+static uint8_t kRsaAttestKey[] = {
+    0x30, 0x82, 0x02, 0x5d, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xc0, 0x83, 0x23, 0xdc, 0x56,
+    0x88, 0x1b, 0xb8, 0x30, 0x20, 0x69, 0xf5, 0xb0, 0x85, 0x61, 0xc6, 0xee, 0xbe, 0x7f, 0x05, 0xe2,
+    0xf5, 0xa8, 0x42, 0x04, 0x8a, 0xbe, 0x8b, 0x47, 0xbe, 0x76, 0xfe, 0xae, 0xf2, 0x5c, 0xf2, 0x9b,
+    0x2a, 0xfa, 0x32, 0x00, 0x14, 0x16, 0x01, 0x42, 0x99, 0x89, 0xa1, 0x5f, 0xcf, 0xc6, 0x81, 0x5e,
+    0xb3, 0x63, 0x58, 0x3c, 0x2f, 0xd2, 0xf2, 0x0b, 0xe4, 0x98, 0x32, 0x83, 0xdd, 0x81, 0x4b, 0x16,
+    0xd7, 0xe1, 0x85, 0x41, 0x7a, 0xe5, 0x4a, 0xbc, 0x29, 0x6a, 0x3a, 0x6d, 0xb5, 0xc0, 0x04, 0x08,
+    0x3b, 0x68, 0xc5, 0x56, 0xc1, 0xf0, 0x23, 0x39, 0x91, 0x64, 0x19, 0x86, 0x4d, 0x50, 0xb7, 0x4d,
+    0x40, 0xae, 0xca, 0x48, 0x4c, 0x77, 0x35, 0x6c, 0x89, 0x5a, 0x0c, 0x27, 0x5a, 0xbf, 0xac, 0x49,
+    0x9d, 0x5d, 0x7d, 0x23, 0x62, 0xf2, 0x9c, 0x5e, 0x02, 0xe8, 0x71, 0x02, 0x03, 0x01, 0x00, 0x01,
+    0x02, 0x81, 0x81, 0x00, 0xbe, 0x86, 0x0b, 0x0b, 0x99, 0xa8, 0x02, 0xa6, 0xfb, 0x1a, 0x59, 0x43,
+    0x8a, 0x7b, 0xb7, 0x15, 0x06, 0x5b, 0x09, 0xa3, 0x6d, 0xc6, 0xe9, 0xca, 0xcc, 0x6b, 0xf3, 0xc0,
+    0x2c, 0x34, 0xd7, 0xd7, 0x9e, 0x94, 0xc6, 0x60, 0x64, 0x28, 0xd8, 0x8c, 0x7b, 0x7f, 0x65, 0x77,
+    0xc1, 0xcd, 0xea, 0x64, 0x07, 0x4a, 0xbe, 0x8e, 0x72, 0x86, 0xdf, 0x1f, 0x08, 0x11, 0xdc, 0x97,
+    0x28, 0x26, 0x08, 0x68, 0xde, 0x95, 0xd3, 0x2e, 0xfc, 0x96, 0xb6, 0xd0, 0x84, 0xff, 0x27, 0x1a,
+    0x5f, 0x60, 0xde, 0xfc, 0xc7, 0x03, 0xe7, 0xa3, 0x8e, 0x6e, 0x29, 0xba, 0x9a, 0x3c, 0x5f, 0xc2,
+    0xc2, 0x80, 0x76, 0xb6, 0xa8, 0x96, 0xaf, 0x1d, 0x34, 0xd7, 0x88, 0x28, 0xce, 0x9b, 0xdd, 0xb1,
+    0xf3, 0x4f, 0x9c, 0x94, 0x04, 0x43, 0x07, 0x81, 0x29, 0x8e, 0x20, 0x13, 0x16, 0x72, 0x5b, 0xbd,
+    0xbc, 0x99, 0x3a, 0x41, 0x02, 0x41, 0x00, 0xe1, 0xc6, 0xd9, 0x27, 0x64, 0x6c, 0x09, 0x16, 0xec,
+    0x36, 0x82, 0x6d, 0x59, 0x49, 0x83, 0x74, 0x0c, 0x21, 0xf1, 0xb0, 0x74, 0xc4, 0xa1, 0xa5, 0x98,
+    0x67, 0xc6, 0x69, 0x79, 0x5c, 0x85, 0xd3, 0xdc, 0x46, 0x4c, 0x5b, 0x92, 0x9e, 0x94, 0xbf, 0xb3,
+    0x4e, 0x0d, 0xcc, 0x50, 0x14, 0xb1, 0x0f, 0x13, 0x34, 0x1a, 0xb7, 0xfd, 0xd5, 0xf6, 0x04, 0x14,
+    0xd2, 0xa3, 0x26, 0xca, 0xd4, 0x1c, 0xc5, 0x02, 0x41, 0x00, 0xda, 0x48, 0x59, 0x97, 0x78, 0x5c,
+    0xd5, 0x63, 0x0f, 0xb0, 0xfd, 0x8c, 0x52, 0x54, 0xf9, 0x8e, 0x53, 0x8e, 0x18, 0x98, 0x3a, 0xae,
+    0x9e, 0x6b, 0x7e, 0x6a, 0x5a, 0x7b, 0x5d, 0x34, 0x37, 0x55, 0xb9, 0x21, 0x8e, 0xbd, 0x40, 0x32,
+    0x0d, 0x28, 0x38, 0x7d, 0x78, 0x9f, 0x76, 0xfa, 0x21, 0x8b, 0xcc, 0x2d, 0x8b, 0x68, 0xa5, 0xf6,
+    0x41, 0x8f, 0xbb, 0xec, 0xa5, 0x17, 0x9a, 0xb3, 0xaf, 0xbd, 0x02, 0x40, 0x50, 0xfe, 0xfc, 0x32,
+    0x64, 0x95, 0x59, 0x61, 0x6e, 0xd6, 0x53, 0x4e, 0x15, 0x45, 0x09, 0x32, 0x9d, 0x93, 0xa3, 0xd8,
+    0x10, 0xdb, 0xe5, 0xbd, 0xb9, 0x82, 0x29, 0x2c, 0xf7, 0x8b, 0xd8, 0xba, 0xdb, 0x80, 0x20, 0xae,
+    0x8d, 0x57, 0xf4, 0xb7, 0x1d, 0x05, 0x38, 0x6f, 0xfe, 0x9e, 0x9d, 0xb2, 0x71, 0xca, 0x34, 0x77,
+    0xa3, 0x49, 0x99, 0xdb, 0x76, 0xf8, 0xe5, 0xec, 0xe9, 0xc0, 0xd4, 0x9d, 0x02, 0x40, 0x15, 0xb7,
+    0x4c, 0xf2, 0x7c, 0xce, 0xff, 0x8b, 0xb3, 0x6b, 0xf0, 0x4d, 0x9d, 0x83, 0x46, 0xb0, 0x9a, 0x2f,
+    0x70, 0xd2, 0xf4, 0x43, 0x9b, 0x0f, 0x26, 0xac, 0x7e, 0x03, 0xf7, 0xe9, 0xd1, 0xf7, 0x7d, 0x4b,
+    0x91, 0x5f, 0xd2, 0x9b, 0x28, 0x23, 0xf0, 0x3a, 0xcb, 0x5d, 0x52, 0x00, 0xe0, 0x85, 0x7f, 0xf2,
+    0xa8, 0x03, 0xe9, 0x3e, 0xee, 0x96, 0xd6, 0x23, 0x5c, 0xe9, 0x54, 0x42, 0xbc, 0x21, 0x02, 0x41,
+    0x00, 0x90, 0xa7, 0x45, 0xda, 0x89, 0x70, 0xb2, 0xcd, 0x64, 0x96, 0x60, 0x32, 0x42, 0x28, 0xc5,
+    0xf8, 0x28, 0x56, 0xff, 0xd6, 0x65, 0xba, 0x9a, 0x85, 0xc8, 0xd6, 0x0f, 0x1b, 0x8b, 0xee, 0x71,
+    0x7e, 0xcd, 0x2c, 0x72, 0xea, 0xe0, 0x1d, 0xad, 0x86, 0xba, 0x76, 0x54, 0xd4, 0xcf, 0x45, 0xad,
+    0xb5, 0xf1, 0xf2, 0xb3, 0x1d, 0x9f, 0x81, 0x22, 0xcf, 0xa5, 0xf1, 0xa5, 0x57, 0x0f, 0x9b, 0x2d,
+    0x25,
+};
+
+static uint8_t kRsaAttestCert[] = {
+    0x30, 0x82, 0x02, 0xb6, 0x30, 0x82, 0x02, 0x1f, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x10,
+    0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
+    0x30, 0x63, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+    0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f,
+    0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d,
+    0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x15, 0x30, 0x13,
+    0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2c, 0x20, 0x49,
+    0x6e, 0x63, 0x2e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x07, 0x41, 0x6e,
+    0x64, 0x72, 0x6f, 0x69, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x31, 0x30, 0x34, 0x31,
+    0x32, 0x34, 0x30, 0x35, 0x33, 0x5a, 0x17, 0x0d, 0x33, 0x35, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32,
+    0x34, 0x30, 0x35, 0x33, 0x5a, 0x30, 0x76, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+    0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43,
+    0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55,
+    0x04, 0x0a, 0x0c, 0x0c, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+    0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x07, 0x41, 0x6e, 0x64, 0x72, 0x6f,
+    0x69, 0x64, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x20, 0x41, 0x6e, 0x64,
+    0x72, 0x6f, 0x69, 0x64, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x41, 0x74,
+    0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4b, 0x65, 0x79, 0x30, 0x81, 0x9f,
+    0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
+    0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xc0, 0x83, 0x23, 0xdc, 0x56, 0x88,
+    0x1b, 0xb8, 0x30, 0x20, 0x69, 0xf5, 0xb0, 0x85, 0x61, 0xc6, 0xee, 0xbe, 0x7f, 0x05, 0xe2, 0xf5,
+    0xa8, 0x42, 0x04, 0x8a, 0xbe, 0x8b, 0x47, 0xbe, 0x76, 0xfe, 0xae, 0xf2, 0x5c, 0xf2, 0x9b, 0x2a,
+    0xfa, 0x32, 0x00, 0x14, 0x16, 0x01, 0x42, 0x99, 0x89, 0xa1, 0x5f, 0xcf, 0xc6, 0x81, 0x5e, 0xb3,
+    0x63, 0x58, 0x3c, 0x2f, 0xd2, 0xf2, 0x0b, 0xe4, 0x98, 0x32, 0x83, 0xdd, 0x81, 0x4b, 0x16, 0xd7,
+    0xe1, 0x85, 0x41, 0x7a, 0xe5, 0x4a, 0xbc, 0x29, 0x6a, 0x3a, 0x6d, 0xb5, 0xc0, 0x04, 0x08, 0x3b,
+    0x68, 0xc5, 0x56, 0xc1, 0xf0, 0x23, 0x39, 0x91, 0x64, 0x19, 0x86, 0x4d, 0x50, 0xb7, 0x4d, 0x40,
+    0xae, 0xca, 0x48, 0x4c, 0x77, 0x35, 0x6c, 0x89, 0x5a, 0x0c, 0x27, 0x5a, 0xbf, 0xac, 0x49, 0x9d,
+    0x5d, 0x7d, 0x23, 0x62, 0xf2, 0x9c, 0x5e, 0x02, 0xe8, 0x71, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
+    0x66, 0x30, 0x64, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xd4, 0x0c,
+    0x10, 0x1b, 0xf8, 0xcd, 0x63, 0xb9, 0xf7, 0x39, 0x52, 0xb5, 0x0e, 0x13, 0x5c, 0xa6, 0xd7, 0x99,
+    0x93, 0x86, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x29,
+    0xfa, 0xf1, 0xac, 0xcc, 0x4d, 0xd2, 0x4c, 0x96, 0x40, 0x27, 0x75, 0xb6, 0xb0, 0xe9, 0x32, 0xe5,
+    0x07, 0xfe, 0x2e, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
+    0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
+    0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x84, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+    0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x9e, 0x2d, 0x48, 0x5f, 0x8c, 0x67,
+    0x33, 0xdc, 0x1a, 0x85, 0xad, 0x99, 0xd7, 0x50, 0x23, 0xea, 0x14, 0xec, 0x43, 0xb0, 0xe1, 0x9d,
+    0xea, 0xc2, 0x23, 0x46, 0x1e, 0x72, 0xb5, 0x19, 0xdc, 0x60, 0x22, 0xe4, 0xa5, 0x68, 0x31, 0x6c,
+    0x0b, 0x55, 0xc4, 0xe6, 0x9c, 0xa2, 0x2d, 0x9f, 0x3a, 0x4f, 0x93, 0x6b, 0x31, 0x8b, 0x16, 0x78,
+    0x16, 0x0d, 0x88, 0xcb, 0xd9, 0x8b, 0xcc, 0x80, 0x9d, 0x84, 0xf0, 0xc2, 0x27, 0xe3, 0x6b, 0x38,
+    0xf1, 0xfd, 0xd1, 0xe7, 0x17, 0x72, 0x31, 0x59, 0x35, 0x7d, 0x96, 0xf3, 0xc5, 0x7f, 0xab, 0x9d,
+    0x8f, 0x96, 0x61, 0x26, 0x4f, 0xb2, 0xbe, 0x81, 0xbb, 0x0d, 0x49, 0x04, 0x22, 0x8a, 0xce, 0x9f,
+    0xf7, 0xf5, 0x42, 0x2e, 0x25, 0x44, 0xfa, 0x21, 0x07, 0x12, 0x5a, 0x83, 0xb5, 0x55, 0xad, 0x18,
+    0x82, 0xf8, 0x40, 0x14, 0x9b, 0x9c, 0x20, 0x63, 0x04, 0x7f,
+};
+
+static uint8_t kRsaAttestRootCert[] = {
+    0x30, 0x82, 0x02, 0xa7, 0x30, 0x82, 0x02, 0x10, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00,
+    0xff, 0x94, 0xd9, 0xdd, 0x9f, 0x07, 0xc8, 0x0c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+    0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x63, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+    0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
+    0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06,
+    0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x56,
+    0x69, 0x65, 0x77, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x47, 0x6f,
+    0x6f, 0x67, 0x6c, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03,
+    0x55, 0x04, 0x0b, 0x0c, 0x07, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x30, 0x1e, 0x17, 0x0d,
+    0x31, 0x36, 0x30, 0x31, 0x30, 0x34, 0x31, 0x32, 0x33, 0x31, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x33,
+    0x35, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x33, 0x31, 0x30, 0x38, 0x5a, 0x30, 0x63, 0x31, 0x0b,
+    0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06,
+    0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61,
+    0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, 0x6f, 0x75, 0x6e, 0x74,
+    0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04,
+    0x0a, 0x0c, 0x0c, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31,
+    0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x07, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+    0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+    0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xa2, 0x6b,
+    0xad, 0xeb, 0x6e, 0x2e, 0x44, 0x61, 0xef, 0xd5, 0x0e, 0x82, 0xe6, 0xb7, 0x94, 0xd1, 0x75, 0x23,
+    0x1f, 0x77, 0x9b, 0x63, 0x91, 0x63, 0xff, 0xf7, 0xaa, 0xff, 0x0b, 0x72, 0x47, 0x4e, 0xc0, 0x2c,
+    0x43, 0xec, 0x33, 0x7c, 0xd7, 0xac, 0xed, 0x40, 0x3e, 0x8c, 0x28, 0xa0, 0x66, 0xd5, 0xf7, 0x87,
+    0x0b, 0x33, 0x97, 0xde, 0x0e, 0xb8, 0x4e, 0x13, 0x40, 0xab, 0xaf, 0xa5, 0x27, 0xbf, 0x95, 0x69,
+    0xa0, 0x31, 0xdb, 0x06, 0x52, 0x65, 0xf8, 0x44, 0x59, 0x57, 0x61, 0xf0, 0xbb, 0xf2, 0x17, 0x4b,
+    0xb7, 0x41, 0x80, 0x64, 0xc0, 0x28, 0x0e, 0x8f, 0x52, 0x77, 0x8e, 0xdb, 0xd2, 0x47, 0xb6, 0x45,
+    0xe9, 0x19, 0xc8, 0xe9, 0x8b, 0xc3, 0xdb, 0xc2, 0x91, 0x3f, 0xd7, 0xd7, 0x50, 0xc4, 0x1d, 0x35,
+    0x66, 0xf9, 0x57, 0xe4, 0x97, 0x96, 0x0b, 0x09, 0xac, 0xce, 0x92, 0x35, 0x85, 0x9b, 0x02, 0x03,
+    0x01, 0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
+    0x04, 0x14, 0x29, 0xfa, 0xf1, 0xac, 0xcc, 0x4d, 0xd2, 0x4c, 0x96, 0x40, 0x27, 0x75, 0xb6, 0xb0,
+    0xe9, 0x32, 0xe5, 0x07, 0xfe, 0x2e, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30,
+    0x16, 0x80, 0x14, 0x29, 0xfa, 0xf1, 0xac, 0xcc, 0x4d, 0xd2, 0x4c, 0x96, 0x40, 0x27, 0x75, 0xb6,
+    0xb0, 0xe9, 0x32, 0xe5, 0x07, 0xfe, 0x2e, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+    0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
+    0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x84, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+    0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x4f, 0x72, 0xf3, 0x36, 0x59,
+    0x8d, 0x0e, 0xc1, 0xb9, 0x74, 0x5b, 0x31, 0x59, 0xf6, 0xf0, 0x8d, 0x25, 0x49, 0x30, 0x9e, 0xa3,
+    0x1c, 0x1c, 0x29, 0xd2, 0x45, 0x2d, 0x20, 0xb9, 0x4d, 0x5f, 0x64, 0xb4, 0xe8, 0x80, 0xc7, 0x78,
+    0x7a, 0x9c, 0x39, 0xde, 0xa8, 0xb3, 0xf5, 0xbf, 0x2f, 0x70, 0x5f, 0x47, 0x10, 0x5c, 0xc5, 0xe6,
+    0xeb, 0x4d, 0x06, 0x99, 0x61, 0xd2, 0xae, 0x9a, 0x07, 0xff, 0xf7, 0x7c, 0xb8, 0xab, 0xeb, 0x9c,
+    0x0f, 0x24, 0x07, 0x5e, 0xb1, 0x7f, 0xba, 0x79, 0x71, 0xfd, 0x4d, 0x5b, 0x9e, 0xdf, 0x14, 0xa9,
+    0xfe, 0xdf, 0xed, 0x7c, 0xc0, 0x88, 0x5d, 0xf8, 0xdd, 0x9b, 0x64, 0x32, 0x56, 0xd5, 0x35, 0x9a,
+    0xe2, 0x13, 0xf9, 0x8f, 0xce, 0xc1, 0x7c, 0xdc, 0xef, 0xa4, 0xaa, 0xb2, 0x55, 0xc3, 0x83, 0xa9,
+    0x2e, 0xfb, 0x5c, 0xf6, 0x62, 0xf5, 0x27, 0x52, 0x17, 0xbe, 0x63,
+};
+
+static uint8_t kEcAttestKey[] = {
+    0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x21, 0xe0, 0x86, 0x43, 0x2a, 0x15, 0x19, 0x84, 0x59,
+    0xcf, 0x36, 0x3a, 0x50, 0xfc, 0x14, 0xc9, 0xda, 0xad, 0xf9, 0x35, 0xf5, 0x27, 0xc2, 0xdf, 0xd7,
+    0x1e, 0x4d, 0x6d, 0xbc, 0x42, 0xe5, 0x44, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+    0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0xeb, 0x9e, 0x79, 0xf8, 0x42, 0x63, 0x59,
+    0xac, 0xcb, 0x2a, 0x91, 0x4c, 0x89, 0x86, 0xcc, 0x70, 0xad, 0x90, 0x66, 0x93, 0x82, 0xa9, 0x73,
+    0x26, 0x13, 0xfe, 0xac, 0xcb, 0xf8, 0x21, 0x27, 0x4c, 0x21, 0x74, 0x97, 0x4a, 0x2a, 0xfe, 0xa5,
+    0xb9, 0x4d, 0x7f, 0x66, 0xd4, 0xe0, 0x65, 0x10, 0x66, 0x35, 0xbc, 0x53, 0xb7, 0xa0, 0xa3, 0xa6,
+    0x71, 0x58, 0x3e, 0xdb, 0x3e, 0x11, 0xae, 0x10, 0x14,
+};
+
+static uint8_t kEcAttestCert[] = {
+    0x30, 0x82, 0x02, 0x78, 0x30, 0x82, 0x02, 0x1e, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x10,
+    0x01, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x81, 0x98,
+    0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30,
+    0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e,
+    0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, 0x6f, 0x75,
+    0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03,
+    0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63,
+    0x2e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x07, 0x41, 0x6e, 0x64, 0x72,
+    0x6f, 0x69, 0x64, 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2a, 0x41, 0x6e,
+    0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x4b, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x53,
+    0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74,
+    0x69, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x31,
+    0x31, 0x31, 0x30, 0x30, 0x34, 0x36, 0x30, 0x39, 0x5a, 0x17, 0x0d, 0x32, 0x36, 0x30, 0x31, 0x30,
+    0x38, 0x30, 0x30, 0x34, 0x36, 0x30, 0x39, 0x5a, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06,
+    0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
+    0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x15, 0x30,
+    0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2c, 0x20,
+    0x49, 0x6e, 0x63, 0x2e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x07, 0x41,
+    0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
+    0x32, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x4b, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72,
+    0x65, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73,
+    0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69,
+    0x61, 0x74, 0x65, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
+    0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xeb, 0x9e,
+    0x79, 0xf8, 0x42, 0x63, 0x59, 0xac, 0xcb, 0x2a, 0x91, 0x4c, 0x89, 0x86, 0xcc, 0x70, 0xad, 0x90,
+    0x66, 0x93, 0x82, 0xa9, 0x73, 0x26, 0x13, 0xfe, 0xac, 0xcb, 0xf8, 0x21, 0x27, 0x4c, 0x21, 0x74,
+    0x97, 0x4a, 0x2a, 0xfe, 0xa5, 0xb9, 0x4d, 0x7f, 0x66, 0xd4, 0xe0, 0x65, 0x10, 0x66, 0x35, 0xbc,
+    0x53, 0xb7, 0xa0, 0xa3, 0xa6, 0x71, 0x58, 0x3e, 0xdb, 0x3e, 0x11, 0xae, 0x10, 0x14, 0xa3, 0x66,
+    0x30, 0x64, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x3f, 0xfc, 0xac,
+    0xd6, 0x1a, 0xb1, 0x3a, 0x9e, 0x81, 0x20, 0xb8, 0xd5, 0x25, 0x1c, 0xc5, 0x65, 0xbb, 0x1e, 0x91,
+    0xa9, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xc8, 0xad,
+    0xe9, 0x77, 0x4c, 0x45, 0xc3, 0xa3, 0xcf, 0x0d, 0x16, 0x10, 0xe4, 0x79, 0x43, 0x3a, 0x21, 0x5a,
+    0x30, 0xcf, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06,
+    0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
+    0x04, 0x04, 0x03, 0x02, 0x02, 0x84, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04,
+    0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x20, 0x4b, 0x8a, 0x9b, 0x7b, 0xee, 0x82, 0xbc,
+    0xc0, 0x33, 0x87, 0xae, 0x2f, 0xc0, 0x89, 0x98, 0xb4, 0xdd, 0xc3, 0x8d, 0xab, 0x27, 0x2a, 0x45,
+    0x9f, 0x69, 0x0c, 0xc7, 0xc3, 0x92, 0xd4, 0x0f, 0x8e, 0x02, 0x21, 0x00, 0xee, 0xda, 0x01, 0x5d,
+    0xb6, 0xf4, 0x32, 0xe9, 0xd4, 0x84, 0x3b, 0x62, 0x4c, 0x94, 0x04, 0xef, 0x3a, 0x7c, 0xcc, 0xbd,
+    0x5e, 0xfb, 0x22, 0xbb, 0xe7, 0xfe, 0xb9, 0x77, 0x3f, 0x59, 0x3f, 0xfb,
+};
+
+static uint8_t kEcAttestRootCert[] = {
+    0x30, 0x82, 0x02, 0x8b, 0x30, 0x82, 0x02, 0x32, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00,
+    0xa2, 0x05, 0x9e, 0xd1, 0x0e, 0x43, 0x5b, 0x57, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
+    0x3d, 0x04, 0x03, 0x02, 0x30, 0x81, 0x98, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+    0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43,
+    0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55,
+    0x04, 0x07, 0x0c, 0x0d, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65,
+    0x77, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x47, 0x6f, 0x6f, 0x67,
+    0x6c, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04,
+    0x0b, 0x0c, 0x07, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x31, 0x33, 0x30, 0x31, 0x06, 0x03,
+    0x55, 0x04, 0x03, 0x0c, 0x2a, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x4b, 0x65, 0x79,
+    0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x41,
+    0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30,
+    0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x31, 0x31, 0x31, 0x30, 0x30, 0x34, 0x33, 0x35, 0x30, 0x5a,
+    0x17, 0x0d, 0x33, 0x36, 0x30, 0x31, 0x30, 0x36, 0x30, 0x30, 0x34, 0x33, 0x35, 0x30, 0x5a, 0x30,
+    0x81, 0x98, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+    0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f,
+    0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d,
+    0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x15, 0x30, 0x13,
+    0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2c, 0x20, 0x49,
+    0x6e, 0x63, 0x2e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x07, 0x41, 0x6e,
+    0x64, 0x72, 0x6f, 0x69, 0x64, 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2a,
+    0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x4b, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65,
+    0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74,
+    0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
+    0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01,
+    0x07, 0x03, 0x42, 0x00, 0x04, 0xee, 0x5d, 0x5e, 0xc7, 0xe1, 0xc0, 0xdb, 0x6d, 0x03, 0xa6, 0x7e,
+    0xe6, 0xb6, 0x1b, 0xec, 0x4d, 0x6a, 0x5d, 0x6a, 0x68, 0x2e, 0x0f, 0xff, 0x7f, 0x49, 0x0e, 0x7d,
+    0x77, 0x1f, 0x44, 0x22, 0x6d, 0xbd, 0xb1, 0xaf, 0xfa, 0x16, 0xcb, 0xc7, 0xad, 0xc5, 0x77, 0xd2,
+    0x56, 0x9c, 0xaa, 0xb7, 0xb0, 0x2d, 0x54, 0x01, 0x5d, 0x3e, 0x43, 0x2b, 0x2a, 0x8e, 0xd7, 0x4e,
+    0xec, 0x48, 0x75, 0x41, 0xa4, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
+    0x04, 0x16, 0x04, 0x14, 0xc8, 0xad, 0xe9, 0x77, 0x4c, 0x45, 0xc3, 0xa3, 0xcf, 0x0d, 0x16, 0x10,
+    0xe4, 0x79, 0x43, 0x3a, 0x21, 0x5a, 0x30, 0xcf, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
+    0x18, 0x30, 0x16, 0x80, 0x14, 0xc8, 0xad, 0xe9, 0x77, 0x4c, 0x45, 0xc3, 0xa3, 0xcf, 0x0d, 0x16,
+    0x10, 0xe4, 0x79, 0x43, 0x3a, 0x21, 0x5a, 0x30, 0xcf, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13,
+    0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
+    0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x84, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86,
+    0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x47, 0x00, 0x30, 0x44, 0x02, 0x20, 0x35, 0x21, 0xa3,
+    0xef, 0x8b, 0x34, 0x46, 0x1e, 0x9c, 0xd5, 0x60, 0xf3, 0x1d, 0x58, 0x89, 0x20, 0x6a, 0xdc, 0xa3,
+    0x65, 0x41, 0xf6, 0x0d, 0x9e, 0xce, 0x8a, 0x19, 0x8c, 0x66, 0x48, 0x60, 0x7b, 0x02, 0x20, 0x4d,
+    0x0b, 0xf3, 0x51, 0xd9, 0x30, 0x7c, 0x7d, 0x5b, 0xda, 0x35, 0x34, 0x1d, 0xa8, 0x47, 0x1b, 0x63,
+    0xa5, 0x85, 0x65, 0x3c, 0xad, 0x4f, 0x24, 0xa7, 0xe7, 0x4d, 0xaf, 0x41, 0x7d, 0xf1, 0xbf,
+};
+
+size_t kCertificateChainLength = 2;
+
+}  // anonymous namespace
+
+SoftKeymasterContext::SoftKeymasterContext(const std::string& root_of_trust)
+    : rsa_factory_(new RsaKeyFactory(this)), ec_factory_(new EcKeyFactory(this)),
+      aes_factory_(new AesKeyFactory(this)), hmac_factory_(new HmacKeyFactory(this)),
+      km1_dev_(nullptr), root_of_trust_(root_of_trust) {}
+
+SoftKeymasterContext::~SoftKeymasterContext() {}
+
+keymaster_error_t SoftKeymasterContext::SetHardwareDevice(keymaster0_device_t* keymaster0_device) {
+    if (!keymaster0_device)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if ((keymaster0_device->flags & KEYMASTER_SOFTWARE_ONLY) != 0) {
+        LOG_E("SoftKeymasterContext only wraps hardware keymaster0 devices", 0);
+        return KM_ERROR_INVALID_ARGUMENT;
+    }
+
+    km0_engine_.reset(new Keymaster0Engine(keymaster0_device));
+    rsa_factory_.reset(new RsaKeymaster0KeyFactory(this, km0_engine_.get()));
+    ec_factory_.reset(new EcdsaKeymaster0KeyFactory(this, km0_engine_.get()));
+    // Keep AES and HMAC factories.
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t SoftKeymasterContext::SetHardwareDevice(keymaster1_device_t* keymaster1_device) {
+    if (!keymaster1_device)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    km1_dev_ = keymaster1_device;
+
+    km1_engine_.reset(new Keymaster1Engine(keymaster1_device));
+    rsa_factory_.reset(new RsaKeymaster1KeyFactory(this, km1_engine_.get()));
+    ec_factory_.reset(new EcdsaKeymaster1KeyFactory(this, km1_engine_.get()));
+
+    // All AES and HMAC operations should be passed directly to the keymaster1 device.  Explicitly
+    // do not handle them, to provoke errors in case the higher layers fail to send them to the
+    // device.
+    aes_factory_.reset(nullptr);
+    hmac_factory_.reset(nullptr);
+
+    return KM_ERROR_OK;
+}
+
+KeyFactory* SoftKeymasterContext::GetKeyFactory(keymaster_algorithm_t algorithm) const {
+    switch (algorithm) {
+    case KM_ALGORITHM_RSA:
+        return rsa_factory_.get();
+    case KM_ALGORITHM_EC:
+        return ec_factory_.get();
+    case KM_ALGORITHM_AES:
+        return aes_factory_.get();
+    case KM_ALGORITHM_HMAC:
+        return hmac_factory_.get();
+    default:
+        return nullptr;
+    }
+}
+
+static keymaster_algorithm_t supported_algorithms[] = {KM_ALGORITHM_RSA, KM_ALGORITHM_EC,
+                                                       KM_ALGORITHM_AES, KM_ALGORITHM_HMAC};
+
+keymaster_algorithm_t*
+SoftKeymasterContext::GetSupportedAlgorithms(size_t* algorithms_count) const {
+    *algorithms_count = array_length(supported_algorithms);
+    return supported_algorithms;
+}
+
+OperationFactory* SoftKeymasterContext::GetOperationFactory(keymaster_algorithm_t algorithm,
+                                                            keymaster_purpose_t purpose) const {
+    KeyFactory* key_factory = GetKeyFactory(algorithm);
+    if (!key_factory)
+        return nullptr;
+    return key_factory->GetOperationFactory(purpose);
+}
+
+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 SetAuthorizations(const AuthorizationSet& key_description,
+                                           keymaster_key_origin_t origin,
+                                           AuthorizationSet* hw_enforced,
+                                           AuthorizationSet* sw_enforced) {
+    sw_enforced->Clear();
+
+    for (auto& entry : key_description) {
+        switch (entry.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, unless the KeyFactory has placed it in
+        // hw_enforced, in which case we defer to its decision.
+        default:
+            if (hw_enforced->GetTagCount(entry.tag) == 0)
+                sw_enforced->push_back(entry);
+            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 = 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;
+
+    return SerializeIntegrityAssuredBlob(key_material, hidden, *hw_enforced, *sw_enforced, blob);
+}
+
+static keymaster_error_t ParseOcbAuthEncryptedBlob(const KeymasterKeyBlob& blob,
+                                                   const AuthorizationSet& hidden,
+                                                   KeymasterKeyBlob* key_material,
+                                                   AuthorizationSet* hw_enforced,
+                                                   AuthorizationSet* sw_enforced) {
+    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;
+
+    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);
+}
+
+// Note: This parsing code in below is from system/security/softkeymaster/keymaster_openssl.cpp's
+// unwrap_key function, modified for the preferred function signature and formatting.  It does some
+// odd things, but they have been left unchanged to avoid breaking compatibility.
+static const uint8_t SOFT_KEY_MAGIC[] = {'P', 'K', '#', '8'};
+keymaster_error_t SoftKeymasterContext::ParseOldSoftkeymasterBlob(
+    const KeymasterKeyBlob& blob, KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced,
+    AuthorizationSet* sw_enforced) const {
+    long publicLen = 0;
+    long privateLen = 0;
+    const uint8_t* p = blob.key_material;
+    const uint8_t* end = blob.key_material + blob.key_material_size;
+
+    int type = 0;
+    ptrdiff_t min_size =
+        sizeof(SOFT_KEY_MAGIC) + sizeof(type) + sizeof(publicLen) + 1 + sizeof(privateLen) + 1;
+    if (end - p < min_size) {
+        LOG_W("key blob appears to be truncated (if an old SW key)", 0);
+        return KM_ERROR_INVALID_KEY_BLOB;
+    }
+
+    if (memcmp(p, SOFT_KEY_MAGIC, sizeof(SOFT_KEY_MAGIC)) != 0)
+        return KM_ERROR_INVALID_KEY_BLOB;
+    p += sizeof(SOFT_KEY_MAGIC);
+
+    for (size_t i = 0; i < sizeof(type); i++)
+        type = (type << 8) | *p++;
+
+    for (size_t i = 0; i < sizeof(type); i++)
+        publicLen = (publicLen << 8) | *p++;
+
+    if (p + publicLen > end) {
+        LOG_W("public key length encoding error: size=%ld, end=%td", publicLen, end - p);
+        return KM_ERROR_INVALID_KEY_BLOB;
+    }
+    p += publicLen;
+
+    if (end - p < 2) {
+        LOG_W("key blob appears to be truncated (if an old SW key)", 0);
+        return KM_ERROR_INVALID_KEY_BLOB;
+    }
+
+    for (size_t i = 0; i < sizeof(type); i++)
+        privateLen = (privateLen << 8) | *p++;
+
+    if (p + privateLen > end) {
+        LOG_W("private key length encoding error: size=%ld, end=%td", privateLen, end - p);
+        return KM_ERROR_INVALID_KEY_BLOB;
+    }
+
+    // Just to be sure, make sure that the ASN.1 structure parses correctly.  We don't actually use
+    // the EVP_PKEY here.
+    const uint8_t* key_start = p;
+    unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PrivateKey(type, nullptr, &p, privateLen));
+    if (pkey.get() == nullptr) {
+        LOG_W("Failed to parse PKCS#8 key material (if old SW key)", 0);
+        return KM_ERROR_INVALID_KEY_BLOB;
+    }
+
+    // All auths go into sw_enforced, including those that would be HW-enforced if we were faking
+    // auths for a HW-backed key.
+    hw_enforced->Clear();
+    keymaster_error_t error = FakeKeyAuthorizations(pkey.get(), sw_enforced, sw_enforced);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    if (!key_material->Reset(privateLen))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    memcpy(key_material->writable_data(), key_start, privateLen);
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t SoftKeymasterContext::ParseKeyBlob(const KeymasterKeyBlob& blob,
+                                                     const AuthorizationSet& additional_params,
+                                                     KeymasterKeyBlob* key_material,
+                                                     AuthorizationSet* hw_enforced,
+                                                     AuthorizationSet* sw_enforced) const {
+    // This is a little bit complicated.
+    //
+    // The SoftKeymasterContext has to handle a lot of different kinds of key blobs.
+    //
+    // 1.  New keymaster1 software key blobs.  These are integrity-assured but not encrypted.  The
+    //     raw key material and auth sets should be extracted and returned.  This is the kind
+    //     produced by this context when the KeyFactory doesn't use keymaster0 to back the keys.
+    //
+    // 2.  Old keymaster1 software key blobs.  These are OCB-encrypted with an all-zero master key.
+    //     They should be decrypted and the key material and auth sets extracted and returned.
+    //
+    // 3.  Old keymaster0 software key blobs.  These are raw key material with a small header tacked
+    //     on the front.  They don't have auth sets, so reasonable defaults are generated and
+    //     returned along with the raw key material.
+    //
+    // 4.  New keymaster0 hardware key blobs.  These are integrity-assured but not encrypted (though
+    //     they're protected by the keymaster0 hardware implementation).  The keymaster0 key blob
+    //     and auth sets should be extracted and returned.
+    //
+    // 5.  Keymaster1 hardware key blobs.  These are raw hardware key blobs.  They contain auth
+    //     sets, which we retrieve from the hardware module.
+    //
+    // 6.  Old keymaster0 hardware key blobs.  These are raw hardware key blobs.  They don't have
+    //     auth sets so reasonable defaults are generated and returned along with the key blob.
+    //
+    // Determining what kind of blob has arrived is somewhat tricky.  What helps is that
+    // integrity-assured and OCB-encrypted blobs are self-consistent and effectively impossible to
+    // parse as anything else.  Old keymaster0 software key blobs have a header.  It's reasonably
+    // unlikely that hardware keys would have the same header.  So anything that is neither
+    // integrity-assured nor OCB-encrypted and lacks the old software key header is assumed to be
+    // keymaster0 hardware.
+
+    AuthorizationSet hidden;
+    keymaster_error_t error = BuildHiddenAuthorizations(additional_params, &hidden);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    // Assume it's an integrity-assured blob (new software-only blob, or new keymaster0-backed
+    // blob).
+    error = DeserializeIntegrityAssuredBlob(blob, hidden, key_material, hw_enforced, sw_enforced);
+    if (error != KM_ERROR_INVALID_KEY_BLOB)
+        return error;
+
+    // Wasn't an integrity-assured blob.  Maybe it's an OCB-encrypted blob.
+    error = ParseOcbAuthEncryptedBlob(blob, hidden, key_material, hw_enforced, sw_enforced);
+    if (error == KM_ERROR_OK)
+        LOG_D("Parsed an old keymaster1 software key", 0);
+    if (error != KM_ERROR_INVALID_KEY_BLOB)
+        return error;
+
+    // Wasn't an OCB-encrypted blob.  Maybe it's an old softkeymaster blob.
+    error = ParseOldSoftkeymasterBlob(blob, key_material, hw_enforced, sw_enforced);
+    if (error == KM_ERROR_OK)
+        LOG_D("Parsed an old sofkeymaster key", 0);
+    if (error != KM_ERROR_INVALID_KEY_BLOB)
+        return error;
+
+    if (km1_dev_)
+        return ParseKeymaster1HwBlob(blob, additional_params, key_material, hw_enforced,
+                                     sw_enforced);
+    else if (km0_engine_)
+        return ParseKeymaster0HwBlob(blob, key_material, hw_enforced, sw_enforced);
+
+    LOG_E("Failed to parse key; not a valid software blob, no hardware module configured", 0);
+    return KM_ERROR_INVALID_KEY_BLOB;
+}
+
+keymaster_error_t SoftKeymasterContext::DeleteKey(const KeymasterKeyBlob& blob) const {
+    if (km1_engine_) {
+        keymaster_error_t error = km1_engine_->DeleteKey(blob);
+        if (error == KM_ERROR_INVALID_KEY_BLOB) {
+            // Note that we succeed on invalid blob, because it probably just indicates that the
+            // blob is a software blob, not a hardware blob.
+            error = KM_ERROR_OK;
+        }
+        return error;
+    }
+
+    if (km0_engine_) {
+        // This could be a keymaster0 hardware key, and it could be either raw or encapsulated in an
+        // integrity-assured blob.  If it's integrity-assured, we can't validate it strongly,
+        // because we don't have the necessary additional_params data.  However, the probability
+        // that anything other than an integrity-assured blob would have all of the structure
+        // required to decode as a valid blob is low -- unless it's maliciously-constructed, but the
+        // deserializer should be proof against bad data, as should the keymaster0 hardware.
+        //
+        // Thus, we first try to parse it as integrity-assured.  If that works, we pass the result
+        // to the underlying hardware.  If not, we pass blob unmodified to the underlying hardware.
+        KeymasterKeyBlob key_material;
+        AuthorizationSet hw_enforced, sw_enforced;
+        keymaster_error_t error = DeserializeIntegrityAssuredBlob_NoHmacCheck(
+            blob, &key_material, &hw_enforced, &sw_enforced);
+        if (error == KM_ERROR_OK && km0_engine_->DeleteKey(key_material))
+            return KM_ERROR_OK;
+
+        km0_engine_->DeleteKey(blob);
+
+        // We succeed unconditionally at this point, even if delete failed.  Failure indicates that
+        // either the blob is a software blob (which we can't distinguish with certainty without
+        // additional_params) or because it is a hardware blob and the hardware failed.  In the
+        // first case, there is no error.  In the second case, the client can't do anything to fix
+        // it anyway, so it's not too harmful to simply swallow the error.  This is not ideal, but
+        // it's the least-bad alternative.
+        return KM_ERROR_OK;
+    }
+
+    // Nothing to do for software-only contexts.
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t SoftKeymasterContext::DeleteAllKeys() const {
+    if (km1_engine_)
+        return km1_engine_->DeleteAllKeys();
+
+    if (km0_engine_ && !km0_engine_->DeleteAllKeys())
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    return KM_ERROR_OK;
+}
+
+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;
+}
+
+EVP_PKEY* SoftKeymasterContext::AttestationKey(keymaster_algorithm_t algorithm,
+                                               keymaster_error_t* error) const {
+
+    const uint8_t* key;
+    size_t key_length;
+    int evp_key_type;
+
+    switch (algorithm) {
+    case KM_ALGORITHM_RSA:
+        key = kRsaAttestKey;
+        key_length = array_length(kRsaAttestKey);
+        evp_key_type = EVP_PKEY_RSA;
+        break;
+
+    case KM_ALGORITHM_EC:
+        key = kEcAttestKey;
+        key_length = array_length(kEcAttestKey);
+        evp_key_type = EVP_PKEY_EC;
+        break;
+
+    default:
+        *error = KM_ERROR_UNSUPPORTED_ALGORITHM;
+        return nullptr;
+    }
+
+    EVP_PKEY* pkey = d2i_PrivateKey(evp_key_type, nullptr /* pkey */, &key, key_length);
+    if (!pkey)
+        *error = TranslateLastOpenSslError();
+
+    return pkey;
+}
+
+keymaster_cert_chain_t* SoftKeymasterContext::AttestationChain(keymaster_algorithm_t algorithm,
+                                                               keymaster_error_t* error) const {
+    // If we have to bail it will be because of an allocation failure.
+    *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    UniquePtr<keymaster_cert_chain_t, CertificateChainDelete> chain(new keymaster_cert_chain_t);
+    if (!chain.get())
+        return nullptr;
+    memset(chain.get(), 0, sizeof(keymaster_cert_chain_t));
+
+    chain->entries = new keymaster_blob_t[kCertificateChainLength];
+    if (!chain->entries)
+        return nullptr;
+
+    memset(chain->entries, 0, sizeof(chain->entries[0]) * kCertificateChainLength);
+    chain->entry_count = kCertificateChainLength;
+
+    size_t entry = 0;
+
+    switch (algorithm) {
+    case KM_ALGORITHM_RSA:
+        chain->entries[entry].data = dup_array(kRsaAttestCert);
+        if (!chain->entries[entry].data)
+            return nullptr;
+        chain->entries[entry].data_length = array_length(kRsaAttestCert);
+        entry++;
+        chain->entries[entry].data = dup_array(kRsaAttestRootCert);
+        if (!chain->entries[entry].data)
+            return nullptr;
+        chain->entries[entry].data_length = array_length(kRsaAttestRootCert);
+        entry++;
+        break;
+
+    case KM_ALGORITHM_EC:
+        chain->entries[entry].data = dup_array(kEcAttestCert);
+        if (!chain->entries[entry].data)
+            return nullptr;
+        chain->entries[entry].data_length = array_length(kEcAttestCert);
+        entry++;
+        chain->entries[entry].data = dup_array(kEcAttestRootCert);
+        if (!chain->entries[entry].data)
+            return nullptr;
+        chain->entries[entry].data_length = array_length(kEcAttestRootCert);
+        entry++;
+        break;
+
+    default:
+        *error = KM_ERROR_UNSUPPORTED_ALGORITHM;
+        return nullptr;
+    };
+
+    assert(entry == kCertificateChainLength);
+
+    *error = KM_ERROR_OK;
+    return chain.release();
+}
+
+keymaster_error_t SoftKeymasterContext::ParseKeymaster1HwBlob(
+    const KeymasterKeyBlob& blob, const AuthorizationSet& additional_params,
+    KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced,
+    AuthorizationSet* sw_enforced) const {
+    assert(km1_dev_);
+
+    keymaster_blob_t client_id = {nullptr, 0};
+    keymaster_blob_t app_data = {nullptr, 0};
+    keymaster_blob_t* client_id_ptr = nullptr;
+    keymaster_blob_t* app_data_ptr = nullptr;
+    if (additional_params.GetTagValue(TAG_APPLICATION_ID, &client_id))
+        client_id_ptr = &client_id;
+    if (additional_params.GetTagValue(TAG_APPLICATION_DATA, &app_data))
+        app_data_ptr = &app_data;
+
+    // Get key characteristics, which incidentally verifies that the HW recognizes the key.
+    keymaster_key_characteristics_t* characteristics;
+    keymaster_error_t error = km1_dev_->get_key_characteristics(km1_dev_, &blob, client_id_ptr,
+                                                                app_data_ptr, &characteristics);
+    if (error != KM_ERROR_OK)
+        return error;
+    unique_ptr<keymaster_key_characteristics_t, Characteristics_Delete> characteristics_deleter(
+        characteristics);
+
+    LOG_D("Module \"%s\" accepted key", km1_dev_->common.module->name);
+
+    hw_enforced->Reinitialize(characteristics->hw_enforced);
+    sw_enforced->Reinitialize(characteristics->sw_enforced);
+    *key_material = blob;
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t SoftKeymasterContext::ParseKeymaster0HwBlob(const KeymasterKeyBlob& blob,
+                                                              KeymasterKeyBlob* key_material,
+                                                              AuthorizationSet* hw_enforced,
+                                                              AuthorizationSet* sw_enforced) const {
+    assert(km0_engine_);
+
+    unique_ptr<EVP_PKEY, EVP_PKEY_Delete> tmp_key(km0_engine_->GetKeymaster0PublicKey(blob));
+
+    if (!tmp_key)
+        return KM_ERROR_INVALID_KEY_BLOB;
+
+    LOG_D("Module \"%s\" accepted key", km0_engine_->device()->common.module->name);
+    keymaster_error_t error = FakeKeyAuthorizations(tmp_key.get(), hw_enforced, sw_enforced);
+    if (error == KM_ERROR_OK)
+        *key_material = blob;
+
+    return error;
+}
+
+keymaster_error_t SoftKeymasterContext::FakeKeyAuthorizations(EVP_PKEY* pubkey,
+                                                              AuthorizationSet* hw_enforced,
+                                                              AuthorizationSet* sw_enforced) const {
+    hw_enforced->Clear();
+    sw_enforced->Clear();
+
+    switch (EVP_PKEY_type(pubkey->type)) {
+    case EVP_PKEY_RSA: {
+        hw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
+        hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_NONE);
+        hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_MD5);
+        hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA1);
+        hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_224);
+        hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+        hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_384);
+        hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_512);
+        hw_enforced->push_back(TAG_PADDING, KM_PAD_NONE);
+        hw_enforced->push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN);
+        hw_enforced->push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+        hw_enforced->push_back(TAG_PADDING, KM_PAD_RSA_PSS);
+        hw_enforced->push_back(TAG_PADDING, KM_PAD_RSA_OAEP);
+
+        sw_enforced->push_back(TAG_PURPOSE, KM_PURPOSE_SIGN);
+        sw_enforced->push_back(TAG_PURPOSE, KM_PURPOSE_VERIFY);
+        sw_enforced->push_back(TAG_PURPOSE, KM_PURPOSE_ENCRYPT);
+        sw_enforced->push_back(TAG_PURPOSE, KM_PURPOSE_DECRYPT);
+
+        unique_ptr<RSA, RSA_Delete> rsa(EVP_PKEY_get1_RSA(pubkey));
+        if (!rsa)
+            return TranslateLastOpenSslError();
+        hw_enforced->push_back(TAG_KEY_SIZE, RSA_size(rsa.get()) * 8);
+        uint64_t public_exponent = BN_get_word(rsa->e);
+        if (public_exponent == 0xffffffffL)
+            return KM_ERROR_INVALID_KEY_BLOB;
+        hw_enforced->push_back(TAG_RSA_PUBLIC_EXPONENT, public_exponent);
+        break;
+    }
+
+    case EVP_PKEY_EC: {
+        hw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
+        hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_NONE);
+        hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_MD5);
+        hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA1);
+        hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_224);
+        hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+        hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_384);
+        hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_512);
+
+        sw_enforced->push_back(TAG_PURPOSE, KM_PURPOSE_SIGN);
+        sw_enforced->push_back(TAG_PURPOSE, KM_PURPOSE_VERIFY);
+
+        UniquePtr<EC_KEY, EC_KEY_Delete> ec_key(EVP_PKEY_get1_EC_KEY(pubkey));
+        if (!ec_key.get())
+            return TranslateLastOpenSslError();
+        size_t key_size_bits;
+        keymaster_error_t error =
+            ec_get_group_size(EC_KEY_get0_group(ec_key.get()), &key_size_bits);
+        if (error != KM_ERROR_OK)
+            return error;
+        hw_enforced->push_back(TAG_KEY_SIZE, key_size_bits);
+        break;
+    }
+
+    default:
+        return KM_ERROR_UNSUPPORTED_ALGORITHM;
+    }
+
+    sw_enforced->push_back(TAG_ALL_USERS);
+    sw_enforced->push_back(TAG_NO_AUTH_REQUIRED);
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t SoftKeymasterContext::BuildHiddenAuthorizations(const AuthorizationSet& input_set,
+                                                                  AuthorizationSet* hidden) const {
+    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(TAG_ROOT_OF_TRUST, reinterpret_cast<const uint8_t*>(root_of_trust_.data()),
+                      root_of_trust_.size());
+
+    return TranslateAuthorizationSetError(hidden->is_valid());
+}
+
+}  // namespace keymaster
diff --git a/keymaster/soft_keymaster_device.cpp b/keymaster/soft_keymaster_device.cpp
new file mode 100644
index 0000000..cbeaec7
--- /dev/null
+++ b/keymaster/soft_keymaster_device.cpp
@@ -0,0 +1,1341 @@
+/*
+ * 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_device.h>
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <algorithm>
+
+#include <type_traits>
+
+#include <openssl/x509.h>
+
+#include <hardware/keymaster1.h>
+#define LOG_TAG "SoftKeymasterDevice"
+#include <cutils/log.h>
+
+#include <keymaster/android_keymaster.h>
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/soft_keymaster_context.h>
+#include <keymaster/soft_keymaster_logger.h>
+
+#include "openssl_utils.h"
+
+struct keystore_module soft_keymaster1_device_module = {
+    .common =
+        {
+            .tag = HARDWARE_MODULE_TAG,
+            .module_api_version = KEYMASTER_MODULE_API_VERSION_1_0,
+            .hal_api_version = HARDWARE_HAL_API_VERSION,
+            .id = KEYSTORE_HARDWARE_MODULE_ID,
+            .name = "OpenSSL-based SoftKeymaster HAL",
+            .author = "The Android Open Source Project",
+            .methods = nullptr,
+            .dso = 0,
+            .reserved = {},
+        },
+};
+
+struct keystore_module soft_keymaster2_device_module = {
+    .common =
+        {
+            .tag = HARDWARE_MODULE_TAG,
+            .module_api_version = KEYMASTER_MODULE_API_VERSION_2_0,
+            .hal_api_version = HARDWARE_HAL_API_VERSION,
+            .id = KEYSTORE_HARDWARE_MODULE_ID,
+            .name = "OpenSSL-based SoftKeymaster HAL",
+            .author = "The Android Open Source Project",
+            .methods = nullptr,
+            .dso = 0,
+            .reserved = {},
+        },
+};
+
+namespace keymaster {
+
+const size_t kOperationTableSize = 16;
+
+template <typename T> std::vector<T> make_vector(const T* array, size_t len) {
+    return std::vector<T>(array, array + len);
+}
+
+static keymaster_error_t add_digests(keymaster1_device_t* dev, keymaster_algorithm_t algorithm,
+                                     keymaster_purpose_t purpose,
+                                     SoftKeymasterDevice::DigestMap* map) {
+    auto key = std::make_pair(algorithm, purpose);
+
+    keymaster_digest_t* digests;
+    size_t digests_length;
+    keymaster_error_t error =
+        dev->get_supported_digests(dev, algorithm, purpose, &digests, &digests_length);
+    if (error != KM_ERROR_OK) {
+        LOG_E("Error %d getting supported digests from keymaster1 device", error);
+        return error;
+    }
+    std::unique_ptr<keymaster_digest_t, Malloc_Delete> digests_deleter(digests);
+
+    (*map)[key] = make_vector(digests, digests_length);
+    return KM_ERROR_OK;
+}
+
+static keymaster_error_t map_digests(keymaster1_device_t* dev,
+                                     SoftKeymasterDevice::DigestMap* map) {
+    map->clear();
+
+    keymaster_algorithm_t sig_algorithms[] = {KM_ALGORITHM_RSA, KM_ALGORITHM_EC};
+    keymaster_purpose_t sig_purposes[] = {KM_PURPOSE_SIGN, KM_PURPOSE_VERIFY};
+    for (auto algorithm : sig_algorithms)
+        for (auto purpose : sig_purposes) {
+            keymaster_error_t error = add_digests(dev, algorithm, purpose, map);
+            if (error != KM_ERROR_OK)
+                return error;
+        }
+
+    keymaster_algorithm_t crypt_algorithms[] = {KM_ALGORITHM_RSA};
+    keymaster_purpose_t crypt_purposes[] = {KM_PURPOSE_ENCRYPT, KM_PURPOSE_DECRYPT};
+    for (auto algorithm : crypt_algorithms)
+        for (auto purpose : crypt_purposes) {
+            keymaster_error_t error = add_digests(dev, algorithm, purpose, map);
+            if (error != KM_ERROR_OK)
+                return error;
+        }
+
+    return KM_ERROR_OK;
+}
+
+SoftKeymasterDevice::SoftKeymasterDevice()
+    : wrapped_km0_device_(nullptr), wrapped_km1_device_(nullptr),
+      context_(new SoftKeymasterContext),
+      impl_(new AndroidKeymaster(context_, kOperationTableSize)) {
+    LOG_I("Creating device", 0);
+    LOG_D("Device address: %p", this);
+
+    initialize_device_struct(KEYMASTER_SOFTWARE_ONLY | KEYMASTER_BLOBS_ARE_STANDALONE |
+                             KEYMASTER_SUPPORTS_EC);
+}
+
+SoftKeymasterDevice::SoftKeymasterDevice(SoftKeymasterContext* context)
+    : wrapped_km0_device_(nullptr), wrapped_km1_device_(nullptr), context_(context),
+      impl_(new AndroidKeymaster(context_, kOperationTableSize)) {
+    LOG_I("Creating test device", 0);
+    LOG_D("Device address: %p", this);
+
+    initialize_device_struct(KEYMASTER_SOFTWARE_ONLY | KEYMASTER_BLOBS_ARE_STANDALONE |
+                             KEYMASTER_SUPPORTS_EC);
+}
+
+keymaster_error_t SoftKeymasterDevice::SetHardwareDevice(keymaster0_device_t* keymaster0_device) {
+    assert(keymaster0_device);
+    LOG_D("Reinitializing SoftKeymasterDevice to use HW keymaster0", 0);
+
+    if (!context_)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    keymaster_error_t error = context_->SetHardwareDevice(keymaster0_device);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    initialize_device_struct(keymaster0_device->flags);
+
+    module_name_ = km1_device_.common.module->name;
+    module_name_.append("(Wrapping ");
+    module_name_.append(keymaster0_device->common.module->name);
+    module_name_.append(")");
+
+    updated_module_ = *km1_device_.common.module;
+    updated_module_.name = module_name_.c_str();
+
+    km1_device_.common.module = &updated_module_;
+
+    wrapped_km0_device_ = keymaster0_device;
+    wrapped_km1_device_ = nullptr;
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t SoftKeymasterDevice::SetHardwareDevice(keymaster1_device_t* keymaster1_device) {
+    assert(keymaster1_device);
+    LOG_D("Reinitializing SoftKeymasterDevice to use HW keymaster1", 0);
+
+    if (!context_)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    keymaster_error_t error = map_digests(keymaster1_device, &km1_device_digests_);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    error = context_->SetHardwareDevice(keymaster1_device);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    initialize_device_struct(keymaster1_device->flags);
+
+    module_name_ = km1_device_.common.module->name;
+    module_name_.append(" (Wrapping ");
+    module_name_.append(keymaster1_device->common.module->name);
+    module_name_.append(")");
+
+    updated_module_ = *km1_device_.common.module;
+    updated_module_.name = module_name_.c_str();
+
+    km1_device_.common.module = &updated_module_;
+
+    wrapped_km0_device_ = nullptr;
+    wrapped_km1_device_ = keymaster1_device;
+    return KM_ERROR_OK;
+}
+
+bool SoftKeymasterDevice::Keymaster1DeviceIsGood() {
+    std::vector<keymaster_digest_t> expected_rsa_digests = {
+        KM_DIGEST_NONE,      KM_DIGEST_MD5,       KM_DIGEST_SHA1,     KM_DIGEST_SHA_2_224,
+        KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512};
+    std::vector<keymaster_digest_t> expected_ec_digests = {
+        KM_DIGEST_NONE,      KM_DIGEST_SHA1,      KM_DIGEST_SHA_2_224,
+        KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512};
+
+    for (auto& entry : km1_device_digests_) {
+        if (entry.first.first == KM_ALGORITHM_RSA)
+            if (!std::is_permutation(entry.second.begin(), entry.second.end(),
+                                     expected_rsa_digests.begin()))
+                return false;
+        if (entry.first.first == KM_ALGORITHM_EC)
+            if (!std::is_permutation(entry.second.begin(), entry.second.end(),
+                                     expected_ec_digests.begin()))
+                return false;
+    }
+    return true;
+}
+
+void SoftKeymasterDevice::initialize_device_struct(uint32_t flags) {
+    memset(&km1_device_, 0, sizeof(km1_device_));
+
+    km1_device_.common.tag = HARDWARE_DEVICE_TAG;
+    km1_device_.common.version = 1;
+    km1_device_.common.module = reinterpret_cast<hw_module_t*>(&soft_keymaster1_device_module);
+    km1_device_.common.close = &close_device;
+
+    km1_device_.flags = flags;
+
+    km1_device_.context = this;
+
+    // keymaster0 APIs
+    km1_device_.generate_keypair = nullptr;
+    km1_device_.import_keypair = nullptr;
+    km1_device_.get_keypair_public = nullptr;
+    km1_device_.delete_keypair = nullptr;
+    km1_device_.delete_all = nullptr;
+    km1_device_.sign_data = nullptr;
+    km1_device_.verify_data = nullptr;
+
+    // keymaster1 APIs
+    km1_device_.get_supported_algorithms = get_supported_algorithms;
+    km1_device_.get_supported_block_modes = get_supported_block_modes;
+    km1_device_.get_supported_padding_modes = get_supported_padding_modes;
+    km1_device_.get_supported_digests = get_supported_digests;
+    km1_device_.get_supported_import_formats = get_supported_import_formats;
+    km1_device_.get_supported_export_formats = get_supported_export_formats;
+    km1_device_.add_rng_entropy = add_rng_entropy;
+    km1_device_.generate_key = generate_key;
+    km1_device_.get_key_characteristics = get_key_characteristics;
+    km1_device_.import_key = import_key;
+    km1_device_.export_key = export_key;
+    km1_device_.delete_key = delete_key;
+    km1_device_.delete_all_keys = delete_all_keys;
+    km1_device_.begin = begin;
+    km1_device_.update = update;
+    km1_device_.finish = finish;
+    km1_device_.abort = abort;
+
+    // keymaster2 APIs
+    memset(&km2_device_, 0, sizeof(km2_device_));
+
+    km2_device_.context = this;
+
+    km2_device_.common.tag = HARDWARE_DEVICE_TAG;
+    km2_device_.common.version = 1;
+    km2_device_.common.module = reinterpret_cast<hw_module_t*>(&soft_keymaster2_device_module);
+    km2_device_.common.close = &close_device;
+
+    km2_device_.add_rng_entropy = add_rng_entropy;
+    km2_device_.generate_key = generate_key;
+    km2_device_.get_key_characteristics = get_key_characteristics;
+    km2_device_.import_key = import_key;
+    km2_device_.export_key = export_key;
+    km2_device_.agree_key = nullptr;  // TODO(swillden) Implement ECDH
+    km2_device_.attest_key = attest_key;
+    km2_device_.upgrade_key = nullptr;  // TODO(swillden) Implement upgrade
+    km2_device_.delete_key = delete_key;
+    km2_device_.delete_all_keys = delete_all_keys;
+    km2_device_.begin = begin;
+    km2_device_.update = update;
+    km2_device_.finish = finish;
+    km2_device_.abort = abort;
+}
+
+hw_device_t* SoftKeymasterDevice::hw_device() {
+    return &km1_device_.common;
+}
+
+keymaster1_device_t* SoftKeymasterDevice::keymaster_device() {
+    return &km1_device_;
+}
+
+keymaster2_device_t* SoftKeymasterDevice::keymaster2_device() {
+    return &km2_device_;
+}
+
+namespace {
+
+keymaster_key_characteristics_t* BuildCharacteristics(const AuthorizationSet& hw_enforced,
+                                                      const AuthorizationSet& sw_enforced) {
+    keymaster_key_characteristics_t* characteristics =
+        reinterpret_cast<keymaster_key_characteristics_t*>(
+            malloc(sizeof(keymaster_key_characteristics_t)));
+    if (characteristics) {
+        hw_enforced.CopyToParamSet(&characteristics->hw_enforced);
+        sw_enforced.CopyToParamSet(&characteristics->sw_enforced);
+    }
+    return characteristics;
+}
+
+template <typename RequestType>
+void AddClientAndAppData(const keymaster_blob_t* client_id, const keymaster_blob_t* app_data,
+                         RequestType* request) {
+    request->additional_params.Clear();
+    if (client_id)
+        request->additional_params.push_back(TAG_APPLICATION_ID, *client_id);
+    if (app_data)
+        request->additional_params.push_back(TAG_APPLICATION_DATA, *app_data);
+}
+
+template <typename T> SoftKeymasterDevice* convert_device(const T* dev) {
+    static_assert((std::is_same<T, keymaster0_device_t>::value ||
+                   std::is_same<T, keymaster1_device_t>::value ||
+                   std::is_same<T, keymaster2_device_t>::value),
+                  "convert_device should only be applied to keymaster devices");
+    return reinterpret_cast<SoftKeymasterDevice*>(dev->context);
+}
+
+bool FindAlgorithm(const keymaster_key_param_set_t& params, keymaster_algorithm_t* algorithm) {
+    for (size_t i = 0; i < params.length; ++i)
+        if (params.params[i].tag == KM_TAG_ALGORITHM) {
+            *algorithm = static_cast<keymaster_algorithm_t>(params.params[i].enumerated);
+            return true;
+        }
+    return false;
+}
+
+keymaster_error_t GetAlgorithm(const keymaster1_device_t* dev, const keymaster_key_blob_t& key,
+                               const AuthorizationSet& in_params,
+                               keymaster_algorithm_t* algorithm) {
+    keymaster_blob_t client_id = {nullptr, 0};
+    keymaster_blob_t app_data = {nullptr, 0};
+    keymaster_blob_t* client_id_ptr = nullptr;
+    keymaster_blob_t* app_data_ptr = nullptr;
+    if (in_params.GetTagValue(TAG_APPLICATION_ID, &client_id))
+        client_id_ptr = &client_id;
+    if (in_params.GetTagValue(TAG_APPLICATION_DATA, &app_data))
+        app_data_ptr = &app_data;
+
+    keymaster_key_characteristics_t* characteristics;
+    keymaster_error_t error =
+        dev->get_key_characteristics(dev, &key, client_id_ptr, app_data_ptr, &characteristics);
+    if (error != KM_ERROR_OK)
+        return error;
+    std::unique_ptr<keymaster_key_characteristics_t, Characteristics_Delete>
+        characteristics_deleter(characteristics);
+
+    if (FindAlgorithm(characteristics->hw_enforced, algorithm))
+        return KM_ERROR_OK;
+
+    if (FindAlgorithm(characteristics->sw_enforced, algorithm))
+        return KM_ERROR_OK;
+
+    return KM_ERROR_INVALID_KEY_BLOB;
+}
+
+}  // unnamed namespaced
+
+/* static */
+int SoftKeymasterDevice::close_device(hw_device_t* dev) {
+    switch (dev->module->module_api_version) {
+    case KEYMASTER_MODULE_API_VERSION_2_0: {
+        delete convert_device(reinterpret_cast<keymaster2_device_t*>(dev));
+        break;
+    }
+
+    case KEYMASTER_MODULE_API_VERSION_1_0: {
+        delete convert_device(reinterpret_cast<keymaster1_device_t*>(dev));
+        break;
+    }
+
+    default:
+        return -1;
+    }
+
+    return 0;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_supported_algorithms(const keymaster1_device_t* dev,
+                                                                keymaster_algorithm_t** algorithms,
+                                                                size_t* algorithms_length) {
+    if (!dev)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!algorithms || !algorithms_length)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
+    if (km1_dev)
+        return km1_dev->get_supported_algorithms(km1_dev, algorithms, algorithms_length);
+
+    SupportedAlgorithmsRequest request;
+    SupportedAlgorithmsResponse response;
+    convert_device(dev)->impl_->SupportedAlgorithms(request, &response);
+    if (response.error != KM_ERROR_OK) {
+        LOG_E("get_supported_algorithms failed with %d", response.error);
+
+        return response.error;
+    }
+
+    *algorithms_length = response.results_length;
+    *algorithms =
+        reinterpret_cast<keymaster_algorithm_t*>(malloc(*algorithms_length * sizeof(**algorithms)));
+    if (!*algorithms)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    std::copy(response.results, response.results + response.results_length, *algorithms);
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_supported_block_modes(const keymaster1_device_t* dev,
+                                                                 keymaster_algorithm_t algorithm,
+                                                                 keymaster_purpose_t purpose,
+                                                                 keymaster_block_mode_t** modes,
+                                                                 size_t* modes_length) {
+    if (!dev)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!modes || !modes_length)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
+    if (km1_dev)
+        return km1_dev->get_supported_block_modes(km1_dev, algorithm, purpose, modes, modes_length);
+
+    SupportedBlockModesRequest request;
+    request.algorithm = algorithm;
+    request.purpose = purpose;
+    SupportedBlockModesResponse response;
+    convert_device(dev)->impl_->SupportedBlockModes(request, &response);
+
+    if (response.error != KM_ERROR_OK) {
+        LOG_E("get_supported_block_modes failed with %d", response.error);
+
+        return response.error;
+    }
+
+    *modes_length = response.results_length;
+    *modes = reinterpret_cast<keymaster_block_mode_t*>(malloc(*modes_length * sizeof(**modes)));
+    if (!*modes)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    std::copy(response.results, response.results + response.results_length, *modes);
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_supported_padding_modes(const keymaster1_device_t* dev,
+                                                                   keymaster_algorithm_t algorithm,
+                                                                   keymaster_purpose_t purpose,
+                                                                   keymaster_padding_t** modes,
+                                                                   size_t* modes_length) {
+    if (!dev)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!modes || !modes_length)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
+    if (km1_dev)
+        return km1_dev->get_supported_padding_modes(km1_dev, algorithm, purpose, modes,
+                                                    modes_length);
+
+    SupportedPaddingModesRequest request;
+    request.algorithm = algorithm;
+    request.purpose = purpose;
+    SupportedPaddingModesResponse response;
+    convert_device(dev)->impl_->SupportedPaddingModes(request, &response);
+
+    if (response.error != KM_ERROR_OK) {
+        LOG_E("get_supported_padding_modes failed with %d", response.error);
+        return response.error;
+    }
+
+    *modes_length = response.results_length;
+    *modes = reinterpret_cast<keymaster_padding_t*>(malloc(*modes_length * sizeof(**modes)));
+    if (!*modes)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    std::copy(response.results, response.results + response.results_length, *modes);
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_supported_digests(const keymaster1_device_t* dev,
+                                                             keymaster_algorithm_t algorithm,
+                                                             keymaster_purpose_t purpose,
+                                                             keymaster_digest_t** digests,
+                                                             size_t* digests_length) {
+    if (!dev)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!digests || !digests_length)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
+    if (km1_dev)
+        return km1_dev->get_supported_digests(km1_dev, algorithm, purpose, digests, digests_length);
+
+    SupportedDigestsRequest request;
+    request.algorithm = algorithm;
+    request.purpose = purpose;
+    SupportedDigestsResponse response;
+    convert_device(dev)->impl_->SupportedDigests(request, &response);
+
+    if (response.error != KM_ERROR_OK) {
+        LOG_E("get_supported_digests failed with %d", response.error);
+        return response.error;
+    }
+
+    *digests_length = response.results_length;
+    *digests = reinterpret_cast<keymaster_digest_t*>(malloc(*digests_length * sizeof(**digests)));
+    if (!*digests)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    std::copy(response.results, response.results + response.results_length, *digests);
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_supported_import_formats(
+    const keymaster1_device_t* dev, keymaster_algorithm_t algorithm,
+    keymaster_key_format_t** formats, size_t* formats_length) {
+    if (!dev)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!formats || !formats_length)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
+    if (km1_dev)
+        return km1_dev->get_supported_import_formats(km1_dev, algorithm, formats, formats_length);
+
+    SupportedImportFormatsRequest request;
+    request.algorithm = algorithm;
+    SupportedImportFormatsResponse response;
+    convert_device(dev)->impl_->SupportedImportFormats(request, &response);
+
+    if (response.error != KM_ERROR_OK) {
+        LOG_E("get_supported_import_formats failed with %d", response.error);
+        return response.error;
+    }
+
+    *formats_length = response.results_length;
+    *formats =
+        reinterpret_cast<keymaster_key_format_t*>(malloc(*formats_length * sizeof(**formats)));
+    if (!*formats)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    std::copy(response.results, response.results + response.results_length, *formats);
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_supported_export_formats(
+    const keymaster1_device_t* dev, keymaster_algorithm_t algorithm,
+    keymaster_key_format_t** formats, size_t* formats_length) {
+    if (!dev)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!formats || !formats_length)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
+    if (km1_dev)
+        return km1_dev->get_supported_export_formats(km1_dev, algorithm, formats, formats_length);
+
+    SupportedExportFormatsRequest request;
+    request.algorithm = algorithm;
+    SupportedExportFormatsResponse response;
+    convert_device(dev)->impl_->SupportedExportFormats(request, &response);
+
+    if (response.error != KM_ERROR_OK) {
+        LOG_E("get_supported_export_formats failed with %d", response.error);
+        return response.error;
+    }
+
+    *formats_length = response.results_length;
+    *formats =
+        reinterpret_cast<keymaster_key_format_t*>(malloc(*formats_length * sizeof(**formats)));
+    if (!*formats)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    std::copy(response.results, response.results + *formats_length, *formats);
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::add_rng_entropy(const keymaster1_device_t* dev,
+                                                       const uint8_t* data, size_t data_length) {
+    if (!dev)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
+    if (km1_dev)
+        return km1_dev->add_rng_entropy(km1_dev, data, data_length);
+
+    AddEntropyRequest request;
+    request.random_data.Reinitialize(data, data_length);
+    AddEntropyResponse response;
+    convert_device(dev)->impl_->AddRngEntropy(request, &response);
+    if (response.error != KM_ERROR_OK)
+        LOG_E("add_rng_entropy failed with %d", response.error);
+    return response.error;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::add_rng_entropy(const keymaster2_device_t* dev,
+                                                       const uint8_t* data, size_t data_length) {
+    if (!dev)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    SoftKeymasterDevice* sk_dev = convert_device(dev);
+    return add_rng_entropy(&sk_dev->km1_device_, data, data_length);
+}
+
+template <typename Collection, typename Value> bool contains(const Collection& c, const Value& v) {
+    return std::find(c.begin(), c.end(), v) != c.end();
+}
+
+bool SoftKeymasterDevice::FindUnsupportedDigest(keymaster_algorithm_t algorithm,
+                                                keymaster_purpose_t purpose,
+                                                const AuthorizationSet& params,
+                                                keymaster_digest_t* unsupported) const {
+    assert(wrapped_km1_device_);
+
+    auto supported_digests = km1_device_digests_.find(std::make_pair(algorithm, purpose));
+    if (supported_digests == km1_device_digests_.end())
+        // Invalid algorith/purpose pair (e.g. EC encrypt).  Let the error be handled by HW module.
+        return false;
+
+    for (auto& entry : params)
+        if (entry.tag == TAG_DIGEST)
+            if (!contains(supported_digests->second, entry.enumerated)) {
+                LOG_I("Digest %d requested but not supported by module %s", entry.enumerated,
+                      wrapped_km1_device_->common.module->name);
+                *unsupported = static_cast<keymaster_digest_t>(entry.enumerated);
+                return true;
+            }
+    return false;
+}
+
+bool SoftKeymasterDevice::RequiresSoftwareDigesting(keymaster_algorithm_t algorithm,
+                                                    keymaster_purpose_t purpose,
+                                                    const AuthorizationSet& params) const {
+    assert(wrapped_km1_device_);
+    if (!wrapped_km1_device_)
+        return true;
+
+    switch (algorithm) {
+    case KM_ALGORITHM_AES:
+    case KM_ALGORITHM_HMAC:
+        LOG_D("Not performing software digesting for algorithm %d", algorithm);
+        return false;
+    case KM_ALGORITHM_RSA:
+    case KM_ALGORITHM_EC:
+        break;
+    }
+
+    keymaster_digest_t unsupported;
+    if (!FindUnsupportedDigest(algorithm, purpose, params, &unsupported)) {
+        LOG_D("Requested digest(s) supported for algorithm %d and purpose %d", algorithm, purpose);
+        return false;
+    }
+
+    return true;
+}
+
+bool SoftKeymasterDevice::KeyRequiresSoftwareDigesting(
+    const AuthorizationSet& key_description) const {
+    assert(wrapped_km1_device_);
+    if (!wrapped_km1_device_)
+        return true;
+
+    keymaster_algorithm_t algorithm;
+    if (!key_description.GetTagValue(TAG_ALGORITHM, &algorithm)) {
+        // The hardware module will return an error during keygen.
+        return false;
+    }
+
+    for (auto& entry : key_description)
+        if (entry.tag == TAG_PURPOSE) {
+            keymaster_purpose_t purpose = static_cast<keymaster_purpose_t>(entry.enumerated);
+            if (RequiresSoftwareDigesting(algorithm, purpose, key_description))
+                return true;
+        }
+
+    return false;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::generate_key(
+    const keymaster1_device_t* dev, const keymaster_key_param_set_t* params,
+    keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t** characteristics) {
+    if (!dev || !params)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!key_blob)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    SoftKeymasterDevice* sk_dev = convert_device(dev);
+
+    GenerateKeyRequest request;
+    request.key_description.Reinitialize(*params);
+
+    keymaster1_device_t* km1_dev = sk_dev->wrapped_km1_device_;
+    if (km1_dev && !sk_dev->KeyRequiresSoftwareDigesting(request.key_description))
+        return km1_dev->generate_key(km1_dev, params, key_blob, characteristics);
+
+    GenerateKeyResponse response;
+    sk_dev->impl_->GenerateKey(request, &response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    key_blob->key_material_size = response.key_blob.key_material_size;
+    uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(key_blob->key_material_size));
+    if (!tmp)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    memcpy(tmp, response.key_blob.key_material, response.key_blob.key_material_size);
+    key_blob->key_material = tmp;
+
+    if (characteristics) {
+        *characteristics = BuildCharacteristics(response.enforced, response.unenforced);
+        if (!*characteristics)
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t
+SoftKeymasterDevice::generate_key(const keymaster2_device_t* dev,  //
+                                  const keymaster_key_param_set_t* params,
+                                  keymaster_key_blob_t* key_blob,
+                                  keymaster_key_characteristics_t* characteristics) {
+    if (!dev)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!key_blob)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    SoftKeymasterDevice* sk_dev = convert_device(dev);
+
+    GenerateKeyRequest request;
+    request.key_description.Reinitialize(*params);
+
+    keymaster1_device_t* km1_dev = sk_dev->wrapped_km1_device_;
+    if (km1_dev && !sk_dev->KeyRequiresSoftwareDigesting(request.key_description)) {
+        keymaster_key_characteristics_t* chars_ptr;
+        keymaster_error_t error = km1_dev->generate_key(km1_dev, params, key_blob,
+                                                        characteristics ? &chars_ptr : nullptr);
+        if (error != KM_ERROR_OK)
+            return error;
+
+        if (characteristics) {
+            *characteristics = *chars_ptr;
+            free(chars_ptr);
+        }
+        return KM_ERROR_OK;
+    }
+
+    GenerateKeyResponse response;
+    sk_dev->impl_->GenerateKey(request, &response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    key_blob->key_material_size = response.key_blob.key_material_size;
+    uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(key_blob->key_material_size));
+    if (!tmp)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    memcpy(tmp, response.key_blob.key_material, response.key_blob.key_material_size);
+    key_blob->key_material = tmp;
+
+    if (characteristics) {
+        response.enforced.CopyToParamSet(&characteristics->hw_enforced);
+        response.unenforced.CopyToParamSet(&characteristics->sw_enforced);
+    }
+
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_key_characteristics(
+    const keymaster1_device_t* dev, const keymaster_key_blob_t* key_blob,
+    const keymaster_blob_t* client_id, const keymaster_blob_t* app_data,
+    keymaster_key_characteristics_t** characteristics) {
+    if (!dev || !key_blob || !key_blob->key_material)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!characteristics)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
+    if (km1_dev)
+        return km1_dev->get_key_characteristics(km1_dev, key_blob, client_id, app_data,
+                                                characteristics);
+
+    GetKeyCharacteristicsRequest request;
+    request.SetKeyMaterial(*key_blob);
+    AddClientAndAppData(client_id, app_data, &request);
+
+    GetKeyCharacteristicsResponse response;
+    convert_device(dev)->impl_->GetKeyCharacteristics(request, &response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    *characteristics = BuildCharacteristics(response.enforced, response.unenforced);
+    if (!*characteristics)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_key_characteristics(
+    const keymaster2_device_t* dev, const keymaster_key_blob_t* key_blob,
+    const keymaster_blob_t* client_id, const keymaster_blob_t* app_data,
+    keymaster_key_characteristics_t* characteristics) {
+    if (!dev)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!characteristics)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    SoftKeymasterDevice* sk_dev = convert_device(dev);
+
+    keymaster_error_t error;
+    keymaster_key_characteristics_t* key_characteristics;
+    error = get_key_characteristics(&sk_dev->km1_device_, key_blob, client_id, app_data,
+                                    &key_characteristics);
+    if (error != KM_ERROR_OK)
+        return error;
+    *characteristics = *key_characteristics;
+    free(key_characteristics);
+
+    return error;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::import_key(
+    const keymaster1_device_t* dev, const keymaster_key_param_set_t* params,
+    keymaster_key_format_t key_format, const keymaster_blob_t* key_data,
+    keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t** characteristics) {
+    if (!params || !key_data)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!key_blob)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    SoftKeymasterDevice* sk_dev = convert_device(dev);
+
+    ImportKeyRequest request;
+    request.key_description.Reinitialize(*params);
+
+    keymaster1_device_t* km1_dev = sk_dev->wrapped_km1_device_;
+    if (km1_dev && !sk_dev->KeyRequiresSoftwareDigesting(request.key_description))
+        return km1_dev->import_key(km1_dev, params, key_format, key_data, key_blob,
+                                   characteristics);
+
+    *characteristics = nullptr;
+
+    request.key_format = key_format;
+    request.SetKeyMaterial(key_data->data, key_data->data_length);
+
+    ImportKeyResponse response;
+    convert_device(dev)->impl_->ImportKey(request, &response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    key_blob->key_material_size = response.key_blob.key_material_size;
+    key_blob->key_material = reinterpret_cast<uint8_t*>(malloc(key_blob->key_material_size));
+    if (!key_blob->key_material)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    memcpy(const_cast<uint8_t*>(key_blob->key_material), response.key_blob.key_material,
+           response.key_blob.key_material_size);
+
+    if (characteristics) {
+        *characteristics = BuildCharacteristics(response.enforced, response.unenforced);
+        if (!*characteristics)
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::import_key(
+    const keymaster2_device_t* dev, const keymaster_key_param_set_t* params,
+    keymaster_key_format_t key_format, const keymaster_blob_t* key_data,
+    keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics) {
+    if (!dev)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    SoftKeymasterDevice* sk_dev = convert_device(dev);
+
+    keymaster_error_t error;
+    if (characteristics) {
+        keymaster_key_characteristics_t* characteristics_ptr;
+        error = import_key(&sk_dev->km1_device_, params, key_format, key_data, key_blob,
+                           &characteristics_ptr);
+        if (error == KM_ERROR_OK) {
+            *characteristics = *characteristics_ptr;
+            free(characteristics_ptr);
+        }
+    } else {
+        error = import_key(&sk_dev->km1_device_, params, key_format, key_data, key_blob, nullptr);
+    }
+
+    return error;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::export_key(const keymaster1_device_t* dev,
+                                                  keymaster_key_format_t export_format,
+                                                  const keymaster_key_blob_t* key_to_export,
+                                                  const keymaster_blob_t* client_id,
+                                                  const keymaster_blob_t* app_data,
+                                                  keymaster_blob_t* export_data) {
+    if (!key_to_export || !key_to_export->key_material)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!export_data)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
+    if (km1_dev)
+        return km1_dev->export_key(km1_dev, export_format, key_to_export, client_id, app_data,
+                                   export_data);
+
+    export_data->data = nullptr;
+    export_data->data_length = 0;
+
+    ExportKeyRequest request;
+    request.key_format = export_format;
+    request.SetKeyMaterial(*key_to_export);
+    AddClientAndAppData(client_id, app_data, &request);
+
+    ExportKeyResponse response;
+    convert_device(dev)->impl_->ExportKey(request, &response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    export_data->data_length = response.key_data_length;
+    uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(export_data->data_length));
+    if (!tmp)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    memcpy(tmp, response.key_data, export_data->data_length);
+    export_data->data = tmp;
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::export_key(const keymaster2_device_t* dev,
+                                                  keymaster_key_format_t export_format,
+                                                  const keymaster_key_blob_t* key_to_export,
+                                                  const keymaster_blob_t* client_id,
+                                                  const keymaster_blob_t* app_data,
+                                                  keymaster_blob_t* export_data) {
+    if (!dev)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    SoftKeymasterDevice* sk_dev = convert_device(dev);
+    return export_key(&sk_dev->km1_device_, export_format, key_to_export, client_id, app_data,
+                      export_data);
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::attest_key(const keymaster2_device_t* dev,
+                                                  const keymaster_key_blob_t* key_to_attest,
+                                                  const keymaster_key_param_set_t* attest_params,
+                                                  keymaster_cert_chain_t* cert_chain) {
+    if (!dev || !key_to_attest || !attest_params || !cert_chain)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    cert_chain->entry_count = 0;
+    cert_chain->entries = nullptr;
+
+    AttestKeyRequest request;
+    request.SetKeyMaterial(*key_to_attest);
+    request.attest_params.Reinitialize(*attest_params);
+
+    AttestKeyResponse response;
+    convert_device(dev)->impl_->AttestKey(request, &response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    // Allocate and clear storage for cert_chain.
+    keymaster_cert_chain_t& rsp_chain = response.certificate_chain;
+    cert_chain->entries = reinterpret_cast<keymaster_blob_t*>(
+        malloc(rsp_chain.entry_count * sizeof(*cert_chain->entries)));
+    if (!cert_chain->entries)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    cert_chain->entry_count = rsp_chain.entry_count;
+    for (keymaster_blob_t& entry : array_range(cert_chain->entries, cert_chain->entry_count))
+        entry = {};
+
+    // Copy cert_chain contents
+    size_t i = 0;
+    for (keymaster_blob_t& entry : array_range(rsp_chain.entries, rsp_chain.entry_count)) {
+        cert_chain->entries[i].data = reinterpret_cast<uint8_t*>(malloc(entry.data_length));
+        if (!cert_chain->entries[i].data) {
+            keymaster_free_cert_chain(cert_chain);
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        }
+        cert_chain->entries[i].data_length = entry.data_length;
+        memcpy(const_cast<uint8_t*>(cert_chain->entries[i].data), entry.data, entry.data_length);
+        ++i;
+    }
+
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::delete_key(const keymaster1_device_t* dev,
+                                                  const keymaster_key_blob_t* key) {
+    if (!dev || !key || !key->key_material)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    KeymasterKeyBlob blob(*key);
+    return convert_device(dev)->context_->DeleteKey(blob);
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::delete_key(const keymaster2_device_t* dev,
+                                                  const keymaster_key_blob_t* key) {
+    if (!dev || !key || !key->key_material)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    KeymasterKeyBlob blob(*key);
+    return convert_device(dev)->context_->DeleteKey(blob);
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::delete_all_keys(const keymaster1_device_t* dev) {
+    if (!dev)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    return convert_device(dev)->context_->DeleteAllKeys();
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::delete_all_keys(const keymaster2_device_t* dev) {
+    if (!dev)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    return convert_device(dev)->context_->DeleteAllKeys();
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::begin(const keymaster1_device_t* dev,
+                                             keymaster_purpose_t purpose,
+                                             const keymaster_key_blob_t* key,
+                                             const keymaster_key_param_set_t* in_params,
+                                             keymaster_key_param_set_t* out_params,
+                                             keymaster_operation_handle_t* operation_handle) {
+    if (!key || !key->key_material)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!operation_handle)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
+    if (km1_dev) {
+        AuthorizationSet in_params_set(*in_params);
+
+        keymaster_algorithm_t algorithm = KM_ALGORITHM_AES;
+        keymaster_error_t error = GetAlgorithm(km1_dev, *key, in_params_set, &algorithm);
+        if (error != KM_ERROR_OK)
+            return error;
+
+        if (!convert_device(dev)->RequiresSoftwareDigesting(algorithm, purpose, in_params_set)) {
+            LOG_D("Operation supported by %s, passing through to keymaster1 module",
+                  km1_dev->common.module->name);
+            return km1_dev->begin(km1_dev, purpose, key, in_params, out_params, operation_handle);
+        }
+        LOG_I("Doing software digesting for keymaster1 module %s", km1_dev->common.module->name);
+    }
+
+    if (out_params) {
+        out_params->params = nullptr;
+        out_params->length = 0;
+    }
+
+    BeginOperationRequest request;
+    request.purpose = purpose;
+    request.SetKeyMaterial(*key);
+    request.additional_params.Reinitialize(*in_params);
+
+    BeginOperationResponse response;
+    convert_device(dev)->impl_->BeginOperation(request, &response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    if (response.output_params.size() > 0) {
+        if (out_params)
+            response.output_params.CopyToParamSet(out_params);
+        else
+            return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    }
+
+    *operation_handle = response.op_handle;
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::begin(const keymaster2_device_t* dev,
+                                             keymaster_purpose_t purpose,
+                                             const keymaster_key_blob_t* key,
+                                             const keymaster_key_param_set_t* in_params,
+                                             keymaster_key_param_set_t* out_params,
+                                             keymaster_operation_handle_t* operation_handle) {
+    if (!dev)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    SoftKeymasterDevice* sk_dev = convert_device(dev);
+    return begin(&sk_dev->km1_device_, purpose, key, in_params, out_params, operation_handle);
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::update(const keymaster1_device_t* dev,
+                                              keymaster_operation_handle_t operation_handle,
+                                              const keymaster_key_param_set_t* in_params,
+                                              const keymaster_blob_t* input, size_t* input_consumed,
+                                              keymaster_key_param_set_t* out_params,
+                                              keymaster_blob_t* output) {
+    if (!input)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!input_consumed)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
+    if (km1_dev && !convert_device(dev)->impl_->has_operation(operation_handle)) {
+        // This operation is being handled by km1_dev (or doesn't exist).  Pass it through to
+        // km1_dev.  Otherwise, we'll use the software AndroidKeymaster, which may delegate to
+        // km1_dev after doing necessary digesting.
+        return km1_dev->update(km1_dev, operation_handle, in_params, input, input_consumed,
+                               out_params, output);
+    }
+
+    if (out_params) {
+        out_params->params = nullptr;
+        out_params->length = 0;
+    }
+    if (output) {
+        output->data = nullptr;
+        output->data_length = 0;
+    }
+
+    UpdateOperationRequest request;
+    request.op_handle = operation_handle;
+    if (input)
+        request.input.Reinitialize(input->data, input->data_length);
+    if (in_params)
+        request.additional_params.Reinitialize(*in_params);
+
+    UpdateOperationResponse response;
+    convert_device(dev)->impl_->UpdateOperation(request, &response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    if (response.output_params.size() > 0) {
+        if (out_params)
+            response.output_params.CopyToParamSet(out_params);
+        else
+            return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    }
+
+    *input_consumed = response.input_consumed;
+    if (output) {
+        output->data_length = response.output.available_read();
+        uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(output->data_length));
+        if (!tmp)
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        memcpy(tmp, response.output.peek_read(), output->data_length);
+        output->data = tmp;
+    } else if (response.output.available_read() > 0) {
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    }
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::update(const keymaster2_device_t* dev,
+                                              keymaster_operation_handle_t operation_handle,
+                                              const keymaster_key_param_set_t* in_params,
+                                              const keymaster_blob_t* input, size_t* input_consumed,
+                                              keymaster_key_param_set_t* out_params,
+                                              keymaster_blob_t* output) {
+    if (!dev)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    SoftKeymasterDevice* sk_dev = convert_device(dev);
+    return update(&sk_dev->km1_device_, operation_handle, in_params, input, input_consumed,
+                  out_params, output);
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::finish(const keymaster1_device_t* dev,
+                                              keymaster_operation_handle_t operation_handle,
+                                              const keymaster_key_param_set_t* params,
+                                              const keymaster_blob_t* signature,
+                                              keymaster_key_param_set_t* out_params,
+                                              keymaster_blob_t* output) {
+    const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
+    if (km1_dev && !convert_device(dev)->impl_->has_operation(operation_handle)) {
+        // This operation is being handled by km1_dev (or doesn't exist).  Pass it through to
+        // km1_dev.  Otherwise, we'll use the software AndroidKeymaster, which may delegate to
+        // km1_dev after doing necessary digesting.
+        return km1_dev->finish(km1_dev, operation_handle, params, signature, out_params, output);
+    }
+
+    if (out_params) {
+        out_params->params = nullptr;
+        out_params->length = 0;
+    }
+
+    if (output) {
+        output->data = nullptr;
+        output->data_length = 0;
+    }
+
+    FinishOperationRequest request;
+    request.op_handle = operation_handle;
+    if (signature && signature->data_length > 0)
+        request.signature.Reinitialize(signature->data, signature->data_length);
+    request.additional_params.Reinitialize(*params);
+
+    FinishOperationResponse response;
+    convert_device(dev)->impl_->FinishOperation(request, &response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    if (response.output_params.size() > 0) {
+        if (out_params)
+            response.output_params.CopyToParamSet(out_params);
+        else
+            return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    }
+    if (output) {
+        output->data_length = response.output.available_read();
+        uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(output->data_length));
+        if (!tmp)
+            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        memcpy(tmp, response.output.peek_read(), output->data_length);
+        output->data = tmp;
+    } else if (response.output.available_read() > 0) {
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    }
+
+    return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::finish(const keymaster2_device_t* dev,
+                                              keymaster_operation_handle_t operation_handle,
+                                              const keymaster_key_param_set_t* params,
+                                              const keymaster_blob_t* input,
+                                              const keymaster_blob_t* signature,
+                                              keymaster_key_param_set_t* out_params,
+                                              keymaster_blob_t* output) {
+    if (!dev)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (input && input->data)
+        return KM_ERROR_UNIMPLEMENTED;  // TODO(swillden): Implement this
+
+    SoftKeymasterDevice* sk_dev = convert_device(dev);
+    return finish(&sk_dev->km1_device_, operation_handle, params, signature, out_params, output);
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::abort(const keymaster1_device_t* dev,
+                                             keymaster_operation_handle_t operation_handle) {
+    const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
+    if (km1_dev && !convert_device(dev)->impl_->has_operation(operation_handle)) {
+        // This operation is being handled by km1_dev (or doesn't exist).  Pass it through to
+        // km1_dev.  Otherwise, we'll use the software AndroidKeymaster, which may delegate to
+        // km1_dev.
+        return km1_dev->abort(km1_dev, operation_handle);
+    }
+
+    AbortOperationRequest request;
+    request.op_handle = operation_handle;
+    AbortOperationResponse response;
+    convert_device(dev)->impl_->AbortOperation(request, &response);
+    return response.error;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::abort(const keymaster2_device_t* dev,
+                                             keymaster_operation_handle_t operation_handle) {
+    if (!dev)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    SoftKeymasterDevice* sk_dev = convert_device(dev);
+    return abort(&sk_dev->km1_device_, operation_handle);
+}
+
+/* static */
+void SoftKeymasterDevice::StoreDefaultNewKeyParams(keymaster_algorithm_t algorithm,
+                                                   AuthorizationSet* auth_set) {
+    auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_SIGN);
+    auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_VERIFY);
+    auth_set->push_back(TAG_ALL_USERS);
+    auth_set->push_back(TAG_NO_AUTH_REQUIRED);
+
+    // All digests.
+    auth_set->push_back(TAG_DIGEST, KM_DIGEST_NONE);
+    auth_set->push_back(TAG_DIGEST, KM_DIGEST_MD5);
+    auth_set->push_back(TAG_DIGEST, KM_DIGEST_SHA1);
+    auth_set->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_224);
+    auth_set->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+    auth_set->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_384);
+    auth_set->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_512);
+
+    if (algorithm == KM_ALGORITHM_RSA) {
+        auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_ENCRYPT);
+        auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_DECRYPT);
+        auth_set->push_back(TAG_PADDING, KM_PAD_NONE);
+        auth_set->push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN);
+        auth_set->push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+        auth_set->push_back(TAG_PADDING, KM_PAD_RSA_PSS);
+        auth_set->push_back(TAG_PADDING, KM_PAD_RSA_OAEP);
+    }
+}
+
+}  // namespace keymaster
diff --git a/keymaster/soft_keymaster_logger.cpp b/keymaster/soft_keymaster_logger.cpp
new file mode 100644
index 0000000..3c55a64
--- /dev/null
+++ b/keymaster/soft_keymaster_logger.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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_logger.h>
+
+#include <stdarg.h>
+#include <syslog.h>
+
+#define LOG_TAG "SoftKeymaster"
+#include <cutils/log.h>
+
+namespace keymaster {
+
+int SoftKeymasterLogger::log_msg(LogLevel level, const char* fmt, va_list args) const {
+
+    int android_log_level = ANDROID_LOG_ERROR;
+    switch (level) {
+    case DEBUG_LVL:
+        android_log_level = ANDROID_LOG_DEBUG;
+        break;
+    case INFO_LVL:
+        android_log_level = ANDROID_LOG_INFO;
+        break;
+    case WARNING_LVL:
+        android_log_level = ANDROID_LOG_WARN;
+        break;
+    case ERROR_LVL:
+        android_log_level = ANDROID_LOG_ERROR;
+        break;
+    case SEVERE_LVL:
+        android_log_level = ANDROID_LOG_ERROR;
+        break;
+    }
+
+    return LOG_PRI_VA(android_log_level, LOG_TAG, fmt, args);
+}
+
+}  // namespace keymaster
diff --git a/keymaster/sw_rsa_attest_root.key.pem b/keymaster/sw_rsa_attest_root.key.pem
new file mode 100644
index 0000000..387a852
--- /dev/null
+++ b/keymaster/sw_rsa_attest_root.key.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQCia63rbi5EYe/VDoLmt5TRdSMfd5tjkWP/96r/C3JHTsAsQ+wz
+fNes7UA+jCigZtX3hwszl94OuE4TQKuvpSe/lWmgMdsGUmX4RFlXYfC78hdLt0GA
+ZMAoDo9Sd47b0ke2RekZyOmLw9vCkT/X11DEHTVm+Vfkl5YLCazOkjWFmwIDAQAB
+AoGAU8dxXchmqzVNbbvff7zgUa63YErk51Yem/EXzhkMaIXRkMO0edaCtZtnkRvg
+9OQ2qEiLWaCTlUoyU7H/HUn2lwTQsOXyZI7dHijVDRMIv1mmrHCrGW/JC8FXfPLS
+r3L3KoHXQVYL2mslbR8Rpogxq4WwnwK6XqSTH9mynFwQwEkCQQDMX3EZk3ricWVH
+ruXD0BpXOMMpZuLu4rg5+1L51WEJvItIMeSjLuNa+g3AI8AYTYYi/aSLk6XEv82L
+iXFGmJ2XAkEAy3M8k8Z0QzHae4olduqoHVWEarBtDE+fqFQBWgdm8fZhdHWrvlAc
+qwJIXMUVc+dWm/FAQarCjbqWqhCRdaYgnQJBAJ7z7GdUCVNtlrQ2F4ZAqPwFreTZ
+nM7njxmpm1Os3hhQiJPSGl3A7huoOGGkbJd6VEWKuRvF7jwkYZ2RfITH1mkCQAvh
+X9E1Toa5+4spRwTJsSV9X+0m/kcwwx7+QNH0CrPockptsKi9Xt8xk+4u6BDLmogi
+r2DmStQh6DhoHUZkfBUCQQCOgBkqH/15drpdR+BQH3VaP4/ALFfxR9E3G+lS+M5a
+IqJEk9kh8vjuGzTaAZyU5keUmpWNc1gI7OvDMaH4+8vQ
+-----END RSA PRIVATE KEY-----
diff --git a/keymaster/symmetric_key.cpp b/keymaster/symmetric_key.cpp
new file mode 100644
index 0000000..1d51e3a
--- /dev/null
+++ b/keymaster/symmetric_key.cpp
@@ -0,0 +1,141 @@
+/*
+ * 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 "symmetric_key.h"
+
+#include <assert.h>
+
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/logger.h>
+#include <keymaster/keymaster_context.h>
+
+#include "aes_key.h"
+#include "hmac_key.h"
+#include "openssl_err.h"
+
+namespace keymaster {
+
+keymaster_error_t SymmetricKeyFactory::GenerateKey(const AuthorizationSet& key_description,
+                                                   KeymasterKeyBlob* key_blob,
+                                                   AuthorizationSet* hw_enforced,
+                                                   AuthorizationSet* sw_enforced) const {
+    if (!key_blob || !hw_enforced || !sw_enforced)
+        return KM_ERROR_OUTPUT_PARAMETER_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;
+
+    keymaster_error_t error = validate_algorithm_specific_new_key_params(key_description);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    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;
+
+    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;
+    }
+
+    return context_->CreateKeyBlob(key_description, KM_ORIGIN_GENERATED, key_material, key_blob,
+                                   hw_enforced, sw_enforced);
+}
+
+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) const {
+    if (!output_key_blob || !hw_enforced || !sw_enforced)
+        return KM_ERROR_OUTPUT_PARAMETER_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);
+    }
+
+    keymaster_error_t error = validate_algorithm_specific_new_key_params(key_description);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    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;
+    }
+
+    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};
+const keymaster_key_format_t*
+SymmetricKeyFactory::SupportedImportFormats(size_t* format_count) const {
+    *format_count = array_length(supported_import_formats);
+    return supported_import_formats;
+}
+
+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;
+
+    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() {
+    memset_s(key_data_.get(), 0, key_data_size_);
+}
+
+keymaster_error_t SymmetricKey::key_material(UniquePtr<uint8_t[]>* key_material,
+                                             size_t* size) const {
+    *size = key_data_size_;
+    key_material->reset(new (std::nothrow) uint8_t[*size]);
+    if (!key_material->get())
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    memcpy(key_material->get(), key_data_.get(), *size);
+    return KM_ERROR_OK;
+}
+
+}  // namespace keymaster
diff --git a/keymaster/symmetric_key.h b/keymaster/symmetric_key.h
new file mode 100644
index 0000000..979df62
--- /dev/null
+++ b/keymaster/symmetric_key.h
@@ -0,0 +1,81 @@
+/*
+ * 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_SYMMETRIC_KEY_H_
+#define SYSTEM_KEYMASTER_SYMMETRIC_KEY_H_
+
+#include <keymaster/key_factory.h>
+
+#include "key.h"
+
+namespace keymaster {
+
+class SymmetricKey;
+
+class SymmetricKeyFactory : public KeyFactory {
+  public:
+    explicit SymmetricKeyFactory(const KeymasterContext* context) : KeyFactory(context) {}
+
+    keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+                                  KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
+                                  AuthorizationSet* sw_enforced) const 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) const override;
+
+    virtual const keymaster_key_format_t* SupportedImportFormats(size_t* format_count) const;
+    virtual const keymaster_key_format_t* SupportedExportFormats(size_t* format_count) const {
+        return NoFormats(format_count);
+    };
+
+  private:
+    virtual bool key_size_supported(size_t key_size_bits) const = 0;
+    virtual keymaster_error_t
+    validate_algorithm_specific_new_key_params(const AuthorizationSet& key_description) const = 0;
+
+    const keymaster_key_format_t* NoFormats(size_t* format_count) const {
+        *format_count = 0;
+        return NULL;
+    }
+};
+
+class SymmetricKey : public Key {
+  public:
+    ~SymmetricKey();
+
+    virtual keymaster_error_t key_material(UniquePtr<uint8_t[]>* key_material, size_t* size) const;
+    virtual keymaster_error_t formatted_key_material(keymaster_key_format_t, UniquePtr<uint8_t[]>*,
+                                                     size_t*) const {
+        return KM_ERROR_UNSUPPORTED_KEY_FORMAT;
+    }
+
+    const uint8_t* key_data() const { return key_data_.get(); }
+    size_t key_data_size() const { return key_data_size_; }
+
+  protected:
+    SymmetricKey(const KeymasterKeyBlob& key_material, const AuthorizationSet& hw_enforced,
+                 const AuthorizationSet& sw_enforced, keymaster_error_t* error);
+
+  private:
+    size_t key_data_size_;
+    UniquePtr<uint8_t[]> key_data_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_AES_KEY_H_
diff --git a/keymaster/valgrind.supp b/keymaster/valgrind.supp
new file mode 100644
index 0000000..2838278
--- /dev/null
+++ b/keymaster/valgrind.supp
@@ -0,0 +1,40 @@
+{
+   BoringSSLErrorLeak
+   Memcheck:Leak
+   fun:malloc
+   ...
+   fun:err_get_state
+   ...
+}
+{
+   EcKeyErrorLeak
+   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
+   ...
+}
+{
+   BoringSSLGetNewIndexLeak1
+   Memcheck:Leak
+   match-leak-kinds: reachable
+   fun:malloc
+   ...
+   fun:CRYPTO_get_ex_new_index
+   ...
+}
+{
+   BoringSSLGetNewIndexLeak2
+   Memcheck:Leak
+   match-leak-kinds: reachable
+   fun:realloc
+   ...
+   fun:CRYPTO_get_ex_new_index
+   ...
+}
\ No newline at end of file