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
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 @@
 }
 
 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;
+    return ExtractKeyCharacteristics();
 }
 
-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;
+KeyBlob::KeyBlob(const AuthorizationSet& enforced, const AuthorizationSet& unenforced)
+    : error_(KM_ERROR_OK), enforced_(enforced), unenforced_(unenforced) {
 }
 
-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;
-}
-
-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;
-    }
-}
-
-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() {