summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Willden <swillden@google.com>2014-09-17 13:04:10 -0600
committerShawn Willden <swillden@google.com>2014-09-23 07:54:57 -0600
commit72014adef83b0346859dbe82d77b09b4756d8e64 (patch)
tree0b2abe1d57d52773ddae43db080c799f999f3082
parent7c0a82b7528c51299bf8dda6beb5e1fc8bf54b23 (diff)
downloadandroid_system_keymaster-72014adef83b0346859dbe82d77b09b4756d8e64.tar.gz
android_system_keymaster-72014adef83b0346859dbe82d77b09b4756d8e64.tar.bz2
android_system_keymaster-72014adef83b0346859dbe82d77b09b4756d8e64.zip
Refactor KeyBlob to separate encryption functionality.
This CL is in preparation for another which will refactor libkeymaster into libkeymaster and libkeymasterclient, the latter for use by programs which merely interface with keymaster and don't do any crypto on their own, but do need to parse key blobs to extract authorization list entries. To make that possible it moves KeyBlob's key encryption and decryption capabilities into a subclass, PlaintextKeyBlob. Change-Id: Ic6a65b6f237c122796ea70458655111316f902d8
-rw-r--r--Makefile5
-rw-r--r--asymmetric_key.cpp12
-rw-r--r--asymmetric_key.h11
-rw-r--r--google_keymaster.cpp21
-rw-r--r--include/keymaster/google_keymaster.h7
-rw-r--r--include/keymaster/key_blob.h97
-rw-r--r--key.cpp6
-rw-r--r--key.h4
-rw-r--r--key_blob.cpp203
-rw-r--r--key_blob_test.cpp70
-rw-r--r--unencrypted_key_blob.cpp201
-rw-r--r--unencrypted_key_blob.h81
12 files changed, 404 insertions, 314 deletions
diff --git a/Makefile b/Makefile
index a533adc..8e512c8 100644
--- a/Makefile
+++ b/Makefile
@@ -40,7 +40,8 @@ CPPSRCS=\
key_blob.cpp \
key_blob_test.cpp \
rsa_operation.cpp \
- serializable.cpp
+ serializable.cpp \
+ unencrypted_key_blob.cpp
CCSRCS=$(GTEST)/src/gtest-all.cc
CSRCS=ocb.c
@@ -109,6 +110,7 @@ key_blob_test: key_blob_test.o \
key_blob.o \
ocb.o \
serializable.o \
+ unencrypted_key_blob.o \
$(GTEST)/src/gtest-all.o
google_keymaster_messages_test: google_keymaster_messages_test.o \
@@ -133,6 +135,7 @@ google_keymaster_test: google_keymaster_test.o \
ocb.o \
rsa_operation.o \
serializable.o \
+ unencrypted_key_blob.o \
$(GTEST)/src/gtest-all.o
$(GTEST)/src/gtest-all.o: CXXFLAGS:=$(subst -Wmissing-declarations,,$(CXXFLAGS))
diff --git a/asymmetric_key.cpp b/asymmetric_key.cpp
index 12f41b1..897fe75 100644
--- a/asymmetric_key.cpp
+++ b/asymmetric_key.cpp
@@ -17,7 +17,6 @@
#include <openssl/evp.h>
#include <openssl/x509.h>
-#include <keymaster/key_blob.h>
#include <keymaster/keymaster_defs.h>
#include "asymmetric_key.h"
@@ -25,6 +24,7 @@
#include "ecdsa_operation.h"
#include "openssl_utils.h"
#include "rsa_operation.h"
+#include "unencrypted_key_blob.h"
namespace keymaster {
@@ -35,13 +35,13 @@ const uint32_t DSA_DEFAULT_KEY_SIZE = 2048;
const uint32_t ECDSA_DEFAULT_KEY_SIZE = 192;
-keymaster_error_t AsymmetricKey::LoadKey(const KeyBlob& blob) {
+keymaster_error_t AsymmetricKey::LoadKey(const UnencryptedKeyBlob& blob) {
UniquePtr<EVP_PKEY, EVP_PKEY_Delete> evp_key(EVP_PKEY_new());
if (evp_key.get() == NULL)
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
EVP_PKEY* tmp_pkey = evp_key.get();
- const uint8_t* key_material = blob.key_material();
+ const uint8_t* key_material = blob.unencrypted_key_material();
if (d2i_PrivateKey(evp_key_type(), &tmp_pkey, &key_material, blob.key_material_length()) ==
NULL) {
return KM_ERROR_INVALID_KEY_BLOB;
@@ -218,7 +218,7 @@ RsaKey* RsaKey::ImportKey(const AuthorizationSet& key_description, EVP_PKEY* pke
return new RsaKey(rsa_key.release(), authorizations, logger);
}
-RsaKey::RsaKey(const KeyBlob& blob, const Logger& logger, keymaster_error_t* error)
+RsaKey::RsaKey(const UnencryptedKeyBlob& blob, const Logger& logger, keymaster_error_t* error)
: AsymmetricKey(blob, logger) {
if (error)
*error = LoadKey(blob);
@@ -422,7 +422,7 @@ DsaKey* DsaKey::ImportKey(const AuthorizationSet& key_description, EVP_PKEY* pke
return new DsaKey(dsa_key.release(), authorizations, logger);
}
-DsaKey::DsaKey(const KeyBlob& blob, const Logger& logger, keymaster_error_t* error)
+DsaKey::DsaKey(const UnencryptedKeyBlob& blob, const Logger& logger, keymaster_error_t* error)
: AsymmetricKey(blob, logger) {
if (error)
*error = LoadKey(blob);
@@ -590,7 +590,7 @@ keymaster_error_t EcdsaKey::get_group_size(const EC_GROUP& group, size_t* key_si
return KM_ERROR_OK;
}
-EcdsaKey::EcdsaKey(const KeyBlob& blob, const Logger& logger, keymaster_error_t* error)
+EcdsaKey::EcdsaKey(const UnencryptedKeyBlob& blob, const Logger& logger, keymaster_error_t* error)
: AsymmetricKey(blob, logger) {
if (error)
*error = LoadKey(blob);
diff --git a/asymmetric_key.h b/asymmetric_key.h
index 6279ff4..7b5f5a1 100644
--- a/asymmetric_key.h
+++ b/asymmetric_key.h
@@ -30,7 +30,7 @@ class AsymmetricKey : public Key {
public:
protected:
AsymmetricKey(const KeyBlob& blob, const Logger& logger) : Key(blob, logger) {}
- keymaster_error_t LoadKey(const KeyBlob& blob);
+ keymaster_error_t LoadKey(const UnencryptedKeyBlob& blob);
/**
* Return a copy of raw key material, in the key's preferred binary format.
@@ -63,7 +63,7 @@ class RsaKey : public AsymmetricKey {
keymaster_error_t* error);
static RsaKey* ImportKey(const AuthorizationSet& key_description, EVP_PKEY* pkey,
const Logger& logger, keymaster_error_t* error);
- RsaKey(const KeyBlob& blob, const Logger& logger, keymaster_error_t* error);
+ RsaKey(const UnencryptedKeyBlob& blob, const Logger& logger, keymaster_error_t* error);
virtual Operation* CreateOperation(keymaster_purpose_t purpose, keymaster_digest_t digest,
keymaster_padding_t padding, keymaster_error_t* error);
@@ -89,14 +89,13 @@ class DsaKey : public AsymmetricKey {
keymaster_error_t* error);
static DsaKey* ImportKey(const AuthorizationSet& key_description, EVP_PKEY* pkey,
const Logger& logger, keymaster_error_t* error);
- DsaKey(const KeyBlob& blob, const Logger& logger, keymaster_error_t* error);
+ DsaKey(const UnencryptedKeyBlob& blob, const Logger& logger, keymaster_error_t* error);
virtual Operation* CreateOperation(keymaster_purpose_t purpose, keymaster_digest_t digest,
keymaster_padding_t padding, keymaster_error_t* error);
static size_t key_size_bits(DSA* dsa_key);
private:
-
DsaKey(DSA* dsa_key, const AuthorizationSet auths, const Logger& logger)
: AsymmetricKey(auths, logger), dsa_key_(dsa_key) {}
@@ -116,8 +115,8 @@ class EcdsaKey : public AsymmetricKey {
static EcdsaKey* GenerateKey(const AuthorizationSet& key_description, const Logger& logger,
keymaster_error_t* error);
static EcdsaKey* ImportKey(const AuthorizationSet& key_description, EVP_PKEY* pkey,
- const Logger& logger, keymaster_error_t* error);
- EcdsaKey(const KeyBlob& blob, const Logger& logger, keymaster_error_t* error);
+ const Logger& logger, keymaster_error_t* error);
+ EcdsaKey(const UnencryptedKeyBlob& blob, const Logger& logger, keymaster_error_t* error);
virtual Operation* CreateOperation(keymaster_purpose_t purpose, keymaster_digest_t digest,
keymaster_padding_t padding, keymaster_error_t* error);
diff --git a/google_keymaster.cpp b/google_keymaster.cpp
index 29a8129..ae69145 100644
--- a/google_keymaster.cpp
+++ b/google_keymaster.cpp
@@ -26,11 +26,11 @@
#include <keymaster/google_keymaster.h>
#include <keymaster/google_keymaster_utils.h>
-#include <keymaster/key_blob.h>
#include "ae.h"
#include "key.h"
#include "operation.h"
+#include "unencrypted_key_blob.h"
namespace keymaster {
@@ -320,9 +320,10 @@ keymaster_error_t GoogleKeymaster::SerializeKey(const Key* key, keymaster_key_or
uint8_t nonce[KeyBlob::NONCE_LENGTH];
GenerateNonce(nonce, array_size(nonce));
- keymaster_key_blob_t key_data = {key_material.get(), key_material_size};
- UniquePtr<KeyBlob> blob(
- new KeyBlob(*enforced, *unenforced, hidden_auths, key_data, MasterKey(), nonce));
+ keymaster_key_blob_t master_key = MasterKey();
+ UniquePtr<KeyBlob> blob(new UnencryptedKeyBlob(
+ *enforced, *unenforced, hidden_auths, key_material.get(), key_material_size,
+ master_key.key_material, master_key.key_material_size, nonce));
if (blob.get() == NULL)
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
if (blob->error() != KM_ERROR_OK)
@@ -342,18 +343,20 @@ keymaster_error_t GoogleKeymaster::SerializeKey(const Key* key, keymaster_key_or
Key* GoogleKeymaster::LoadKey(const keymaster_key_blob_t& key,
const AuthorizationSet& client_params, keymaster_error_t* error) {
- UniquePtr<KeyBlob> blob(LoadKeyBlob(key, client_params, error));
+ UniquePtr<UnencryptedKeyBlob> blob(LoadKeyBlob(key, client_params, error));
if (*error != KM_ERROR_OK)
return NULL;
return Key::CreateKey(*blob, logger(), error);
}
-KeyBlob* GoogleKeymaster::LoadKeyBlob(const keymaster_key_blob_t& key,
- const AuthorizationSet& client_params,
- keymaster_error_t* error) {
+UnencryptedKeyBlob* GoogleKeymaster::LoadKeyBlob(const keymaster_key_blob_t& key,
+ const AuthorizationSet& client_params,
+ keymaster_error_t* error) {
AuthorizationSet hidden;
BuildHiddenAuthorizations(client_params, &hidden);
- UniquePtr<KeyBlob> blob(new KeyBlob(key, hidden, MasterKey()));
+ keymaster_key_blob_t master_key = MasterKey();
+ UniquePtr<UnencryptedKeyBlob> blob(
+ new UnencryptedKeyBlob(key, hidden, master_key.key_material, master_key.key_material_size));
if (blob.get() == NULL) {
*error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
return NULL;
diff --git a/include/keymaster/google_keymaster.h b/include/keymaster/google_keymaster.h
index 4ce8eb8..235c658 100644
--- a/include/keymaster/google_keymaster.h
+++ b/include/keymaster/google_keymaster.h
@@ -24,8 +24,8 @@
namespace keymaster {
class Key;
-class KeyBlob;
class Operation;
+class UnencryptedKeyBlob;
/**
* OpenSSL-based Keymaster backing implementation, for use as a pure software implmentation
@@ -91,8 +91,9 @@ class GoogleKeymaster {
AuthorizationSet* unenforced);
Key* LoadKey(const keymaster_key_blob_t& key, const AuthorizationSet& client_params,
keymaster_error_t* error);
- KeyBlob* LoadKeyBlob(const keymaster_key_blob_t& key, const AuthorizationSet& client_params,
- keymaster_error_t* error);
+ UnencryptedKeyBlob* LoadKeyBlob(const keymaster_key_blob_t& key,
+ const AuthorizationSet& client_params,
+ keymaster_error_t* error);
keymaster_error_t SetAuthorizations(const AuthorizationSet& key_description,
keymaster_key_origin_t origin, AuthorizationSet* enforced,
diff --git a/include/keymaster/key_blob.h b/include/keymaster/key_blob.h
index 8d4bb42..b6827ac 100644
--- a/include/keymaster/key_blob.h
+++ b/include/keymaster/key_blob.h
@@ -31,9 +31,9 @@
namespace keymaster {
/**
- * This class represents a Keymaster key blob, including authorization sets and key material, both
- * encrypted and unencrypted. It's primary purpose is to serialize and deserialize blob arrays, and
- * provide access to the data in the blob.
+ * This class represents a Keymaster key blob, including authorization sets and encrypted key
+ * material. It serializes and deserializes blob arrays, and provides access to the data in the
+ * blob.
*/
class KeyBlob : public Serializable {
public:
@@ -41,50 +41,15 @@ class KeyBlob : public Serializable {
static const size_t TAG_LENGTH = 128 / 8;
/**
- * Create a KeyBlob containing the specified authorization data and key material. The copy of
- * \p key will be encrypted with key derived from \p master_key, using OCB authenticated
- * encryption with \p nonce. It is critically important that nonces NEVER be reused. The most
- * convenient way to accomplish that is to choose them randomly (assuming good randomness, that
- * means there's a probability of reuse of one in 2^96).
- *
- * Note that this interface abuses \p keymaster_key_blob_t a bit. Normally, that struct is used
- * to contain a full Keymaster blob, i.e. what KeyBlob is designed to create and manage. In
- * this case we're using it to hold pure key material without any of the additional structure
- * needed for a true Keymaster key.
- *
- * IMPORTANT: After constructing a KeyBlob, call error() to verify that the blob is usable.
- */
- KeyBlob(const AuthorizationSet& enforced, const AuthorizationSet& unenforced,
- const AuthorizationSet& hidden, const keymaster_key_blob_t& key,
- const keymaster_key_blob_t& master_key, const uint8_t nonce[NONCE_LENGTH]);
-
- /**
- * Create a KeyBlob, reconstituting it from the encrypted material in \p encrypted_key,
- * decrypted with key derived from \p master_key. The KeyBlob takes ownership of the \p
- * keymaster_blob.key_material.
- *
- * Note, again, that \p master_key here is an abuse of \p keymaster_key_blob_t, since it
- * is just key material, not a full Keymaster blob.
+ * Create a KeyBlob, extracting the enforced and unenforced sets. The KeyBlob does *not* take
+ * ownership of \p key_blob's contents.
*
* IMPORTANT: After constructing a KeyBlob, call error() to verify that the blob is usable.
*/
- KeyBlob(const keymaster_key_blob_t& keymaster_blob, const AuthorizationSet& hidden,
- const keymaster_key_blob_t& master_key);
-
- /**
- * Create a KeyBlob, extracting the enforced and unenforced sets, but not decrypting the key, or
- * even keeping it. The KeyBlob does *not* take ownership of key_blob.
- *
- * IMPORTANT: After constructing a KeyBlob, call error() to verify that the blob is usable.
- */
- KeyBlob(const uint8_t* key_blob, size_t blob_size);
+ KeyBlob(const keymaster_key_blob_t& key_blob);
~KeyBlob() {
- memset_s(key_material_.get(), 0, key_material_length_);
- // The following aren't sensitive, but clear them anyway.
- memset_s(encrypted_key_material_.get(), 0, key_material_length_);
- memset_s(nonce_.get(), 0, NONCE_LENGTH);
- memset_s(tag_.get(), 0, TAG_LENGTH);
+ ClearKeyData();
// AuthorizationSets clear themselves.
}
@@ -93,54 +58,56 @@ class KeyBlob : public Serializable {
bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end);
/**
- * Decrypt encrypted key. Call this after calling "Deserialize". Until it's called,
- * key_material() will return a pointer to an uninitialized buffer. Sets error if there is a
- * problem.
- */
- void DecryptKey(const keymaster_key_blob_t& master_key);
-
- /**
* Returns KM_ERROR_OK if all is well, or an appropriate error code if there is a problem. This
- * error code should be checked after constructing or deserializing/decrypting, and if it does
- * not return KM_ERROR_OK, then don't call any other methods.
+ * error code should be checked after construction or deserialization, and if it does not return
+ * KM_ERROR_OK, then don't call any other methods.
*/
inline keymaster_error_t error() { return error_; }
inline const uint8_t* nonce() const { return nonce_.get(); }
- inline const uint8_t* key_material() const { return key_material_.get(); }
inline const uint8_t* encrypted_key_material() const { return encrypted_key_material_.get(); }
inline size_t key_material_length() const { return key_material_length_; }
inline const uint8_t* tag() const { return tag_.get(); }
inline const AuthorizationSet& enforced() const { return enforced_; }
inline const AuthorizationSet& unenforced() const { return unenforced_; }
- inline const AuthorizationSet& hidden() const { return hidden_; }
inline keymaster_algorithm_t algorithm() const { return algorithm_; }
inline size_t key_size_bits() const { return key_size_bits_; }
- private:
- void EncryptKey(const keymaster_key_blob_t& master_key);
- bool ExtractKeyCharacteristics();
-
+ protected:
/**
- * Create an AES_OCB context initialized with a key derived using \p master_key and the
- * authorizations.
+ * Create a KeyBlob containing the specified authorization data.
+ *
+ * IMPORTANT: After constructing a KeyBlob, call error() to verify that the blob is usable.
*/
- class AeCtx;
- AeCtx* InitializeKeyWrappingContext(const keymaster_key_blob_t& master_key,
- keymaster_error_t* error) const;
+ KeyBlob(const AuthorizationSet& enforced, const AuthorizationSet& unenforced);
- const uint8_t* BuildDerivationData(size_t* derivation_data_len) const;
+ /**
+ * Set encrypted key and supporting nonce and tag. Takes ownership of all arguments.
+ */
+ void SetEncryptedKey(uint8_t* encrypted_key_material, size_t encrypted_key_material_length,
+ uint8_t* nonce, uint8_t* tag);
keymaster_error_t error_;
+
+ private:
+ void ClearKeyData() {
+ // None of these are sensitive, but clear them anyway.
+ if (encrypted_key_material_.get())
+ memset_s(encrypted_key_material_.get(), 0, key_material_length_);
+ if (nonce_.get())
+ memset_s(nonce_.get(), 0, NONCE_LENGTH);
+ if (tag_.get())
+ memset_s(tag_.get(), 0, TAG_LENGTH);
+ }
+ bool ExtractKeyCharacteristics();
+
UniquePtr<uint8_t[]> nonce_;
- UniquePtr<uint8_t[]> key_material_;
UniquePtr<uint8_t[]> encrypted_key_material_;
UniquePtr<uint8_t[]> tag_;
size_t key_material_length_;
AuthorizationSet enforced_;
AuthorizationSet unenforced_;
- AuthorizationSet hidden_;
keymaster_algorithm_t algorithm_;
uint32_t key_size_bits_;
};
diff --git a/key.cpp b/key.cpp
index 74cb508..b665919 100644
--- a/key.cpp
+++ b/key.cpp
@@ -16,10 +16,9 @@
#include <openssl/x509.h>
-#include <keymaster/key_blob.h>
-
#include "asymmetric_key.h"
#include "openssl_utils.h"
+#include "unencrypted_key_blob.h"
#include "key.h"
@@ -35,7 +34,8 @@ Key::Key(const KeyBlob& blob, const Logger& logger) : logger_(logger) {
}
/* static */
-Key* Key::CreateKey(const KeyBlob& blob, const Logger& logger, keymaster_error_t* error) {
+Key* Key::CreateKey(const UnencryptedKeyBlob& blob, const Logger& logger,
+ keymaster_error_t* error) {
switch (blob.algorithm()) {
case KM_ALGORITHM_RSA:
return new RsaKey(blob, logger, error);
diff --git a/key.h b/key.h
index 5fd824f..982367f 100644
--- a/key.h
+++ b/key.h
@@ -25,10 +25,12 @@ namespace keymaster {
class KeyBlob;
class Operation;
+class UnencryptedKeyBlob;
class Key {
public:
- static Key* CreateKey(const KeyBlob& blob, const Logger& logger, keymaster_error_t* error);
+ static Key* CreateKey(const UnencryptedKeyBlob& blob, const Logger& logger,
+ keymaster_error_t* error);
static Key* GenerateKey(const AuthorizationSet& key_description, const Logger& logger,
keymaster_error_t* error);
static Key* ImportKey(const AuthorizationSet& key_description,
diff --git a/key_blob.cpp b/key_blob.cpp
index 4eb99f3..3e6ff9a 100644
--- a/key_blob.cpp
+++ b/key_blob.cpp
@@ -16,99 +16,24 @@
#include <assert.h>
-#include <openssl/aes.h>
-#include <openssl/sha.h>
-
#include <keymaster/google_keymaster_utils.h>
#include <keymaster/key_blob.h>
-#include "ae.h"
-
namespace keymaster {
-class KeyBlob::AeCtx {
- public:
- AeCtx() : ctx_(ae_allocate(NULL)) {}
- ~AeCtx() {
- ae_clear(ctx_);
- ae_free(ctx_);
- }
-
- ae_ctx* get() { return ctx_; }
-
- private:
- ae_ctx* ctx_;
-};
-
const size_t KeyBlob::NONCE_LENGTH;
const size_t KeyBlob::TAG_LENGTH;
-KeyBlob::KeyBlob(const AuthorizationSet& enforced, const AuthorizationSet& unenforced,
- const AuthorizationSet& hidden, const keymaster_key_blob_t& key,
- const keymaster_key_blob_t& master_key, const uint8_t nonce[NONCE_LENGTH])
- : error_(KM_ERROR_OK), nonce_(new uint8_t[NONCE_LENGTH]), tag_(new uint8_t[TAG_LENGTH]),
- enforced_(enforced), unenforced_(unenforced), hidden_(hidden) {
+KeyBlob::KeyBlob(const keymaster_key_blob_t& key_blob)
+ : error_(KM_ERROR_OK), nonce_(new uint8_t[NONCE_LENGTH]), tag_(new uint8_t[TAG_LENGTH]) {
if (!nonce_.get() || !tag_.get()) {
error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
return;
}
error_ = KM_ERROR_OK;
- if (enforced_.is_valid() == AuthorizationSet::ALLOCATION_FAILURE ||
- unenforced_.is_valid() == AuthorizationSet::ALLOCATION_FAILURE ||
- hidden_.is_valid() == AuthorizationSet::ALLOCATION_FAILURE) {
- error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
- return;
- }
-
- if (enforced_.is_valid() != AuthorizationSet::OK ||
- unenforced_.is_valid() != AuthorizationSet::OK ||
- hidden_.is_valid() != AuthorizationSet::OK) {
- error_ = KM_ERROR_UNKNOWN_ERROR;
- return;
- }
-
- if (!ExtractKeyCharacteristics())
- return;
-
- key_material_length_ = key.key_material_size;
- key_material_.reset(new uint8_t[key_material_length_]);
- encrypted_key_material_.reset(new uint8_t[key_material_length_]);
-
- if (!key_material_.get() || !encrypted_key_material_.get() || !nonce_.get() || !tag_.get()) {
- error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
- return;
- }
-
- memcpy(nonce_.get(), nonce, NONCE_LENGTH);
- memcpy(key_material_.get(), key.key_material, key_material_length_);
- EncryptKey(master_key);
-}
-
-KeyBlob::KeyBlob(const keymaster_key_blob_t& key, const AuthorizationSet& hidden,
- const keymaster_key_blob_t& master_key)
- : nonce_(new uint8_t[NONCE_LENGTH]), tag_(new uint8_t[TAG_LENGTH]), hidden_(hidden) {
- if (!nonce_.get() || !tag_.get()) {
- error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
- return;
- }
- error_ = KM_ERROR_OK;
-
- const uint8_t* p = key.key_material;
- if (!Deserialize(&p, key.key_material + key.key_material_size))
- return;
- DecryptKey(master_key);
-}
-
-KeyBlob::KeyBlob(const uint8_t* key_blob, size_t blob_size)
- : nonce_(new uint8_t[NONCE_LENGTH]), tag_(new uint8_t[TAG_LENGTH]) {
- if (!nonce_.get() || !tag_.get()) {
- error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
- return;
- }
- error_ = KM_ERROR_OK;
-
- if (!Deserialize(&key_blob, key_blob + blob_size))
+ const uint8_t* key_material = key_blob.key_material;
+ if (!Deserialize(&key_material, key_blob.key_material + key_blob.key_material_size))
return;
}
@@ -129,124 +54,28 @@ uint8_t* KeyBlob::Serialize(uint8_t* buf, const uint8_t* end) const {
}
bool KeyBlob::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
- UniquePtr<uint8_t[]> tmp_key_ptr;
if (!copy_from_buf(buf_ptr, end, nonce_.get(), NONCE_LENGTH) ||
- !copy_size_and_data_from_buf(buf_ptr, end, &key_material_length_, &tmp_key_ptr) ||
+ !copy_size_and_data_from_buf(buf_ptr, end, &key_material_length_,
+ &encrypted_key_material_) ||
!copy_from_buf(buf_ptr, end, tag_.get(), TAG_LENGTH) ||
!enforced_.Deserialize(buf_ptr, end) || !unenforced_.Deserialize(buf_ptr, end)) {
error_ = KM_ERROR_INVALID_KEY_BLOB;
return false;
}
-
- if (!ExtractKeyCharacteristics())
- return false;
-
- encrypted_key_material_.reset(tmp_key_ptr.release());
- key_material_.reset(new uint8_t[key_material_length_]);
- return true;
-}
-
-void KeyBlob::EncryptKey(const keymaster_key_blob_t& master_key) {
- UniquePtr<AeCtx> ctx(InitializeKeyWrappingContext(master_key, &error_));
- if (error_ != KM_ERROR_OK)
- return;
-
- int ae_err = ae_encrypt(ctx->get(), nonce_.get(), key_material(), key_material_length(),
- NULL /* additional data */, 0 /* additional data length */,
- encrypted_key_material_.get(), tag_.get(), 1 /* final */);
- if (ae_err < 0) {
- error_ = KM_ERROR_UNKNOWN_ERROR;
- return;
- }
- assert(ae_err == static_cast<int>(key_material_length_));
- error_ = KM_ERROR_OK;
-}
-
-void KeyBlob::DecryptKey(const keymaster_key_blob_t& master_key) {
- UniquePtr<AeCtx> ctx(InitializeKeyWrappingContext(master_key, &error_));
- if (error_ != KM_ERROR_OK)
- return;
-
- int ae_err =
- ae_decrypt(ctx->get(), nonce_.get(), encrypted_key_material(), key_material_length(),
- NULL /* additional data */, 0 /* additional data length */, key_material_.get(),
- tag_.get(), 1 /* final */);
- if (ae_err == AE_INVALID) {
- // Authentication failed! Decryption probably succeeded(ish), but we don't want to return
- // any data when the authentication fails, so clear it.
- memset_s(key_material_.get(), 0, key_material_length());
- error_ = KM_ERROR_INVALID_KEY_BLOB;
- return;
- } else if (ae_err < 0) {
- error_ = KM_ERROR_UNKNOWN_ERROR;
- return;
- }
- assert(ae_err == static_cast<int>(key_material_length()));
- error_ = KM_ERROR_OK;
+ return ExtractKeyCharacteristics();
}
-KeyBlob::AeCtx* KeyBlob::InitializeKeyWrappingContext(const keymaster_key_blob_t& master_key,
- keymaster_error_t* error) const {
- size_t derivation_data_length;
- UniquePtr<const uint8_t[]> derivation_data(BuildDerivationData(&derivation_data_length));
- if (derivation_data.get() == NULL) {
- *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
- return NULL;
- }
-
- *error = KM_ERROR_OK;
- UniquePtr<AeCtx> ctx(new AeCtx);
-
- SHA256_CTX sha256_ctx;
- UniquePtr<uint8_t[]> hash_buf(new uint8_t[SHA256_DIGEST_LENGTH]);
- Eraser hash_eraser(hash_buf.get(), SHA256_DIGEST_LENGTH);
- UniquePtr<uint8_t[]> derived_key(new uint8_t[AES_BLOCK_SIZE]);
- Eraser derived_key_eraser(derived_key.get(), AES_BLOCK_SIZE);
-
- if (ctx.get() == NULL || hash_buf.get() == NULL || derived_key.get() == NULL) {
- *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
- return NULL;
- }
-
- Eraser sha256_ctx_eraser(sha256_ctx);
-
- // Hash derivation data.
- SHA256_Init(&sha256_ctx);
- SHA256_Update(&sha256_ctx, derivation_data.get(), derivation_data_length);
- SHA256_Final(hash_buf.get(), &sha256_ctx);
-
- // Encrypt hash with master key to build derived key.
- AES_KEY aes_key;
- Eraser aes_key_eraser(AES_KEY);
- if (AES_set_encrypt_key(master_key.key_material, master_key.key_material_size * 8, &aes_key) !=
- 0) {
- *error = KM_ERROR_UNKNOWN_ERROR;
- return NULL;
- }
- AES_encrypt(hash_buf.get(), derived_key.get(), &aes_key);
-
- // Set up AES OCB context using derived key.
- if (ae_init(ctx->get(), derived_key.get(), AES_BLOCK_SIZE, NONCE_LENGTH, TAG_LENGTH) ==
- AE_SUCCESS)
- return ctx.release();
- else {
- memset_s(ctx.get(), 0, ae_ctx_sizeof());
- return NULL;
- }
+KeyBlob::KeyBlob(const AuthorizationSet& enforced, const AuthorizationSet& unenforced)
+ : error_(KM_ERROR_OK), enforced_(enforced), unenforced_(unenforced) {
}
-const uint8_t* KeyBlob::BuildDerivationData(size_t* derivation_data_length) const {
- *derivation_data_length =
- hidden_.SerializedSize() + enforced_.SerializedSize() + unenforced_.SerializedSize();
- uint8_t* derivation_data = new uint8_t[*derivation_data_length];
- if (derivation_data != NULL) {
- uint8_t* buf = derivation_data;
- uint8_t* end = derivation_data + *derivation_data_length;
- buf = hidden_.Serialize(buf, end);
- buf = enforced_.Serialize(buf, end);
- buf = unenforced_.Serialize(buf, end);
- }
- return derivation_data;
+void KeyBlob::SetEncryptedKey(uint8_t* encrypted_key_material, size_t encrypted_key_material_length,
+ uint8_t* nonce, uint8_t* tag) {
+ ClearKeyData();
+ encrypted_key_material_.reset(encrypted_key_material);
+ key_material_length_ = encrypted_key_material_length;
+ nonce_.reset(nonce);
+ tag_.reset(tag);
}
bool KeyBlob::ExtractKeyCharacteristics() {
diff --git a/key_blob_test.cpp b/key_blob_test.cpp
index 275da8b..aae2584 100644
--- a/key_blob_test.cpp
+++ b/key_blob_test.cpp
@@ -24,7 +24,7 @@
#include <keymaster/google_keymaster_utils.h>
#include <keymaster/keymaster_tags.h>
-#include <keymaster/key_blob.h>
+#include "unencrypted_key_blob.h"
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
@@ -46,11 +46,6 @@ const uint8_t nonce[KeyBlob::NONCE_LENGTH]{12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
class KeyBlobTest : public testing::Test {
protected:
KeyBlobTest() {
- key_.key_material = const_cast<uint8_t*>(key_data);
- key_.key_material_size = array_size(key_data);
- master_key_.key_material = const_cast<uint8_t*>(master_key_data);
- master_key_.key_material_size = array_size(master_key_data);
-
enforced_.push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
enforced_.push_back(TAG_KEY_SIZE, 256);
enforced_.push_back(TAG_BLOB_USAGE_REQUIREMENTS, KM_BLOB_STANDALONE);
@@ -67,17 +62,16 @@ class KeyBlobTest : public testing::Test {
hidden_.push_back(TAG_ROOT_OF_TRUST, "foo", 3);
hidden_.push_back(TAG_APPLICATION_ID, "my_app", 6);
- blob_.reset(new KeyBlob(enforced_, unenforced_, hidden_, key_, master_key_, nonce));
+ blob_.reset(new UnencryptedKeyBlob(enforced_, unenforced_, hidden_, key_data,
+ array_size(key_data), master_key_data,
+ array_size(master_key_data), nonce));
}
AuthorizationSet enforced_;
AuthorizationSet unenforced_;
AuthorizationSet hidden_;
- UniquePtr<KeyBlob> blob_;
-
- keymaster_key_blob_t key_;
- keymaster_key_blob_t master_key_;
+ UniquePtr<UnencryptedKeyBlob> blob_;
};
TEST_F(KeyBlobTest, EncryptDecrypt) {
@@ -92,9 +86,10 @@ TEST_F(KeyBlobTest, EncryptDecrypt) {
// Recover the key material.
keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- KeyBlob deserialized(encrypted_blob, hidden_, master_key_);
+ UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
+ array_size(master_key_data));
EXPECT_EQ(KM_ERROR_OK, deserialized.error());
- EXPECT_EQ(0, memcmp(deserialized.key_material(), key_data, array_size(key_data)));
+ EXPECT_EQ(0, memcmp(deserialized.unencrypted_key_material(), key_data, array_size(key_data)));
}
TEST_F(KeyBlobTest, WrongKeyLength) {
@@ -103,11 +98,12 @@ TEST_F(KeyBlobTest, WrongKeyLength) {
blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
// Modify the key length
- serialized_blob[KeyBlob::NONCE_LENGTH]++;
+ serialized_blob[UnencryptedKeyBlob::NONCE_LENGTH]++;
// Decrypting with wrong nonce should fail.
keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- KeyBlob deserialized(encrypted_blob, hidden_, master_key_);
+ UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
+ array_size(master_key_data));
EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
}
@@ -126,9 +122,10 @@ TEST_F(KeyBlobTest, WrongNonce) {
// Decrypting with wrong nonce should fail.
keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- KeyBlob deserialized(encrypted_blob, hidden_, master_key_);
+ UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
+ array_size(master_key_data));
EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
- EXPECT_NE(0, memcmp(deserialized.key_material(), key_data, array_size(key_data)));
+ EXPECT_NE(0, memcmp(deserialized.unencrypted_key_material(), key_data, array_size(key_data)));
}
TEST_F(KeyBlobTest, WrongTag) {
@@ -139,16 +136,19 @@ TEST_F(KeyBlobTest, WrongTag) {
// Find the tag, them modify it.
uint8_t* begin = serialized_blob.get();
uint8_t* end = begin + size;
- auto tag_ptr = std::search(begin, end, blob_->tag(), blob_->tag() + KeyBlob::TAG_LENGTH);
+ auto tag_ptr =
+ std::search(begin, end, blob_->tag(), blob_->tag() + UnencryptedKeyBlob::TAG_LENGTH);
ASSERT_NE(tag_ptr, end);
- EXPECT_EQ(end, std::search(tag_ptr + 1, end, blob_->tag(), blob_->tag() + KeyBlob::TAG_LENGTH));
+ EXPECT_EQ(end, std::search(tag_ptr + 1, end, blob_->tag(),
+ blob_->tag() + UnencryptedKeyBlob::TAG_LENGTH));
(*tag_ptr)++;
// Decrypting with wrong tag should fail.
keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- KeyBlob deserialized(encrypted_blob, hidden_, master_key_);
+ UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
+ array_size(master_key_data));
EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
- EXPECT_NE(0, memcmp(deserialized.key_material(), key_data, array_size(key_data)));
+ EXPECT_NE(0, memcmp(deserialized.unencrypted_key_material(), key_data, array_size(key_data)));
}
TEST_F(KeyBlobTest, WrongCiphertext) {
@@ -169,9 +169,10 @@ TEST_F(KeyBlobTest, WrongCiphertext) {
// Decrypting with wrong tag should fail.
keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- KeyBlob deserialized(encrypted_blob, hidden_, master_key_);
+ UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
+ array_size(master_key_data));
EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
- EXPECT_NE(0, memcmp(deserialized.key_material(), key_data, array_size(key_data)));
+ EXPECT_NE(0, memcmp(deserialized.unencrypted_key_material(), key_data, array_size(key_data)));
}
TEST_F(KeyBlobTest, WrongMasterKey) {
@@ -180,15 +181,13 @@ TEST_F(KeyBlobTest, WrongMasterKey) {
blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
uint8_t wrong_master_data[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- keymaster_key_blob_t wrong_master;
- wrong_master.key_material = wrong_master_data;
- wrong_master.key_material_size = array_size(wrong_master_data);
// Decrypting with wrong master key should fail.
keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- KeyBlob deserialized(encrypted_blob, hidden_, wrong_master);
+ UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, wrong_master_data,
+ array_size(wrong_master_data));
EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
- EXPECT_NE(0, memcmp(deserialized.key_material(), key_data, array_size(key_data)));
+ EXPECT_NE(0, memcmp(deserialized.unencrypted_key_material(), key_data, array_size(key_data)));
}
TEST_F(KeyBlobTest, WrongEnforced) {
@@ -212,7 +211,8 @@ TEST_F(KeyBlobTest, WrongEnforced) {
// Decrypting with wrong unenforced data should fail.
keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- KeyBlob deserialized(encrypted_blob, hidden_, master_key_);
+ UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
+ array_size(master_key_data));
EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
}
@@ -237,7 +237,8 @@ TEST_F(KeyBlobTest, WrongUnenforced) {
// Decrypting with wrong unenforced data should fail.
keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- KeyBlob deserialized(encrypted_blob, hidden_, master_key_);
+ UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
+ array_size(master_key_data));
EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
}
@@ -252,7 +253,8 @@ TEST_F(KeyBlobTest, EmptyHidden) {
// Decrypting with wrong hidden data should fail.
keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- KeyBlob deserialized(encrypted_blob, wrong_hidden, master_key_);
+ UnencryptedKeyBlob deserialized(encrypted_blob, wrong_hidden, master_key_data,
+ array_size(master_key_data));
EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
}
@@ -269,7 +271,8 @@ TEST_F(KeyBlobTest, WrongRootOfTrust) {
// Decrypting with wrong hidden data should fail.
keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- KeyBlob deserialized(encrypted_blob, wrong_hidden, master_key_);
+ UnencryptedKeyBlob deserialized(encrypted_blob, wrong_hidden, master_key_data,
+ array_size(master_key_data));
EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
}
@@ -286,7 +289,8 @@ TEST_F(KeyBlobTest, WrongAppId) {
// Decrypting with wrong hidden data should fail.
keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- KeyBlob deserialized(encrypted_blob, wrong_hidden, master_key_);
+ UnencryptedKeyBlob deserialized(encrypted_blob, wrong_hidden, master_key_data,
+ array_size(master_key_data));
EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
}
diff --git a/unencrypted_key_blob.cpp b/unencrypted_key_blob.cpp
new file mode 100644
index 0000000..bc16030
--- /dev/null
+++ b/unencrypted_key_blob.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+
+#include <openssl/aes.h>
+#include <openssl/sha.h>
+
+#include <keymaster/google_keymaster_utils.h>
+
+#include "ae.h"
+#include "unencrypted_key_blob.h"
+
+namespace keymaster {
+
+class UnencryptedKeyBlob::AeCtx {
+ public:
+ AeCtx() : ctx_(ae_allocate(NULL)) {}
+ ~AeCtx() {
+ ae_clear(ctx_);
+ ae_free(ctx_);
+ }
+
+ ae_ctx* get() { return ctx_; }
+
+ private:
+ ae_ctx* ctx_;
+};
+
+UnencryptedKeyBlob::UnencryptedKeyBlob(const AuthorizationSet& enforced,
+ const AuthorizationSet& unenforced,
+ const AuthorizationSet& hidden,
+ const uint8_t* unencrypted_key,
+ size_t unencrypted_key_length, const uint8_t* master_key,
+ size_t master_key_length, const uint8_t nonce[NONCE_LENGTH])
+ : KeyBlob(enforced, unenforced), hidden_(hidden) {
+ // Check that KeyBlob ctor succeeded.
+ if (error_ != KM_ERROR_OK)
+ return;
+
+ if (hidden_.is_valid() == AuthorizationSet::ALLOCATION_FAILURE) {
+ error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return;
+ }
+
+ if (hidden_.is_valid() != AuthorizationSet::OK) {
+ error_ = KM_ERROR_UNKNOWN_ERROR;
+ return;
+ }
+
+ unencrypted_key_material_.reset(new uint8_t[unencrypted_key_length]);
+ if (!unencrypted_key_material_.get()) {
+ error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return;
+ }
+
+ unencrypted_key_material_length_ = unencrypted_key_length;
+ memcpy(unencrypted_key_material_.get(), unencrypted_key, unencrypted_key_length);
+ EncryptKey(master_key, master_key_length, nonce);
+}
+
+UnencryptedKeyBlob::UnencryptedKeyBlob(const keymaster_key_blob_t& key,
+ const AuthorizationSet& hidden, const uint8_t* master_key,
+ size_t master_key_length)
+ : KeyBlob(key), hidden_(hidden) {
+ // Check that KeyBlob ctor succeeded.
+ if (error_ != KM_ERROR_OK)
+ return;
+ DecryptKey(master_key, master_key_length);
+}
+
+void UnencryptedKeyBlob::EncryptKey(const uint8_t* master_key, size_t master_key_length,
+ const uint8_t* nonce) {
+ UniquePtr<AeCtx> ctx(InitializeKeyWrappingContext(master_key, master_key_length));
+ if (error_ != KM_ERROR_OK)
+ return;
+
+ UniquePtr<uint8_t[]> encrypted_key_material(new uint8_t[unencrypted_key_material_length()]);
+ UniquePtr<uint8_t[]> tag(new uint8_t[TAG_LENGTH]);
+ UniquePtr<uint8_t[]> nonce_copy(new uint8_t[NONCE_LENGTH]);
+ if (!encrypted_key_material.get() || !tag.get() || !nonce_copy.get()) {
+ error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return;
+ }
+ memcpy(nonce_copy.get(), nonce, NONCE_LENGTH);
+
+ int ae_err =
+ ae_encrypt(ctx->get(), nonce, unencrypted_key_material(), unencrypted_key_material_length(),
+ NULL /* additional data */, 0 /* additional data length */,
+ encrypted_key_material.get(), tag.get(), 1 /* final */);
+ if (ae_err < 0) {
+ error_ = KM_ERROR_UNKNOWN_ERROR;
+ return;
+ }
+ assert(ae_err == static_cast<int>(unencrypted_key_material_length()));
+
+ SetEncryptedKey(encrypted_key_material.release(), unencrypted_key_material_length(),
+ nonce_copy.release(), tag.release());
+}
+
+void UnencryptedKeyBlob::DecryptKey(const uint8_t* master_key, size_t master_key_length) {
+ UniquePtr<AeCtx> ctx(InitializeKeyWrappingContext(master_key, master_key_length));
+ if (error_ != KM_ERROR_OK)
+ return;
+
+ unencrypted_key_material_length_ = key_material_length();
+ unencrypted_key_material_.reset(new uint8_t[unencrypted_key_material_length_]);
+ int ae_err = ae_decrypt(ctx->get(), nonce(), encrypted_key_material(), key_material_length(),
+ NULL /* additional data */, 0 /* additional data length */,
+ unencrypted_key_material_.get(), tag(), 1 /* final */);
+ if (ae_err == AE_INVALID) {
+ // Authentication failed! Decryption probably succeeded(ish), but we don't want to return
+ // any data when the authentication fails, so clear it.
+ memset_s(unencrypted_key_material_.get(), 0, unencrypted_key_material_length());
+ error_ = KM_ERROR_INVALID_KEY_BLOB;
+ return;
+ } else if (ae_err < 0) {
+ error_ = KM_ERROR_UNKNOWN_ERROR;
+ return;
+ }
+ assert(ae_err == static_cast<int>(unencrypted_key_material_length()));
+ error_ = KM_ERROR_OK;
+}
+
+UnencryptedKeyBlob::AeCtx*
+UnencryptedKeyBlob::InitializeKeyWrappingContext(const uint8_t* master_key,
+ size_t master_key_length) {
+ size_t derivation_data_length;
+ UniquePtr<const uint8_t[]> derivation_data(BuildDerivationData(&derivation_data_length));
+ if (derivation_data.get() == NULL) {
+ error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return NULL;
+ }
+
+ UniquePtr<AeCtx> ctx(new AeCtx);
+
+ SHA256_CTX sha256_ctx;
+ UniquePtr<uint8_t[]> hash_buf(new uint8_t[SHA256_DIGEST_LENGTH]);
+ Eraser hash_eraser(hash_buf.get(), SHA256_DIGEST_LENGTH);
+ UniquePtr<uint8_t[]> derived_key(new uint8_t[AES_BLOCK_SIZE]);
+ Eraser derived_key_eraser(derived_key.get(), AES_BLOCK_SIZE);
+
+ if (ctx.get() == NULL || hash_buf.get() == NULL || derived_key.get() == NULL) {
+ error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return NULL;
+ }
+
+ Eraser sha256_ctx_eraser(sha256_ctx);
+
+ // Hash derivation data.
+ SHA256_Init(&sha256_ctx);
+ SHA256_Update(&sha256_ctx, derivation_data.get(), derivation_data_length);
+ SHA256_Final(hash_buf.get(), &sha256_ctx);
+
+ // Encrypt hash with master key to build derived key.
+ AES_KEY aes_key;
+ Eraser aes_key_eraser(AES_KEY);
+ if (AES_set_encrypt_key(master_key, master_key_length * 8, &aes_key) != 0) {
+ error_ = KM_ERROR_UNKNOWN_ERROR;
+ return NULL;
+ }
+ AES_encrypt(hash_buf.get(), derived_key.get(), &aes_key);
+
+ // Set up AES OCB context using derived key.
+ if (ae_init(ctx->get(), derived_key.get(), AES_BLOCK_SIZE, NONCE_LENGTH, TAG_LENGTH) ==
+ AE_SUCCESS)
+ return ctx.release();
+ else {
+ memset_s(ctx.get(), 0, ae_ctx_sizeof());
+ return NULL;
+ }
+}
+
+const uint8_t* UnencryptedKeyBlob::BuildDerivationData(size_t* derivation_data_length) const {
+ *derivation_data_length =
+ hidden_.SerializedSize() + enforced().SerializedSize() + unenforced().SerializedSize();
+ uint8_t* derivation_data = new uint8_t[*derivation_data_length];
+ if (derivation_data != NULL) {
+ uint8_t* buf = derivation_data;
+ uint8_t* end = derivation_data + *derivation_data_length;
+ buf = hidden_.Serialize(buf, end);
+ buf = enforced().Serialize(buf, end);
+ buf = unenforced().Serialize(buf, end);
+ }
+ return derivation_data;
+}
+
+} // namespace keymaster
diff --git a/unencrypted_key_blob.h b/unencrypted_key_blob.h
new file mode 100644
index 0000000..51e602a
--- /dev/null
+++ b/unencrypted_key_blob.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_UNENCRYPTED_KEY_BLOB_H_
+#define SYSTEM_KEYMASTER_UNENCRYPTED_KEY_BLOB_H_
+
+#include <keymaster/key_blob.h>
+
+namespace keymaster {
+
+/**
+ * Extends KeyBlob to provide access the the unencrypted key material as well as the encrypted form.
+ */
+class UnencryptedKeyBlob : public KeyBlob {
+ public:
+ /**
+ * Create a UnencryptedKeyBlob containing the specified authorization data and key material. \p
+ * key will be encrypted with a key derived from \p master_key, using OCB authenticated
+ * encryption with \p nonce. It is critically important that nonces NEVER be reused. The most
+ * convenient way to accomplish that is to choose them randomly.
+ *
+ * IMPORTANT: After constructing a UnencryptedKeyBlob, call error() to verify that the blob is
+ * usable.
+ */
+ UnencryptedKeyBlob(const AuthorizationSet& enforced, const AuthorizationSet& unenforced,
+ const AuthorizationSet& hidden, const uint8_t* unencrypted_key,
+ size_t unencrypted_key_length, const uint8_t* master_key,
+ size_t master_key_length, const uint8_t nonce[NONCE_LENGTH]);
+
+ /**
+ * Create a UnencryptedKeyBlob, extracting the enforced and unenforced sets and decrypting the
+ * key. The KeyBlob does *not* take ownership of key_blob.
+ *
+ * IMPORTANT: After constructing a UnencryptedKeyBlob, call error() to verify that the blob is
+ * usable.
+ */
+ UnencryptedKeyBlob(const keymaster_key_blob_t& key_blob, const AuthorizationSet& hidden,
+ const uint8_t* master_key, size_t master_key_length);
+
+ inline const uint8_t* unencrypted_key_material() const {
+ return unencrypted_key_material_.get();
+ }
+ inline size_t unencrypted_key_material_length() const {
+ return unencrypted_key_material_length_;
+ }
+ inline const AuthorizationSet& hidden() const { return hidden_; }
+
+ private:
+ void DecryptKey(const uint8_t* master_key, size_t master_key_length);
+ void EncryptKey(const uint8_t* master_key, size_t master_key_length, const uint8_t* nonce);
+
+ /**
+ * Create an AES_OCB context initialized with a key derived using \p master_key and the
+ * authorizations.
+ */
+ class AeCtx;
+ AeCtx* InitializeKeyWrappingContext(const uint8_t* master_key, size_t master_key_length);
+
+ const uint8_t* BuildDerivationData(size_t* derivation_data_len) const;
+
+ UniquePtr<uint8_t[]> unencrypted_key_material_;
+ size_t unencrypted_key_material_length_;
+ AuthorizationSet hidden_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_UNENCRYPTED_KEY_BLOB_H_