Merge "Created an ObjectStore skeleton with functional encryption."
diff --git a/Makefile b/Makefile
index 6a0b5e5..89be111 100644
--- a/Makefile
+++ b/Makefile
@@ -28,6 +28,7 @@
        $(OUT)object_mock.o \
        $(OUT)object_policy_mock.o \
        $(OUT)object_pool_mock.o \
+       $(OUT)object_store_mock.o \
        $(OUT)session_mock.o \
        $(OUT)slot_manager_mock.o \
        $(OUT)tpm_utility_mock.o
@@ -77,7 +78,8 @@
               $(OUT)object_policy_secret_key.o \
               $(OUT)object_pool_impl.o \
               $(OUT)tpm_utility_impl.o \
-              $(OUT)chaps_factory_impl.o
+              $(OUT)chaps_factory_impl.o \
+              $(OUT)object_store_impl.o
 	$(call cxx_binary, -ldl -ltspi)
 RM_ON_CLEAN += $(OUT)chapsd
 
@@ -145,6 +147,12 @@
 	$(call cxx_binary, -lgtest -lgmock)
 RM_ON_CLEAN += $(OUT)object_pool_test
 
+$(OUT)object_store_test: $(COMMON) \
+                        $(OUT)object_store_test.o \
+                        $(OUT)object_store_impl.o
+	$(call cxx_binary, -lgtest)
+RM_ON_CLEAN += $(OUT)object_store_test
+
 $(OUT)tpm_utility_test: $(COMMON) $(MOCK) \
                         $(OUT)tpm_utility_test.o \
                         $(OUT)tpm_utility_impl.o
@@ -173,7 +181,8 @@
        $(OUT)session_test \
        $(OUT)object_test \
        $(OUT)object_policy_test \
-       $(OUT)object_pool_test
+       $(OUT)object_pool_test \
+       $(OUT)object_store_test
 
 live_tests: $(OUT)chapsd_test \
             $(OUT)chaps_event_generator \
@@ -189,3 +198,4 @@
 	$(OUT)object_test
 	$(OUT)object_policy_test
 	$(OUT)object_pool_test
+	$(OUT)object_store_test
diff --git a/chaps_utility.cc b/chaps_utility.cc
index ef60416..643d059 100644
--- a/chaps_utility.cc
+++ b/chaps_utility.cc
@@ -10,6 +10,9 @@
 #include <string>
 #include <vector>
 
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
 #include <openssl/sha.h>
 
 #include "chaps/attributes.h"
@@ -487,4 +490,24 @@
   return ConvertByteBufferToString(digest, SHA_DIGEST_LENGTH);
 }
 
+ScopedOpenSSL::ScopedOpenSSL() {
+  OpenSSL_add_all_algorithms();
+  ERR_load_crypto_strings();
+}
+
+ScopedOpenSSL::~ScopedOpenSSL() {
+  EVP_cleanup();
+  ERR_free_strings();
+}
+
+std::string GetOpenSSLError() {
+  BIO* bio = BIO_new(BIO_s_mem());
+  ERR_print_errors(bio);
+  char* data = NULL;
+  int data_len = BIO_get_mem_data(bio, &data);
+  string error_string(data, data_len);
+  BIO_free(bio);
+  return error_string;
+}
+
 }  // namespace
diff --git a/chaps_utility.h b/chaps_utility.h
index 406e4cd..f3b8cbe 100644
--- a/chaps_utility.h
+++ b/chaps_utility.h
@@ -194,6 +194,17 @@
 // Computes and returns a SHA-1 hash of the given input.
 std::string sha1(const std::string& input);
 
+// Initializes the OpenSSL library on construction and terminates the library on
+// destruction.
+class ScopedOpenSSL {
+ public:
+  ScopedOpenSSL();
+  ~ScopedOpenSSL();
+};
+
+// Returns a description of the OpenSSL error stack.
+std::string GetOpenSSLError();
+
 }  // namespace chaps
 
 #endif  // CHAPS_CHAPS_UTILITY_H
diff --git a/chapsd.cc b/chapsd.cc
index 240e070..3a92c4b 100644
--- a/chapsd.cc
+++ b/chapsd.cc
@@ -23,6 +23,7 @@
 #include "chaps/chaps_factory_impl.h"
 #include "chaps/chaps_service.h"
 #include "chaps/chaps_service_redirect.h"
+#include "chaps/chaps_utility.h"
 #include "chaps/slot_manager_impl.h"
 #include "chaps/tpm_utility_impl.h"
 
@@ -95,6 +96,7 @@
   CommandLine::Init(argc, argv);
   CommandLine* cl = CommandLine::ForCurrentProcess();
   chromeos::InitLog(chromeos::kLogToSyslog | chromeos::kLogToStderr);
+  chaps::ScopedOpenSSL openssl;
   chaps::g_dispatcher.reset(new DBus::BusDispatcher());
   CHECK(chaps::g_dispatcher.get());
   DBus::default_dispatcher = chaps::g_dispatcher.get();
diff --git a/object_pool.h b/object_pool.h
index 024183b..e1224b1 100644
--- a/object_pool.h
+++ b/object_pool.h
@@ -21,7 +21,7 @@
   // These methods get and set internal persistent blobs. These internal blobs
   // are for use by Chaps. PKCS #11 applications will not see these when
   // searching for objects. Only persistent implementations need to support
-  // internal blobs.
+  // internal blobs. Internal blobs do not need to be encrypted.
   //   blob_id - The value of this identifier must be managed by the caller.
   //             Only one blob can be set per blob_id (i.e. a subsequent call
   //             to SetInternalBlob with the same blob_id will overwrite the
@@ -31,7 +31,7 @@
   // SetKey sets the encryption key for objects in this pool. This is only
   // relevant if the pool is persistent; an object pool has no obligation to
   // encrypt object data in memory.
-  virtual void SetKey(const std::string& key) = 0;
+  virtual bool SetEncryptionKey(const std::string& key) = 0;
   // This method takes ownership of the 'object' pointer on success.
   virtual bool Insert(Object* object) = 0;
   virtual bool Delete(const Object* object) = 0;
diff --git a/object_pool_impl.cc b/object_pool_impl.cc
index 01c1e65..42b6fb6 100644
--- a/object_pool_impl.cc
+++ b/object_pool_impl.cc
@@ -68,9 +68,10 @@
   return false;
 }
 
-void ObjectPoolImpl::SetKey(const string& key) {
+bool ObjectPoolImpl::SetEncryptionKey(const string& key) {
   if (store_.get())
-    store_->SetEncryptionKey(key);
+    return store_->SetEncryptionKey(key);
+  return true;
 }
 
 bool ObjectPoolImpl::Insert(Object* object) {
diff --git a/object_pool_impl.h b/object_pool_impl.h
index 8840501..3ba6e7a 100644
--- a/object_pool_impl.h
+++ b/object_pool_impl.h
@@ -40,7 +40,7 @@
   virtual bool Init();
   virtual bool GetInternalBlob(int blob_id, std::string* blob);
   virtual bool SetInternalBlob(int blob_id, const std::string& blob);
-  virtual void SetKey(const std::string& key);
+  virtual bool SetEncryptionKey(const std::string& key);
   virtual bool Insert(Object* object);
   virtual bool Delete(const Object* object);
   virtual bool Find(const Object* search_template,
diff --git a/object_pool_mock.h b/object_pool_mock.h
index 8fa6d7a..40a23e0 100644
--- a/object_pool_mock.h
+++ b/object_pool_mock.h
@@ -21,7 +21,7 @@
 
   MOCK_METHOD2(GetInternalBlob, bool (int, std::string*));
   MOCK_METHOD2(SetInternalBlob, bool (int, const std::string&));
-  MOCK_METHOD1(SetKey, void (const std::string&));
+  MOCK_METHOD1(SetEncryptionKey, bool (const std::string&));
   MOCK_METHOD1(Insert, bool (Object*));
   MOCK_METHOD1(Delete, bool (const Object*));
   MOCK_METHOD2(Find, bool (const Object*, std::vector<const Object*>*));
diff --git a/object_pool_test.cc b/object_pool_test.cc
index 2d8ab44..ef43a64 100644
--- a/object_pool_test.cc
+++ b/object_pool_test.cc
@@ -123,12 +123,12 @@
   EXPECT_CALL(*store_, SetEncryptionKey(s)).Times(1);
   EXPECT_FALSE(pool2_->GetInternalBlob(1, &s));
   EXPECT_FALSE(pool2_->SetInternalBlob(1, s));
-  pool2_->SetKey(s);
+  pool2_->SetEncryptionKey(s);
   EXPECT_FALSE(pool_->GetInternalBlob(1, &s));
   EXPECT_TRUE(pool_->GetInternalBlob(1, &s));
   EXPECT_FALSE(pool_->SetInternalBlob(1, s));
   EXPECT_TRUE(pool_->SetInternalBlob(1, s));
-  pool_->SetKey(s);
+  pool_->SetEncryptionKey(s);
 }
 
 // Test basic object management operations.
diff --git a/object_store.h b/object_store.h
index e96af94..2cf852e 100644
--- a/object_store.h
+++ b/object_store.h
@@ -8,6 +8,8 @@
 #include <map>
 #include <string>
 
+#include "pkcs11/cryptoki.h"
+
 namespace chaps {
 
 // An object store provides persistent storage of object blobs and internal
@@ -26,11 +28,13 @@
   //             Only one blob can be set per blob_id (i.e. a subsequent call
   //             to SetInternalBlob with the same blob_id will overwrite the
   //             blob).
-  //   blob - The blob data.
+  //  blob - The blob data. This will not be encrypted.
   virtual bool GetInternalBlob(int blob_id, std::string* blob) = 0;
   virtual bool SetInternalBlob(int blob_id, const std::string& blob) = 0;
-  // SetKey sets the encryption key used to encrypt object blobs.
-  virtual void SetEncryptionKey(const std::string& key) = 0;
+  // SetEncryptionKey sets the encryption key used to encrypt all object blobs.
+  // This method must be called before any object blob methods (e.g.
+  // InsertObjectBlob, DeleteObjectBlob, ...).
+  virtual bool SetEncryptionKey(const std::string& key) = 0;
   // Inserts a new blob.
   virtual bool InsertObjectBlob(bool is_private,
                                 CK_OBJECT_CLASS object_class,
diff --git a/object_store_fake.h b/object_store_fake.h
index 3bea58d..b0f14bb 100644
--- a/object_store_fake.h
+++ b/object_store_fake.h
@@ -27,7 +27,8 @@
     internal_blobs_[blob_id] = blob;
     return true;
   }
-  virtual void SetEncryptionKey(const std::string& key) {
+  virtual bool SetEncryptionKey(const std::string& key) {
+    return true;
   }
   virtual bool InsertObjectBlob(bool is_private,
                             CK_OBJECT_CLASS object_class,
diff --git a/object_store_impl.cc b/object_store_impl.cc
new file mode 100644
index 0000000..f4c3800
--- /dev/null
+++ b/object_store_impl.cc
@@ -0,0 +1,159 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chaps/object_store_impl.h"
+
+#include <map>
+#include <string>
+
+#include <base/logging.h>
+#include <chromeos/utility.h>
+#include <openssl/evp.h>
+
+#include "chaps/chaps_utility.h"
+#include "pkcs11/cryptoki.h"
+
+using std::map;
+using std::string;
+
+namespace chaps {
+
+const int ObjectStoreImpl::kAESBlockSizeBytes = 16;
+const int ObjectStoreImpl::kAESKeySizeBytes = 32;
+
+ObjectStoreImpl::ObjectStoreImpl() : cipher_() {
+  EVP_CIPHER_CTX_init(&cipher_context_);
+}
+
+ObjectStoreImpl::~ObjectStoreImpl() {
+  // TODO(dkrahn): Use SecureBlob. See crosbug.com/27681.
+  chromeos::SecureMemset(const_cast<char*>(key_.data()), 0, key_.length());
+  EVP_CIPHER_CTX_cleanup(&cipher_context_);
+}
+
+bool ObjectStoreImpl::GetInternalBlob(int blob_id, string* blob) {
+  return false;
+}
+
+bool ObjectStoreImpl::SetInternalBlob(int blob_id, const string& blob) {
+  return false;
+}
+
+bool ObjectStoreImpl::SetEncryptionKey(const string& key) {
+  if (key.length() != static_cast<size_t>(kAESKeySizeBytes)) {
+    LOG(ERROR) << "Unexpected key size: " << key.length();
+    return false;
+  }
+  key_ = key;
+  return true;
+}
+
+bool ObjectStoreImpl::InsertObjectBlob(bool is_private,
+                                       CK_OBJECT_CLASS object_class,
+                                       const string& key_id,
+                                       const string& blob,
+                                       int* handle) {
+  if (key_.empty())
+    return false;
+  return false;
+}
+
+bool ObjectStoreImpl::DeleteObjectBlob(int handle) {
+  if (key_.empty())
+    return false;
+  return false;
+}
+
+bool ObjectStoreImpl::UpdateObjectBlob(int handle, const string& blob) {
+  if (key_.empty())
+    return false;
+  return false;
+}
+
+bool ObjectStoreImpl::LoadAllObjectBlobs(map<int, string>* blobs) {
+  if (key_.empty())
+    return false;
+  return false;
+}
+
+bool ObjectStoreImpl::RunCipher(bool is_encrypt,
+                                const string& input,
+                                string* output) {
+  if (key_.empty()) {
+    LOG(ERROR) << "Store encryption key has not been initialized.";
+    return false;
+  }
+  int input_length = input.length();
+  string iv;
+  if (is_encrypt) {
+    // Generate a new random IV.
+    iv.resize(kAESBlockSizeBytes);
+    RAND_bytes(ConvertStringToByteBuffer(iv.data()), kAESBlockSizeBytes);
+  } else {
+    // Recover the IV from the input.
+    if (input_length < kAESBlockSizeBytes) {
+      LOG(ERROR) << "Decrypt: Invalid input.";
+      return false;
+    }
+    iv = input.substr(input_length - kAESBlockSizeBytes);
+    input_length -= kAESBlockSizeBytes;
+  }
+  if (!EVP_CipherInit_ex(&cipher_context_,
+                         EVP_aes_256_cbc(),
+                         NULL,
+                         ConvertStringToByteBuffer(key_.data()),
+                         ConvertStringToByteBuffer(iv.data()),
+                         is_encrypt)) {
+    LOG(ERROR) << "EVP_CipherInit_ex failed: " << GetOpenSSLError();
+    return false;
+  }
+  EVP_CIPHER_CTX_set_padding(&cipher_context_,
+                             1);  // Enables PKCS padding.
+  // Set the buffer size to be large enough to hold all output. For encryption,
+  // this will allow space for padding and, for decryption, this will comply
+  // with openssl documentation (even though the final output will be no larger
+  // than input_length).
+  output->resize(input_length + kAESBlockSizeBytes);
+  int output_length = 0;
+  unsigned char* output_bytes = ConvertStringToByteBuffer(output->data());
+  unsigned char* input_bytes = ConvertStringToByteBuffer(input.data());
+  if (!EVP_CipherUpdate(&cipher_context_,
+                        output_bytes,
+                        &output_length,  // Will be set to actual output length.
+                        input_bytes,
+                        input_length)) {
+    LOG(ERROR) << "EVP_CipherUpdate failed: " << GetOpenSSLError();
+    return false;
+  }
+  // The final block is yet to be computed. This check ensures we have at least
+  // kAESBlockSizeBytes bytes left in the output buffer.
+  CHECK(output_length <= input_length);
+  int output_length2 = 0;
+  if (!EVP_CipherFinal_ex(&cipher_context_,
+                          output_bytes + output_length,
+                          &output_length2)) {
+    LOG(ERROR) << "EVP_CipherFinal_ex failed: " << GetOpenSSLError();
+    return false;
+  }
+  // Adjust the output size to the number of bytes actually written.
+  output->resize(output_length + output_length2);
+  if (is_encrypt) {
+    // Append the IV so it will be available during decryption.
+    *output += iv;
+  }
+  return true;
+}
+
+bool ObjectStoreImpl::Encrypt(const string& plain_text,
+                              string* cipher_text) {
+  return RunCipher(true, plain_text, cipher_text);
+}
+
+bool ObjectStoreImpl::Decrypt(const string& cipher_text,
+                              string* plain_text) {
+  return RunCipher(false, cipher_text, plain_text);
+}
+
+}  // namespace chaps
+
diff --git a/object_store_impl.h b/object_store_impl.h
new file mode 100644
index 0000000..c43c46c
--- /dev/null
+++ b/object_store_impl.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHAPS_OBJECT_STORE_IMPL_H_
+#define CHAPS_OBJECT_STORE_IMPL_H_
+
+#include "chaps/object_store.h"
+
+#include <map>
+#include <string>
+
+#include <base/basictypes.h>
+#include <gtest/gtest.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+
+namespace chaps {
+
+// An ObjectStore implementation based on SQLite.
+class ObjectStoreImpl : public ObjectStore {
+ public:
+  ObjectStoreImpl();
+  virtual ~ObjectStoreImpl();
+
+  // ObjectStore methods.
+  virtual bool GetInternalBlob(int blob_id, std::string* blob);
+  virtual bool SetInternalBlob(int blob_id, const std::string& blob);
+  virtual bool SetEncryptionKey(const std::string& key);
+  virtual bool InsertObjectBlob(bool is_private,
+                            CK_OBJECT_CLASS object_class,
+                            const std::string& key_id,
+                            const std::string& blob,
+                            int* handle);
+  virtual bool DeleteObjectBlob(int handle);
+  virtual bool UpdateObjectBlob(int handle, const std::string& blob);
+  virtual bool LoadAllObjectBlobs(std::map<int, std::string>* blobs);
+
+ private:
+  bool RunCipher(bool is_encrypt,
+                 const std::string& input,
+                 std::string* output);
+  bool Encrypt(const std::string& plain_text, std::string* cipher_text);
+  bool Decrypt(const std::string& cipher_text, std::string* plain_text);
+
+  static const int kAESBlockSizeBytes;
+  static const int kAESKeySizeBytes;
+
+  std::string key_;
+  EVP_CIPHER_CTX cipher_context_;
+  const EVP_CIPHER* cipher_;
+
+  friend class TestObjectStoreEncryption;
+  FRIEND_TEST(TestObjectStoreEncryption, EncryptionInit);
+  FRIEND_TEST(TestObjectStoreEncryption, Encryption);
+  FRIEND_TEST(TestObjectStoreEncryption, CBCMode);
+
+  DISALLOW_COPY_AND_ASSIGN(ObjectStoreImpl);
+};
+
+}  // namespace chaps
+
+#endif  // CHAPS_OBJECT_STORE_IMPL_H_
diff --git a/object_store_mock.cc b/object_store_mock.cc
new file mode 100644
index 0000000..d07c56d
--- /dev/null
+++ b/object_store_mock.cc
@@ -0,0 +1,12 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "object_store_mock.h"
+
+namespace chaps {
+
+ObjectStoreMock::ObjectStoreMock() {}
+ObjectStoreMock::~ObjectStoreMock() {}
+
+}
diff --git a/object_store_mock.h b/object_store_mock.h
index 510072f..bb5e27e 100644
--- a/object_store_mock.h
+++ b/object_store_mock.h
@@ -2,21 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHAPS_PERSISTENCE_MOCK_H
-#define CHAPS_PERSISTENCE_MOCK_H
+#ifndef CHAPS_OBJECT_STORE_MOCK_H
+#define CHAPS_OBJECT_STORE_MOCK_H
 
 #include "chaps/object_store.h"
 
+#include <gmock/gmock.h>
+
 namespace chaps {
 
 class ObjectStoreMock : public ObjectStore {
  public:
+  ObjectStoreMock();
+  virtual ~ObjectStoreMock();
   MOCK_METHOD2(GetInternalBlob,
       bool(int blob_id, std::string* blob));
   MOCK_METHOD2(SetInternalBlob,
       bool(int blob_id, const std::string& blob));
   MOCK_METHOD1(SetEncryptionKey,
-      void(const std::string& key));
+      bool(const std::string& key));
   MOCK_METHOD5(InsertObjectBlob,
       bool(bool is_private,
            CK_OBJECT_CLASS object_class,
@@ -33,4 +37,4 @@
 
 }  // namespace
 
-#endif  // CHAPS_PERSISTENCE_MOCK_H
+#endif  // CHAPS_OBJECT_STORE_MOCK_H
diff --git a/object_store_test.cc b/object_store_test.cc
new file mode 100644
index 0000000..87752c4
--- /dev/null
+++ b/object_store_test.cc
@@ -0,0 +1,103 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chaps/object_store_impl.h"
+
+#include <map>
+#include <string>
+
+#include <base/scoped_ptr.h>
+#include <gtest/gtest.h>
+#include <openssl/err.h>
+
+using std::map;
+using std::string;
+
+namespace chaps {
+
+class TestObjectStoreEncryption : public ::testing::Test {
+ public:
+  bool TestEncryption(ObjectStoreImpl& store,
+                      const string& input) {
+    string encrypted;
+    if (!store.Encrypt(input, &encrypted))
+      return false;
+    string decrypted;
+    if (!store.Decrypt(encrypted, &decrypted))
+      return false;
+    return (input == decrypted);
+  }
+};
+
+TEST_F(TestObjectStoreEncryption, EncryptionInit) {
+  ObjectStoreImpl store;
+  string input(10, 0x00), output;
+  EXPECT_FALSE(store.Encrypt(input, &output));
+  EXPECT_FALSE(store.Decrypt(input, &output));
+  EXPECT_FALSE(store.SetEncryptionKey(string()));
+  EXPECT_FALSE(store.SetEncryptionKey(string(16, 0xAA)));
+  EXPECT_FALSE(store.SetEncryptionKey(string(31, 0xAA)));
+  EXPECT_FALSE(store.SetEncryptionKey(string(33, 0xAA)));
+  EXPECT_TRUE(store.SetEncryptionKey(string(32, 0xAA)));
+  EXPECT_TRUE(TestEncryption(store, input));
+}
+
+TEST_F(TestObjectStoreEncryption, Encryption) {
+  ObjectStoreImpl store;
+  string key(32, 0xAA);
+  ASSERT_TRUE(store.SetEncryptionKey(key));
+  string blob(64, 0xBB);
+  // On AES block boundary.
+  EXPECT_TRUE(TestEncryption(store, blob));
+  // Not on AES block boundary.
+  EXPECT_TRUE(TestEncryption(store, string(21, 0xCC)));
+  // One over AES block boundary.
+  EXPECT_TRUE(TestEncryption(store, string(33, 0xDD)));
+  // One under AES block boundary.
+  EXPECT_TRUE(TestEncryption(store, string(31, 0xEE)));
+  // Zero length input.
+  EXPECT_TRUE(TestEncryption(store, string()));
+  // Test random IV: two identical blobs should have different cipher texts.
+  string encrypted1;
+  EXPECT_TRUE(store.Encrypt(blob, &encrypted1));
+  string encrypted2;
+  EXPECT_TRUE(store.Encrypt(blob, &encrypted2));
+  EXPECT_TRUE(encrypted1 != encrypted2);
+  string decrypted1;
+  EXPECT_TRUE(store.Decrypt(encrypted1, &decrypted1));
+  EXPECT_TRUE(decrypted1 == blob);
+  string decrypted2;
+  EXPECT_TRUE(store.Decrypt(encrypted2, &decrypted2));
+  EXPECT_TRUE(decrypted2 == blob);
+  // Invalid decrypt.
+  EXPECT_FALSE(store.Decrypt(blob, &decrypted1));
+  // Test corrupted IV.
+  encrypted1[encrypted1.size()-1]++;
+  EXPECT_TRUE(store.Decrypt(encrypted1, &decrypted1));
+  EXPECT_FALSE(decrypted1 == blob);
+  // Test corrupted cipher text.
+  encrypted2[0]++;
+  EXPECT_TRUE(store.Decrypt(encrypted2, &decrypted2));
+  EXPECT_FALSE(decrypted2 == blob);
+}
+
+TEST_F(TestObjectStoreEncryption, CBCMode) {
+  ObjectStoreImpl store;
+  string key(32, 0xAA);
+  ASSERT_TRUE(store.SetEncryptionKey(key));
+  string two_identical_blocks(32, 0xBB);
+  string encrypted;
+  EXPECT_TRUE(store.Encrypt(two_identical_blocks, &encrypted));
+  string encrypted_block1 = encrypted.substr(0, 16);
+  string encrypted_block2 = encrypted.substr(16, 16);
+  EXPECT_FALSE(encrypted_block1 == encrypted_block2);
+}
+
+}  // namespace chaps
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  ERR_load_crypto_strings();
+  return RUN_ALL_TESTS();
+}
diff --git a/session_impl.cc b/session_impl.cc
index b6cdea9..5e5b060 100644
--- a/session_impl.cc
+++ b/session_impl.cc
@@ -1012,16 +1012,6 @@
   return rsa;
 }
 
-string SessionImpl::GetOpenSSLError() {
-  BIO* bio = BIO_new(BIO_s_mem());
-  ERR_print_errors(bio);
-  char* data = NULL;
-  int data_len = BIO_get_mem_data(bio, &data);
-  string error_string(data, data_len);
-  BIO_free(bio);
-  return error_string;
-}
-
 const EVP_CIPHER* SessionImpl::GetOpenSSLCipher(CK_MECHANISM_TYPE mechanism,
                                                 size_t key_size) {
   switch (mechanism) {
diff --git a/session_impl.h b/session_impl.h
index 6533618..3064b4f 100644
--- a/session_impl.h
+++ b/session_impl.h
@@ -181,7 +181,6 @@
   BIGNUM* ConvertToBIGNUM(const std::string& big_integer);
   // Always returns a non-NULL value.
   RSA* CreateKeyFromObject(const Object* key_object);
-  std::string GetOpenSSLError();
   const EVP_CIPHER* GetOpenSSLCipher(CK_MECHANISM_TYPE mechanism,
                                      size_t key_size);
   const EVP_MD* GetOpenSSLDigest(CK_MECHANISM_TYPE mechanism);
diff --git a/slot_manager_impl.cc b/slot_manager_impl.cc
index f5ee08b..111f572 100644
--- a/slot_manager_impl.cc
+++ b/slot_manager_impl.cc
@@ -265,7 +265,11 @@
       return;
     }
   }
-  object_pool->SetKey(master_key);
+  if (!object_pool->SetEncryptionKey(master_key)) {
+    LOG(ERROR) << "SetEncryptionKey failed for token at " << path.value();
+    tpm_utility_->UnloadKeysForSlot(slot_id);
+    return;
+  }
   // Insert the new token into the empty slot.
   slot_list_[slot_id].token_object_pool = object_pool;
   slot_list_[slot_id].slot_info.flags |= CKF_TOKEN_PRESENT;
diff --git a/slot_manager_test.cc b/slot_manager_test.cc
index 4085aea..ffb80a7 100644
--- a/slot_manager_test.cc
+++ b/slot_manager_test.cc
@@ -51,7 +51,8 @@
       .WillRepeatedly(Return(true));
   EXPECT_CALL(*object_pool, SetInternalBlob(1, string("encrypted_master_key")))
       .WillRepeatedly(Return(true));
-  EXPECT_CALL(*object_pool, SetKey(string("master_key"))).Times(AnyNumber());
+  EXPECT_CALL(*object_pool, SetEncryptionKey(string("master_key")))
+      .WillRepeatedly(Return(true));
   return object_pool;
 }