diff --git a/cc/BUILD b/cc/BUILD
index 74dd7ed8439a7a2ce389e3a110d43f60a21b86ef..f08f31490201fda1016bf0a88cfda813ec030267 100644
--- a/cc/BUILD
+++ b/cc/BUILD
@@ -1,33 +1,130 @@
 licenses(["notice"])  # Apache 2.0
 
+# TODO(przydatek): consider adding string_view/string_piece to util
+#     instead of relying on stringpiece in protobuf.
 cc_library(
     name = "aead",
-    hdrs = ["public/aead.h"],
+    hdrs = ["aead.h"],
     deps = [
+        "//cc/util:statusor",
         "@com_github_google_protobuf//:protobuf_lite",
     ],
 )
 
+cc_library(
+    name = "mac",
+    hdrs = ["mac.h"],
+    deps = [
+        "//cc/util:status",
+        "//cc/util:statusor",
+        "@com_github_google_protobuf//:protobuf_lite",
+    ],
+)
+
+cc_library(
+    name = "registry",
+    srcs = ["registry.h"],
+    hdrs = ["registry.h"],
+    deps = [
+        ":key_manager",
+        "//cc/util:errors",
+        "//cc/util:status",
+        "//cc/util:statusor",
+        "//proto:cc_core",
+        "@com_github_google_protobuf//:protobuf_lite",
+    ],
+)
+
+cc_library(
+    name = "keyset_handle",
+    srcs = ["core/keyset_handle.cc"],
+    hdrs = ["keyset_handle.h"],
+    deps = [
+        "//proto:cc_core",
+    ],
+)
+
+cc_library(
+    name = "key_manager",
+    srcs = ["key_manager.h"],
+    hdrs = ["key_manager.h"],
+    deps = [
+        "//cc/util:errors",
+        "//cc/util:status",
+        "//cc/util:statusor",
+        "@com_github_google_protobuf//:protobuf_lite",
+    ],
+)
+
+cc_library(
+    name = "aead_factory",
+    srcs = ["core/aead_factory.cc"],
+    hdrs = ["aead_factory.h"],
+    deps = [
+        ":aead",
+        ":key_manager",
+        ":keyset_handle",
+        "//cc/util:errors",
+        "//cc/util:status",
+        "//cc/util:statusor",
+    ],
+)
+
+cc_library(
+    name = "mac_factory",
+    srcs = ["core/mac_factory.cc"],
+    hdrs = ["mac_factory.h"],
+    deps = [
+        ":key_manager",
+        ":keyset_handle",
+        ":mac",
+        "//cc/util:status",
+        "//cc/util:statusor",
+    ],
+)
+
 # tests
 
 cc_test(
-    name = "tink_proto_test",
+    name = "aead_factory_test",
     size = "small",
-    srcs = ["tink_proto_test.cc"],
+    srcs = ["core/aead_factory_test.cc"],
     copts = ["-Iexternal/gtest/include"],
     deps = [
-        "//proto:cc_core",
+        ":aead",
+        ":aead_factory",
+        "//cc/util:status",
+        "//cc/util:statusor",
+        "@gtest//:gtest",
+    ],
+)
+
+cc_test(
+    name = "mac_factory_test",
+    size = "small",
+    srcs = ["core/mac_factory_test.cc"],
+    copts = ["-Iexternal/gtest/include"],
+    deps = [
+        ":mac",
+        ":mac_factory",
+        "//cc/util:status",
+        "//cc/util:statusor",
         "@gtest//:gtest",
     ],
 )
 
 cc_test(
-    name = "ecdsa_proto_test",
+    name = "registry_test",
     size = "small",
-    srcs = ["ecdsa_proto_test.cc"],
+    srcs = ["core/registry_test.cc"],
     copts = ["-Iexternal/gtest/include"],
     deps = [
-        "//proto:cc_ecdsa",
+        ":aead",
+        ":registry",
+        "//cc/util:status",
+        "//cc/util:statusor",
+        "//proto:cc_aes_ctr_hmac_aead",
+        "//proto:cc_aes_gcm",
         "@gtest//:gtest",
     ],
 )
diff --git a/cc/aead.h b/cc/aead.h
new file mode 100644
index 0000000000000000000000000000000000000000..eeb329b7b1c8d123aac34967dd1041b59f087cef
--- /dev/null
+++ b/cc/aead.h
@@ -0,0 +1,61 @@
+// Copyright 2017 Google Inc.
+//
+// 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 TINK_AEAD_H_
+#define TINK_AEAD_H_
+
+#include "cc/util/statusor.h"
+#include "google/protobuf/stubs/stringpiece.h"
+
+namespace cloud {
+namespace crypto {
+namespace tink {
+
+///////////////////////////////////////////////////////////////////////////////
+// The interface for authenticated encryption with additional authenticated
+// data.  Implementations of this interface are secure against adaptive
+// chosen ciphertext attacks.  Encryption with additional data ensures
+// authenticity and integrity of that data, but not its secrecy.
+// (see RFC 5116, https://tools.ietf.org/html/rfc5116)
+class Aead {
+ public:
+  // Encrypts 'plaintext' with 'additional_data' as additional
+  // authenticated data, and returns the resulting ciphertext.
+  // The ciphertext allows for checking authenticity and integrity
+  // of the additional data , but does not guarantee its secrecy.
+  virtual util::StatusOr<std::string> Encrypt(
+      const google::protobuf::StringPiece& plaintext,
+      const google::protobuf::StringPiece& additional_data) const = 0;
+
+  // Decrypts 'ciphertext' with 'additional_data' as additional
+  // authenticated data, and returns the resulting plaintext.
+  // The decryption verifies the authenticity and integrity
+  // of the additional data, but there are no guarantees wrt. secrecy
+  // of that data.
+  virtual util::StatusOr<std::string> Decrypt(
+      const google::protobuf::StringPiece& ciphertext,
+      const google::protobuf::StringPiece& additional_data) const = 0;
+
+  virtual ~Aead() {}
+
+  // TODO(przydatek): add asynchronous API.
+};
+
+}  // namespace tink
+}  // namespace crypto
+}  // namespace cloud
+
+#endif  // TINK_AEAD_H_
diff --git a/cc/aead_factory.h b/cc/aead_factory.h
new file mode 100644
index 0000000000000000000000000000000000000000..ee441c8b93e3ead18f6b9eeb0f93d8d5cd3c224f
--- /dev/null
+++ b/cc/aead_factory.h
@@ -0,0 +1,88 @@
+// Copyright 2017 Google Inc.
+//
+// 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 TINK_AEAD_FACTORY_H_
+#define TINK_AEAD_FACTORY_H_
+
+#include "cc/aead.h"
+#include "cc/key_manager.h"
+#include "cc/keyset_handle.h"
+#include "cc/util/errors.h"
+#include "cc/util/statusor.h"
+
+namespace cloud {
+namespace crypto {
+namespace tink {
+
+///////////////////////////////////////////////////////////////////////////////
+// AeadFactory allows obtaining a primitive from a KeysetHandle.
+//
+// AeadFactory gets primitives from the Registry. The factory allows
+// initalizing the Registry with native key types and their managers
+// that Tink supports out of the box.  These key types are divided in
+// two groups:
+//
+//  - standard: secure and safe to use in new code. Over time, with
+//    new developments in cryptanalysis and computing power, some
+//    standard key types might become legacy.
+//
+//  - legacy: deprecated and insecure or obsolete, should not be used
+//    in new code. Existing users should upgrade to one of the standard
+//    key types.
+//
+// This divison allows for gradual retiring insecure or
+// obsolete key types.
+//
+// For example, here is how one can obtain and use an Aead primitive:
+//
+//   AeadFactory.RegisterStandardKeyTypes();
+//   KeysetHandle keyset_handle = ...;
+//   Aead aead = AeadFactory.GetPrimitive(keyset_handle);
+//   string plaintext = ...;
+//   string aad = ...;
+//   string ciphertext = aead.Encrypt(plaintext, aad).ValueOrDie();
+//
+class AeadFactory {
+ public:
+  // Registers standard Aead key types and their managers with the Registry.
+  static util::Status RegisterStandardKeyTypes();
+
+  // Registers legacy Aead key types and their managers with the Registry.
+  static util::Status RegisterLegacyKeyTypes();
+
+  // Returns an Aead-primitive that uses key material from the keyset
+  // specified via 'keyset_handle'.
+  static util::StatusOr<std::unique_ptr<Aead>> GetPrimitive(
+      const KeysetHandle& keyset_handle) {
+    return util::Status::UNKNOWN;
+  }
+
+  // Returns an Aead-primitive that uses key material from the keyset
+  // specified via 'keyset_handle' and is instantiated by the given
+  // 'custom_key_manager' (instead of the key manager from the Registry).
+  static util::StatusOr<std::unique_ptr<Aead>> GetPrimitive(
+      const KeysetHandle& keyset_handle,
+      const KeyManager<Aead>& custom_key_manager) {
+    return util::Status::UNKNOWN;
+  }
+
+};
+
+}  // namespace tink
+}  // namespace crypto
+}  // namespace cloud
+
+#endif  // TINK_AEAD_FACTORY_H_
diff --git a/cc/core/aead_factory.cc b/cc/core/aead_factory.cc
new file mode 100644
index 0000000000000000000000000000000000000000..4ff5c68dcc19786dd45fe9a19f9280f4b6792edb
--- /dev/null
+++ b/cc/core/aead_factory.cc
@@ -0,0 +1,47 @@
+// Copyright 2017 Google Inc.
+//
+// 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 "cc/aead_factory.h"
+
+#include "cc/aead.h"
+#include "cc/util/errors.h"
+#include "cc/util/status.h"
+#include "cc/util/statusor.h"
+#include "proto/tink.pb.h"
+
+namespace cloud {
+namespace crypto {
+namespace tink {
+
+// static
+util::Status AeadFactory::RegisterStandardKeyTypes() {
+  return util::Status(util::error::UNIMPLEMENTED, "Not implemented yet.");
+}
+
+// static
+util::Status AeadFactory::RegisterLegacyKeyTypes() {
+  return util::Status(util::error::UNIMPLEMENTED, "Not implemented yet.");
+}
+
+// static
+util::StatusOr<std::unique_ptr<Aead>> GetPrimitive(
+    const KeysetHandle& keyset_handle) {
+  return util::Status::UNKNOWN;
+}
+
+}  // namespace tink
+}  // namespace crypto
+}  // namespace cloud
diff --git a/cc/core/aead_factory_test.cc b/cc/core/aead_factory_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..eea4e4015cd4d21985eee1965222a4563a7498e4
--- /dev/null
+++ b/cc/core/aead_factory_test.cc
@@ -0,0 +1,56 @@
+// Copyright 2017 Google Inc.
+//
+// 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 "cc/aead.h"
+#include "cc/aead_factory.h"
+#include "cc/util/status.h"
+#include "cc/util/statusor.h"
+#include "gtest/gtest.h"
+#include "proto/tink.pb.h"
+
+using google::cloud::crypto::tink::Keyset;
+using util::Status;
+
+namespace cloud {
+namespace crypto {
+namespace tink {
+namespace {
+
+class AeadFactoryTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+  }
+  void TearDown() override {
+  }
+};
+
+TEST_F(AeadFactoryTest, testBasic) {
+  EXPECT_EQ(util::error::UNIMPLEMENTED,
+            AeadFactory::RegisterStandardKeyTypes().error_code());
+  EXPECT_EQ(util::error::UNIMPLEMENTED,
+            AeadFactory::RegisterLegacyKeyTypes().error_code());
+}
+
+}  // namespace
+}  // namespace tink
+}  // namespace crypto
+}  // namespace cloud
+
+
+int main(int ac, char* av[]) {
+  testing::InitGoogleTest(&ac, av);
+  return RUN_ALL_TESTS();
+}
diff --git a/cc/tink_proto_test.cc b/cc/core/keyset_handle.cc
similarity index 60%
rename from cc/tink_proto_test.cc
rename to cc/core/keyset_handle.cc
index f433692b85bd081d71ec747aba062bcd547c6704..240823b48c6b53db323b0099be8443b5fbdfa0ac 100644
--- a/cc/tink_proto_test.cc
+++ b/cc/core/keyset_handle.cc
@@ -4,7 +4,7 @@
 // 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
+//     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,
@@ -12,30 +12,23 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 //
-////////////////////////////////////////////////////////////////////////////////
-
-#include "gtest/gtest.h"
+///////////////////////////////////////////////////////////////////////////////
 
+#include "cc/keyset_handle.h"
 #include "proto/tink.pb.h"
 
 using google::cloud::crypto::tink::Keyset;
 
-class TinkProtoTest : public ::testing::Test {
- protected:
-  virtual void SetUp() {
-  }
+namespace cloud {
+namespace crypto {
+namespace tink {
 
-  virtual void TearDown() {
-  }
-};
+KeysetHandle::KeysetHandle(const Keyset& keyset) : keyset_(keyset) {}
 
-TEST_F(TinkProtoTest, testKeysetBasic) {
-  Keyset keyset;
-  keyset.set_primary_key_id(1);
-  EXPECT_EQ(1, keyset.primary_key_id());
+const Keyset& KeysetHandle::get_keyset() {
+  return keyset_;
 }
 
-int main(int ac, char* av[]) {
-  testing::InitGoogleTest(&ac, av);
-  return RUN_ALL_TESTS();
-}
+}  // namespace tink
+}  // namespace crypto
+}  // namespace cloud
diff --git a/cc/core/mac_factory.cc b/cc/core/mac_factory.cc
new file mode 100644
index 0000000000000000000000000000000000000000..1130a705488f4aa3cffcf2ce8deb90222e1124ae
--- /dev/null
+++ b/cc/core/mac_factory.cc
@@ -0,0 +1,40 @@
+// Copyright 2017 Google Inc.
+//
+// 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 "cc/mac_factory.h"
+
+#include "cc/mac.h"
+#include "google/protobuf/stubs/stringpiece.h"
+#include "proto/tink.pb.h"
+
+namespace cloud {
+namespace crypto {
+namespace tink {
+
+
+// static
+util::Status MacFactory::RegisterStandardKeyTypes() {
+  return util::Status(util::error::UNIMPLEMENTED, "Not implemented yet.");
+}
+
+// static
+util::Status MacFactory::RegisterLegacyKeyTypes() {
+  return util::Status(util::error::UNIMPLEMENTED, "Not implemented yet.");
+}
+
+}  // namespace tink
+}  // namespace crypto
+}  // namespace cloud
diff --git a/cc/ecdsa_proto_test.cc b/cc/core/mac_factory_test.cc
similarity index 54%
rename from cc/ecdsa_proto_test.cc
rename to cc/core/mac_factory_test.cc
index 8d407a693291a1248d43bea137815ea1a7606a45..d5ab26ce70f26edf982236750f8e8ab786f276a0 100644
--- a/cc/ecdsa_proto_test.cc
+++ b/cc/core/mac_factory_test.cc
@@ -14,27 +14,42 @@
 //
 ////////////////////////////////////////////////////////////////////////////////
 
+#include "cc/mac.h"
+#include "cc/mac_factory.h"
+#include "cc/util/status.h"
+#include "cc/util/statusor.h"
 #include "gtest/gtest.h"
+#include "proto/tink.pb.h"
 
-#include "proto/ecdsa.pb.h"
+using google::cloud::crypto::tink::Keyset;
+using util::Status;
 
-using google::cloud::crypto::tink::EcdsaPublicKey;
+namespace cloud {
+namespace crypto {
+namespace tink {
+namespace {
 
-class EcdsaProtoTest : public ::testing::Test {
+class MacFactoryTest : public ::testing::Test {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
   }
-
-  virtual void TearDown() {
+  void TearDown() override {
   }
 };
 
-TEST_F(EcdsaProtoTest, testEcdsaPublicKey) {
-  EcdsaPublicKey pubKey;
-  pubKey.set_version(1);
-  EXPECT_EQ(1, pubKey.version());
+TEST_F(MacFactoryTest, testBasic) {
+  EXPECT_EQ(util::error::UNIMPLEMENTED,
+            MacFactory::RegisterStandardKeyTypes().error_code());
+  EXPECT_EQ(util::error::UNIMPLEMENTED,
+            MacFactory::RegisterLegacyKeyTypes().error_code());
 }
 
+}  // namespace
+}  // namespace tink
+}  // namespace crypto
+}  // namespace cloud
+
+
 int main(int ac, char* av[]) {
   testing::InitGoogleTest(&ac, av);
   return RUN_ALL_TESTS();
diff --git a/cc/core/registry_test.cc b/cc/core/registry_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..da6d86feaeaf8e9f227084386cd2bd8ffa21e494
--- /dev/null
+++ b/cc/core/registry_test.cc
@@ -0,0 +1,113 @@
+// Copyright 2017 Google Inc.
+//
+// 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 <vector>
+
+#include "cc/aead.h"
+#include "cc/registry.h"
+#include "cc/util/status.h"
+#include "cc/util/statusor.h"
+#include "google/protobuf/message_lite.h"
+#include "gtest/gtest.h"
+#include "proto/aes_ctr_hmac_aead.pb.h"
+#include "proto/aes_gcm.pb.h"
+#include "proto/tink.pb.h"
+
+
+using google::cloud::crypto::tink::AesCtrHmacAeadKey;
+using google::cloud::crypto::tink::AesCtrHmacAeadKeyFormat;
+using google::cloud::crypto::tink::AesGcmKey;
+using google::cloud::crypto::tink::AesGcmKeyFormat;
+using google::cloud::crypto::tink::Keyset;
+using google::protobuf::MessageLite;
+using util::Status;
+
+namespace cloud {
+namespace crypto {
+namespace tink {
+namespace {
+
+class RegistryTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+  }
+  void TearDown() override {
+  }
+};
+
+template <class K, class F>
+class TestAeadKeyManager :
+      public KeyManager<Aead> {
+ public:
+  TestAeadKeyManager(const std::string& key_type) {
+    key_types_.push_back(key_type);
+  }
+
+  util::StatusOr<std::unique_ptr<Aead>>
+  GetPrimitive(const MessageLite& key) const override {
+    return util::Status::UNKNOWN;
+  }
+
+  util::Status NewKey(const MessageLite& key_format, MessageLite* key) const override {
+    return util::Status::UNKNOWN;
+  }
+
+  const std::vector<std::string>&  get_supported_key_types() const override {
+    return key_types_;
+  }
+ private:
+  std::vector<std::string> key_types_;
+};
+
+TEST_F(RegistryTest, testBasic) {
+  Registry& registry = Registry::get_default_registry();
+  std::string key_type_1 = AesCtrHmacAeadKey::descriptor()->full_name();
+  std::string key_type_2 = AesGcmKey::descriptor()->full_name();
+  auto manager_result = registry.get_manager<Aead>(key_type_1);
+  EXPECT_FALSE(manager_result.ok());
+  EXPECT_EQ(util::error::NOT_FOUND,
+            manager_result.status().error_code());
+
+  registry.RegisterKeyManager(key_type_1,
+      new TestAeadKeyManager<AesCtrHmacAeadKey,
+                             AesCtrHmacAeadKeyFormat>(key_type_1));
+  registry.RegisterKeyManager(key_type_2,
+      new TestAeadKeyManager<AesGcmKey,
+                             AesGcmKeyFormat>(key_type_2));
+
+  manager_result = registry.get_manager<Aead>(key_type_1);
+  EXPECT_TRUE(manager_result.ok());
+  auto manager = manager_result.ValueOrDie();
+  EXPECT_TRUE(manager->DoesSupport(key_type_1));
+  EXPECT_FALSE(manager->DoesSupport(key_type_2));
+
+  manager_result = registry.get_manager<Aead>(key_type_2);
+  EXPECT_TRUE(manager_result.ok());
+  manager = manager_result.ValueOrDie();
+  EXPECT_TRUE(manager->DoesSupport(key_type_2));
+  EXPECT_FALSE(manager->DoesSupport(key_type_1));
+}
+
+}  // namespace
+}  // namespace tink
+}  // namespace crypto
+}  // namespace cloud
+
+
+int main(int ac, char* av[]) {
+  testing::InitGoogleTest(&ac, av);
+  return RUN_ALL_TESTS();
+}
diff --git a/cc/key_manager.h b/cc/key_manager.h
new file mode 100644
index 0000000000000000000000000000000000000000..90c5aeb3b0edccfff227798c8bd4bd486559945d
--- /dev/null
+++ b/cc/key_manager.h
@@ -0,0 +1,70 @@
+// Copyright 2017 Google Inc.
+//
+// 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 <vector>
+
+#ifndef TINK_KEY_MANAGER_H_
+#define TINK_KEY_MANAGER_H_
+
+#include "cc/util/errors.h"
+#include "cc/util/status.h"
+#include "cc/util/statusor.h"
+#include "google/protobuf/message_lite.h"
+#include "proto/tink.pb.h"
+
+namespace cloud {
+namespace crypto {
+namespace tink {
+
+/**
+ * KeyManager "understands" keys of a specific key types: it can
+ * generate keys of a supported type and create primitives for
+ * supported keys.  A key type is identified by the global name of the
+ * protocol buffer that holds the corresponding key material, and is
+ * given by type_url-field of KeyData-protocol buffer.
+ *
+ * - P: the primitive implemented by keys understood by this manager
+ */
+template<class P>
+class KeyManager {
+ public:
+  // Constructs an instance of P for the given 'key'.
+  virtual util::StatusOr<std::unique_ptr<P>>
+  GetPrimitive(const google::protobuf::MessageLite& key) const = 0;
+
+  // Generates a new random key, based on the specified 'key_format'.
+  virtual util::Status NewKey(
+      const google::protobuf::MessageLite& key_format,
+      google::protobuf::MessageLite* key) const = 0;
+
+  // Returns a vector of type_url-strings that identify the key types
+  // of keys handled by this manager.
+  virtual const std::vector<std::string>&  get_supported_key_types() const = 0;
+
+  bool DoesSupport(const std::string& key_type) const {
+    auto types = get_supported_key_types();
+    return (std::find(types.begin(), types.end(), key_type) != types.end());
+  }
+
+  virtual ~KeyManager<P>() {}
+};
+
+}  // namespace tink
+}  // namespace crypto
+}  // namespace cloud
+
+#endif  // TINK_KEY_MANAGER_H_
diff --git a/cc/keyset_handle.h b/cc/keyset_handle.h
new file mode 100644
index 0000000000000000000000000000000000000000..7860b16d563622d7c340f56517ff027596a57e28
--- /dev/null
+++ b/cc/keyset_handle.h
@@ -0,0 +1,48 @@
+// Copyright 2017 Google Inc.
+//
+// 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 TINK_KEYSET_HANDLE_H_
+#define TINK_KEYSET_HANDLE_H_
+
+#include "google/protobuf/stubs/statusor.h"
+#include "google/protobuf/stubs/stringpiece.h"
+#include "proto/tink.pb.h"
+
+namespace cloud {
+namespace crypto {
+namespace tink {
+
+/**
+ * KeysetHandle provides abstracted access to Keysets, to limit
+ * the exposure of actual protocol buffers that hold sensitive
+ * key material.
+ */
+class KeysetHandle {
+ public:
+  // TODO(przydatek): refactor to ensure that creation KeysetHandle-objects
+  //   can be controlled (as in Java).
+  KeysetHandle(const google::cloud::crypto::tink::Keyset& keyset);
+  const google::cloud::crypto::tink::Keyset& get_keyset();
+
+ private:
+  google::cloud::crypto::tink::Keyset keyset_;
+};
+
+}  // namespace tink
+}  // namespace crypto
+}  // namespace cloud
+
+#endif  // TINK_KEYSET_HANDLE_H_
diff --git a/cc/mac.h b/cc/mac.h
new file mode 100644
index 0000000000000000000000000000000000000000..73f21a0c334639229ad9db24b206fcd2ff91c1eb
--- /dev/null
+++ b/cc/mac.h
@@ -0,0 +1,53 @@
+// Copyright 2017 Google Inc.
+//
+// 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 TINK_MAC_H_
+#define TINK_MAC_H_
+
+#include "cc/util/status.h"
+#include "cc/util/statusor.h"
+#include "google/protobuf/stubs/stringpiece.h"
+
+namespace cloud {
+namespace crypto {
+namespace tink {
+
+///////////////////////////////////////////////////////////////////////////////
+// Interface for MACs (Message Authentication Codes).
+// This interface should be used for authentication only, and not for other
+// purposes (e.g., it should not be used to generate pseudorandom bytes).
+class Mac {
+ public:
+  // Computes and returns the message authentication code (MAC) for 'data'.
+  virtual util::StatusOr<std::string> ComputeMac(
+      google::protobuf::StringPiece data) const = 0;
+
+  // Verifies if 'mac' is a correct authentication code (MAC) for 'data'.
+  // Returns Status::OK if 'mac' is correct, and a non-OK-Status otherwise.
+  virtual util::Status VerifyMac(
+      google::protobuf::StringPiece mac,
+      google::protobuf::StringPiece data) const = 0;
+
+  virtual ~Mac() {}
+
+  // TODO(przydatek): add asynchronous API.
+};
+
+}  // namespace tink
+}  // namespace crypto
+}  // namespace cloud
+
+#endif  // TINK_MAC_H_
diff --git a/cc/mac_factory.h b/cc/mac_factory.h
new file mode 100644
index 0000000000000000000000000000000000000000..d117cabc39ff5ee9e9426688128999ea0a2e3c8a
--- /dev/null
+++ b/cc/mac_factory.h
@@ -0,0 +1,86 @@
+// Copyright 2017 Google Inc.
+//
+// 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 TINK_MAC_FACTORY_H_
+#define TINK_MAC_FACTORY_H_
+
+#include "cc/key_manager.h"
+#include "cc/keyset_handle.h"
+#include "cc/mac.h"
+#include "cc/util/status.h"
+#include "cc/util/statusor.h"
+#include "proto/tink.pb.h"
+
+namespace cloud {
+namespace crypto {
+namespace tink {
+
+///////////////////////////////////////////////////////////////////////////////
+// MacFactory allows obtaining a primitive from a KeysetHandle.
+//
+// MacFactory gets primitives from the Registry. The factory allows
+// initalizing the Registry with native key types and their managers
+// that Tink supports out of the box. These key types are divided in
+// two groups:
+//
+// - standard: secure and safe to use in new code. Over time, with new
+//   developments in cryptanalysis and computing power, some standard
+//   key types might become legacy.
+//
+// - legacy: deprecated and insecure or obsolete, should not be used
+//   in new code.  Existing users should upgrade to one of the
+//   standard key types.
+//
+// This divison allows for gradual retiring insecure or obsolete key types.
+//
+// For example, here is how one can obtain and use a Mac primitive:
+//
+//   MacFactory.RegisterStandardKeyTypes();
+//   KeysetHandle keyset_handle = ...;
+//   Mac mac = MacFactory.GetPrimitive(keyset_handle);
+//   string data = ...;
+//   string tag = mac.ComputeMac(data).ValueOrDie();
+//
+class MacFactory {
+ public:
+  // Registers standard Mac key types and their managers with the Registry.
+  static util::Status RegisterStandardKeyTypes();
+
+  // Registers legacy Mac key types and their managers with the Registry.
+  static util::Status RegisterLegacyKeyTypes();
+
+  // Returns a Mac-primitive that uses key material from the keyset
+  // specified via 'keyset_handle'.
+  static util::StatusOr<std::unique_ptr<Mac>> GetPrimitive(
+      const KeysetHandle& keyset_handle) {
+    return util::Status::UNKNOWN;
+  }
+
+  // Returns a Mac-primitive that uses key material from the keyset
+  // specified via 'keyset_handle' and is instantiated by the given
+  // 'custom_key_manager' (instead of the key manager from the Registry).
+  static util::StatusOr<std::unique_ptr<Mac>> GetPrimitive(
+      const KeysetHandle& keyset_handle,
+      const KeyManager<Mac>& custom_key_manager) {
+    return util::Status::UNKNOWN;
+  }
+};
+
+}  // namespace tink
+}  // namespace crypto
+}  // namespace cloud
+
+#endif  // TINK_MAC_FACTORY_H_
diff --git a/cc/public/aead.h b/cc/public/aead.h
deleted file mode 100644
index d0cf6983820b8ffff3273d1d76ea05de9311a69b..0000000000000000000000000000000000000000
--- a/cc/public/aead.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * 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.
- */
-// AEAD primitive (Authenticated Encryption with Associated Data, RFC 5116).
-// TODO(przydatek): add documentation.
-
-#ifndef TINK_PUBLIC_AEAD_H_
-#define TINK_PUBLIC_AEAD_H_
-
-#include "google/protobuf/stubs/stringpiece.h"
-#include "google/protobuf/stubs/statusor.h"
-
-namespace cloud {
-namespace crypto {
-namespace tink {
-
-using google::protobuf;
-
-class Aead {
- public:
-  virtual util::StatusOr<std::string> Encrypt(
-     StringPiece plaintext, StringPiece associated_data) const = 0;
-  virtual util::StatusOr<std::string> Decrypt(
-     StringPiece ciphertext, StringPiece associated_data) const = 0;
-  virtual ~Aead() {}
-};
-
-}  // namespace tink
-}  // namespace crypto
-}  // namespace cloud
-
-#endif  // TINK_PUBLIC_AEAD_H_
diff --git a/cc/registry.h b/cc/registry.h
new file mode 100644
index 0000000000000000000000000000000000000000..980c2c601312d91135520c7b7599347c85ae708a
--- /dev/null
+++ b/cc/registry.h
@@ -0,0 +1,135 @@
+// Copyright 2017 Google Inc.
+//
+// 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 TINK_REGISTRY_H_
+#define TINK_REGISTRY_H_
+
+#include <typeinfo>
+#include <unordered_map>
+
+#include "cc/key_manager.h"
+#include "cc/util/errors.h"
+#include "cc/util/status.h"
+#include "google/protobuf/message_lite.h"
+#include "google/protobuf/stubs/singleton.h"
+#include "google/protobuf/stubs/stringpiece.h"
+#include "proto/tink.pb.h"
+
+namespace cloud {
+namespace crypto {
+namespace tink {
+
+template <class P>
+void delete_manager(void* t) {
+  delete static_cast<KeyManager<P>*>(t);
+}
+
+// Registry for KeyMangers.
+//
+// It is essentially a big container (map) that for each supported key
+// type holds a corresponding KeyManager object, which "understands"
+// the key type (i.e. the KeyManager can instantiate the primitive
+// corresponding to given key, or can generate new keys of the
+// supported key type).  Registry is initialized at startup, and is
+// later used to instantiate primitives for given keys or keysets.
+// Keeping KeyManagers for all primitives in a single Registry (rather
+// than having a separate KeyManager per primitive) enables modular
+// construction of compound primitives from "simple" ones, e.g.,
+// AES-CTR-HMAC AEAD encryption uses IND-CPA encryption and a MAC.
+//
+// Note that regular users will usually not work directly with
+// Registry, but rather via primitive factories, which in the
+// background query the Registry for specific KeyManagers.  Registry
+// is public though, to enable configurations with custom primitives
+// and KeyManagers.
+class Registry {
+ public:
+  static Registry& get_default_registry() {
+    return *(default_registry_.get());
+  }
+
+  // Registers the given 'manager' for the key type identified by 'type_url'.
+  // Takes ownership of 'manager', which must be non-nullptr.
+  template <class P>
+  util::Status RegisterKeyManager(const std::string& type_url,
+                                  KeyManager<P>* manager) {
+    std::unique_ptr<void, void(*)(void*)>
+        entry(manager, delete_manager<P>);
+    if (!manager->DoesSupport(type_url)) {
+      return ToStatusF(util::error::INVALID_ARGUMENT,
+                       "The manager does not support type '%s'.",
+                       type_url.c_str());
+    }
+    auto curr_manager = type_to_manager_map_.find(type_url);
+    if (curr_manager != type_to_manager_map_.end()) {
+      return ToStatusF(util::error::ALREADY_EXISTS,
+                       "A manager for type '%s' has been already registered.",
+                       type_url.c_str());
+    }
+    type_to_manager_map_.insert(
+        std::make_pair(type_url, std::move(entry)));
+    type_to_primitive_map_.insert(
+        std::make_pair(type_url, typeid(P).name()));
+    return util::Status::OK;
+  }
+
+  // Returns a key manager for the given type_url (if any found).
+  // Keeps the ownership of the manager.
+  // TODO(przydatek): consider changing return value to
+  //   StatusOr<std::reference_wrapper<KeyManager<P>>>
+  // (cannot return reference directly, as StatusOr does not support it,
+  // see https://goo.gl/x0ymDz)
+  template <class P>
+  util::StatusOr<const KeyManager<P>*> get_manager(
+      const std::string& type_url) {
+    auto manager_entry = type_to_manager_map_.find(type_url);
+    if (manager_entry == type_to_manager_map_.end()) {
+      return ToStatusF(util::error::NOT_FOUND,
+                       "No manager for type '%s' has been registered.",
+                       type_url.c_str());
+    }
+    if (type_to_primitive_map_[type_url] != typeid(P).name()) {
+      return ToStatusF(util::error::INVALID_ARGUMENT,
+                       "Wrong Primitive type for key type '%s': "
+                       "got '%s', expected '%s'",
+                       type_url.c_str(),
+                       typeid(P).name(),
+                       type_to_primitive_map_[type_url]);
+    }
+    return static_cast<KeyManager<P>*>(manager_entry->second.get());
+  }
+
+ protected:
+  friend class google::protobuf::internal::Singleton<Registry>;
+  Registry() {}
+
+ private:
+  static google::protobuf::internal::Singleton<Registry> default_registry_;
+  // TODO(przydatek): change to tbb::concurrent_unordered_map for thread safety
+  //     (https://www.threadingbuildingblocks.org/)
+  typedef std::unordered_map<std::string, std::unique_ptr<void, void(*)(void*)>>
+      TypeToManagerMap;
+  typedef std::unordered_map<std::string, const char*>
+      TypeToPrimitiveMap;
+  TypeToManagerMap type_to_manager_map_;
+  TypeToPrimitiveMap type_to_primitive_map_;
+};
+
+}  // namespace tink
+}  // namespace crypto
+}  // namespace cloud
+
+#endif  // TINK_REGISTRY_H_
diff --git a/cc/util/BUILD b/cc/util/BUILD
new file mode 100644
index 0000000000000000000000000000000000000000..3dbe97d293dc3bb1cf5edfac3d54fc206729b252
--- /dev/null
+++ b/cc/util/BUILD
@@ -0,0 +1,42 @@
+licenses(["notice"])  # Apache 2.0
+
+package(default_visibility = ["//cc:__subpackages__"])
+
+cc_library(
+    name = "errors",
+    srcs = ["errors.cc"],
+    hdrs = ["errors.h"],
+    deps = [
+        ":status",
+    ],
+)
+
+cc_library(
+    name = "status",
+    srcs = ["status.cc"],
+    hdrs = ["status.h"],
+)
+
+cc_library(
+    name = "statusor",
+    srcs = ["statusor.h"],
+    hdrs = ["statusor.h"],
+    deps = [
+        ":status",
+    ],
+)
+
+# tests
+
+cc_test(
+    name = "errors_test",
+    size = "small",
+    srcs = ["errors_test.cc"],
+    copts = ["-Iexternal/gtest/include"],
+    linkopts = ["-lpthread"],
+    deps = [
+        ":errors",
+        ":status",
+        "@gtest//:gtest",
+    ],
+)
diff --git a/cc/util/errors.cc b/cc/util/errors.cc
new file mode 100644
index 0000000000000000000000000000000000000000..32b679806784dafbc583b8dcc15619b831d086f5
--- /dev/null
+++ b/cc/util/errors.cc
@@ -0,0 +1,42 @@
+// Copyright 2017 Google Inc.
+//
+// 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 <stdarg.h>
+
+#include "cc/util/status.h"
+
+using util::error::Code;
+using util::Status;
+
+namespace cloud {
+namespace crypto {
+namespace tink {
+
+// Construct a Status object given a printf-style va list.
+Status ToStatusF(Code code, const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  char* p;
+  vasprintf(&p, format, ap);
+  va_end(ap);
+  Status status(code, p);
+  free(p);
+  return status;
+}
+
+}  // namespace tink
+}  // namespace crypto
+}  // namespace cloud
diff --git a/cc/util/errors.h b/cc/util/errors.h
new file mode 100644
index 0000000000000000000000000000000000000000..e1a76637d8c2c45d0f93256407a37f4a74529d80
--- /dev/null
+++ b/cc/util/errors.h
@@ -0,0 +1,39 @@
+// Copyright 2017 Google Inc.
+//
+// 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 TINK_UTIL_ERRORS_H_
+#define TINK_UTIL_ERRORS_H_
+
+#include "cc/util/status.h"
+
+// from #include "absl/base/port.h"
+#define PRINTF_ATTRIBUTE(string_index, first_to_check)                  \
+    __attribute__((__format__ (__printf__, string_index, first_to_check)))
+
+namespace cloud {
+namespace crypto {
+namespace tink {
+
+// Constructs a Status object given a printf-style va list.
+util::Status ToStatusF(
+    util::error::Code code, const char* format, ...)
+    PRINTF_ATTRIBUTE(2, 3);
+
+}  // namespace tink
+}  // namespace crypto
+}  // namespace cloud
+
+#endif  // TINK_UTIL_ERRORS_H_
diff --git a/cc/util/errors_test.cc b/cc/util/errors_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f735bbced2f8ea24ea0c93396883ebe3512a8f70
--- /dev/null
+++ b/cc/util/errors_test.cc
@@ -0,0 +1,60 @@
+// Copyright 2017 Google Inc.
+//
+// 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 <stdarg.h>
+
+#include "gtest/gtest.h"
+#include "cc/util/errors.h"
+#include "cc/util/status.h"
+
+namespace cloud {
+namespace crypto {
+namespace tink {
+namespace {
+
+class ErrorsTest : public ::testing::Test {
+ protected:
+  void SetUp() override {}
+  void TearDown() override {}
+};
+
+TEST_F(ErrorsTest, ToStatusFTest) {
+  const char* const msg1 = "test message 1";
+  const char* const msg2 = "test message %s 2 %d";
+  util::Status status;
+
+  status = ToStatusF(util::error::OK, msg1);
+  EXPECT_TRUE(status.ok());
+  // if status is OK, error message is ignored
+  EXPECT_EQ("", status.error_message());
+  EXPECT_EQ(util::error::OK, status.error_code());
+
+  const char* expected_msg2 = "test message asdf 2 42";
+  status = ToStatusF(util::error::UNKNOWN, msg2, "asdf", 42);
+  EXPECT_FALSE(status.ok());
+  EXPECT_EQ(expected_msg2, status.error_message());
+  EXPECT_EQ(util::error::UNKNOWN, status.error_code());
+}
+
+}  // namespace
+}  // namespace tink
+}  // namespace crypto
+}  // namespace cloud
+
+int main(int ac, char* av[]) {
+  testing::InitGoogleTest(&ac, av);
+  return RUN_ALL_TESTS();
+}
diff --git a/cc/util/status.cc b/cc/util/status.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8b3b9422672a21485b71c0e0d489f8419dc289c9
--- /dev/null
+++ b/cc/util/status.cc
@@ -0,0 +1,128 @@
+// Copyright 2017 Google Inc.
+//
+// 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 <sstream>
+
+#include "cc/util/status.h"
+
+using ::std::ostream;
+using std::string;
+
+namespace util {
+
+namespace {
+
+
+const Status& GetCancelled() {
+  static const Status status(::util::error::CANCELLED, "");
+  return status;
+}
+
+const Status& GetUnknown() {
+  static const Status status(::util::error::UNKNOWN, "");
+  return status;
+}
+
+
+}  // namespace
+
+
+Status::Status() : code_(::util::error::OK), message_("") {
+}
+
+Status::Status(::util::error::Code error, const string& error_message)
+    : code_(error), message_(error_message) {
+  if (code_ == ::util::error::OK) {
+    message_.clear();
+  }
+}
+
+Status::Status(const Status& other)
+    : code_(other.code_), message_(other.message_) {
+}
+
+Status& Status::operator=(const Status& other) {
+  code_ = other.code_;
+  message_ = other.message_;
+  return *this;
+}
+
+const Status& Status::CANCELLED = GetCancelled();
+const Status& Status::UNKNOWN = GetUnknown();
+const Status& Status::OK = Status();
+
+string Status::ToString() const {
+  if (code_ == ::util::error::OK) {
+    return "OK";
+  }
+
+  std::ostringstream oss;
+  oss << code_ << ": " << message_;
+  return oss.str();
+}
+
+string ErrorCodeString(util::error::Code error) {
+  switch (error) {
+    case util::error::OK:
+      return "OK";
+    case util::error::CANCELLED:
+      return "CANCELLED";
+    case util::error::UNKNOWN:
+      return "UNKNOWN";
+    case util::error::INVALID_ARGUMENT:
+      return "INVALID_ARGUMENT";
+    case util::error::DEADLINE_EXCEEDED:
+      return "DEADLINE_EXCEEDED";
+    case util::error::NOT_FOUND:
+      return "NOT_FOUND";
+    case util::error::ALREADY_EXISTS:
+      return "ALREADY_EXISTS";
+    case util::error::PERMISSION_DENIED:
+      return "PERMISSION_DENIED";
+    case util::error::RESOURCE_EXHAUSTED:
+      return "RESOURCE_EXHAUSTED";
+    case util::error::FAILED_PRECONDITION:
+      return "FAILED_PRECONDITION";
+    case util::error::ABORTED:
+      return "ABORTED";
+    case util::error::OUT_OF_RANGE:
+      return "OUT_OF_RANGE";
+    case util::error::UNIMPLEMENTED:
+      return "UNIMPLEMENTED";
+    case util::error::INTERNAL:
+      return "INTERNAL";
+    case util::error::UNAVAILABLE:
+      return "UNAVAILABLE";
+    case util::error::DATA_LOSS:
+      return "DATA_LOSS";
+  }
+  // Avoid using a "default" in the switch, so that the compiler can
+  // give us a warning, but still provide a fallback here.
+  return std::to_string(error);
+}
+
+extern ostream& operator<<(ostream& os, util::error::Code code) {
+  os << ErrorCodeString(code);
+  return os;
+}
+
+extern ostream& operator<<(ostream& os, const Status& other) {
+  os << other.ToString();
+  return os;
+}
+
+
+}  // namespace util
diff --git a/cc/util/status.h b/cc/util/status.h
new file mode 100644
index 0000000000000000000000000000000000000000..07816bae0db14c157f894103981c15533e96f6a2
--- /dev/null
+++ b/cc/util/status.h
@@ -0,0 +1,189 @@
+// Copyright 2017 Google Inc.
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+// This code was unceremoniously lifted from the version at
+// github.com/google/lmctfy with a few minor modifications mainly to reduce the
+// dependencies.
+
+#ifndef TINK_UTIL_STATUS_H_
+#define TINK_UTIL_STATUS_H_
+
+#include <string>
+
+namespace util {
+
+namespace error {
+
+
+// These values match the error codes in the codes.proto file of the original.
+enum Code {
+  // Not an error; returned on success
+  OK = 0,
+
+  // The operation was cancelled (typically by the caller).
+  CANCELLED = 1,
+
+  // Unknown error.
+  UNKNOWN = 2,
+
+  // Client specified an invalid argument.  Note that this differs
+  // from FAILED_PRECONDITION.  INVALID_ARGUMENT indicates arguments
+  // that are problematic regardless of the state of the system
+  // (e.g., a malformed file name).
+  INVALID_ARGUMENT = 3,
+
+  // Deadline expired before operation could complete.
+  DEADLINE_EXCEEDED = 4,
+
+  // Some requested entity (e.g., file or directory) was not found.
+  NOT_FOUND = 5,
+
+  // Some entity that we attempted to create (e.g., file or directory)
+  // already exists.
+  ALREADY_EXISTS = 6,
+
+  // The caller does not have permission to execute the specified
+  // operation.
+  PERMISSION_DENIED = 7,
+
+  // Some resource has been exhausted, perhaps a per-user quota, or
+  // perhaps the entire file system is out of space.
+  RESOURCE_EXHAUSTED = 8,
+
+  // Operation was rejected because the system is not in a state
+  // required for the operation's execution.  For example, directory
+  // to be deleted may be non-empty, an rmdir operation is applied to
+  // a non-directory, etc.
+  //
+  // A litmus test that may help a service implementor in deciding
+  // between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
+  //  (a) Use UNAVAILABLE if the client can retry just the failing call.
+  //  (b) Use ABORTED if the client should retry at a higher-level
+  //      (e.g., restarting a read-modify-write sequence).
+  //  (c) Use FAILED_PRECONDITION if the client should not retry until
+  //      the system state has been explicitly fixed.  E.g., if an "rmdir"
+  //      fails because the directory is non-empty, FAILED_PRECONDITION
+  //      should be returned since the client should not retry unless
+  //      they have first fixed up the directory by deleting files from it.
+  FAILED_PRECONDITION = 9,
+
+  // The operation was aborted, typically due to a concurrency issue
+  // like sequencer check failures, transaction aborts, etc.
+  //
+  // See litmus test above for deciding between FAILED_PRECONDITION,
+  // ABORTED, and UNAVAILABLE.
+  ABORTED = 10,
+
+  // Operation was attempted past the valid range.  E.g., seeking or
+  // reading past end of file.
+  //
+  // Unlike INVALID_ARGUMENT, this error indicates a problem that may
+  // be fixed if the system state changes. For example, a 32-bit file
+  // system will generate INVALID_ARGUMENT if asked to read at an
+  // offset that is not in the range [0,2^32-1], but it will generate
+  // OUT_OF_RANGE if asked to read from an offset past the current
+  // file size.
+  OUT_OF_RANGE = 11,
+
+  // Operation is not implemented or not supported/enabled in this service.
+  UNIMPLEMENTED = 12,
+
+  // Internal errors.  Means some invariants expected by underlying
+  // system has been broken.  If you see one of these errors,
+  // something is very broken.
+  INTERNAL = 13,
+
+  // The service is currently unavailable.  This is a most likely a
+  // transient condition and may be corrected by retrying with
+  // a backoff.
+  //
+  // See litmus test above for deciding between FAILED_PRECONDITION,
+  // ABORTED, and UNAVAILABLE.
+  UNAVAILABLE = 14,
+
+  // Unrecoverable data loss or corruption.
+  DATA_LOSS = 15,
+};
+
+
+}  // namespace error
+
+
+// A Status is a combination of an error code and a string message (for non-OK
+// error codes).
+class Status {
+ public:
+  // Creates an OK status
+  Status();
+
+  // Make a Status from the specified error and message.
+  Status(::util::error::Code error, const std::string& error_message);
+
+  Status(const Status& other);
+  Status& operator=(const Status& other);
+
+  // Some pre-defined Status objects
+  static const Status& OK;  // Identical to 0-arg constructor
+  static const Status& CANCELLED;
+  static const Status& UNKNOWN;
+
+  // Accessors
+  bool ok() const {
+    return code_ == ::util::error::OK;
+  }
+  int error_code() const {
+    return code_;
+  }
+  ::util::error::Code CanonicalCode() const {
+    return code_;
+  }
+  const std::string& error_message() const {
+    return message_;
+  }
+
+  bool operator==(const Status& x) const;
+  bool operator!=(const Status& x) const;
+
+  // NoOp
+  void IgnoreError() const {
+  }
+
+  std::string ToString() const;
+
+ private:
+  ::util::error::Code code_;
+  std::string message_;
+};
+
+inline bool Status::operator==(const Status& other) const {
+  return (this->code_ == other.code_) && (this->message_ == other.message_);
+}
+
+inline bool Status::operator!=(const Status& other) const {
+  return !(*this == other);
+}
+
+extern std::string ErrorCodeString(util::error::Code error);
+
+extern ::std::ostream& operator<<(::std::ostream& os,
+                                  ::util::error::Code code);
+extern ::std::ostream& operator<<(::std::ostream& os, const Status& other);
+
+// Returns an OK status, equivalent to a default constructed instance.
+inline Status OkStatus() { return Status(); }
+
+}  // namespace util
+
+#endif  // TINK_UTIL_STATUS_H_
diff --git a/cc/util/statusor.h b/cc/util/statusor.h
new file mode 100644
index 0000000000000000000000000000000000000000..b8e889df76f7edee9cbcce326ee5951921eab8dc
--- /dev/null
+++ b/cc/util/statusor.h
@@ -0,0 +1,141 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// 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 TINK_UTIL_STATUSOR_H_
+#define TINK_UTIL_STATUSOR_H_
+
+#include <utility>
+
+#include "cc/util/status.h"
+
+namespace util {
+
+// A StatusOr holds a Status (in the case of an error), or a value T.
+template <typename T>
+class StatusOr {
+ public:
+  // Has status UNKNOWN.
+  inline StatusOr();
+
+  // Builds from a non-OK status. Crashes if an OK status is specified.
+  inline StatusOr(const ::util::Status& status);  // NOLINT
+
+  // Builds from the specified value.
+  inline StatusOr(const T& value);  // NOLINT
+  inline StatusOr(T&& value);       // NOLINT
+
+  // Copy constructor.
+  inline StatusOr(const StatusOr& other);
+
+  // Move constructor.
+  inline StatusOr(StatusOr&& other);
+
+  // Conversion copy constructor, T must be copy constructible from U.
+  template <typename U>
+  inline StatusOr(const StatusOr<U>& other);
+
+  // Assignment operator.
+  inline const StatusOr& operator=(const StatusOr& other);
+
+  // Conversion assignment operator, T must be assignable from U
+  template <typename U>
+  inline const StatusOr& operator=(const StatusOr<U>& other);
+
+  // Accessors.
+  inline const ::util::Status& status() const {
+    return status_;
+  }
+
+  // Shorthand for status().ok().
+  inline bool ok() const {
+    return status_.ok();
+  }
+
+  // Returns value or crashes if ok() is false.
+  inline const T& ValueOrDie() const {
+    // CHECK(ok()) << "Attempting to fetch value of non-OK StatusOr";
+    return value_;
+  }
+  inline T& ValueOrDie() {
+    // CHECK(ok()) << "Attempting to fetch value of non-OK StatusOr";
+    return value_;
+  }
+
+  template <typename U>
+  friend class StatusOr;
+
+ private:
+  Status status_;
+  T value_;
+};
+
+// Implementation.
+
+template <typename T>
+inline StatusOr<T>::StatusOr() : status_(::util::error::UNKNOWN, "") {
+}
+
+template <typename T>
+inline StatusOr<T>::StatusOr(const ::util::Status& status) : status_(status) {
+  // CHECK(!status.ok()) << "::util::OkStatus() is not a valid argument to StatusOr";
+}
+
+template <typename T>
+inline StatusOr<T>::StatusOr(const T& value) : value_(value) {
+}
+
+template <typename T>
+inline StatusOr<T>::StatusOr(T&& value) : value_(std::move(value)) {
+}
+
+template <typename T>
+inline StatusOr<T>::StatusOr(const StatusOr& other)
+    : status_(other.status_), value_(other.value_) {
+}
+
+template <typename T>
+inline StatusOr<T>::StatusOr(StatusOr&& other)
+    : status_(other.status_), value_(std::move(other.value_)) {
+}
+
+template <typename T>
+template <typename U>
+inline StatusOr<T>::StatusOr(const StatusOr<U>& other)
+    : status_(other.status_), value_(other.value_) {
+}
+
+template <typename T>
+inline const StatusOr<T>& StatusOr<T>::operator=(const StatusOr& other) {
+  status_ = other.status_;
+  if (status_.ok()) {
+    value_ = other.value_;
+  }
+  return *this;
+}
+
+template <typename T>
+template <typename U>
+inline const StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) {
+  status_ = other.status_;
+  if (status_.ok()) {
+    value_ = other.value_;
+  }
+  return *this;
+}
+
+}  // namespace util
+
+#endif  // TINK_UTIL_STATUSOR_H_