1 // Copyright 2019 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 /////////////////////////////////////////////////////////////////////////////// 16 17 #ifndef TINK_PYTHON_TINK_CC_CC_KEY_MANAGER_H_ 18 #define TINK_PYTHON_TINK_CC_CC_KEY_MANAGER_H_ 19 20 #include <string> 21 #include <utility> 22 23 #include "absl/memory/memory.h" 24 #include "absl/status/status.h" 25 #include "absl/strings/str_cat.h" 26 #include "pybind11/pybind11.h" 27 #include "tink/key_manager.h" 28 #include "tink/registry.h" 29 #include "tink/util/status.h" 30 #include "tink/util/statusor.h" 31 #include "tink/cc/pybind/tink_exception.h" 32 33 namespace crypto { 34 namespace tink { 35 36 using pybind11::google_tink::TinkException; 37 38 /** 39 * CcKeyManager is a thin wrapper of KeyManager in 40 * third_party/tink/cc/key_manager.h 41 * It only implements the methods currently needed in Python, and slightly 42 * changes the interface to ease usage of pybind. 43 */ 44 template<class P> 45 class CcKeyManager { 46 public: 47 // Returns a key manager from the registry. GetFromCcRegistry(const std::string & type_url)48 static std::unique_ptr<CcKeyManager<P>> GetFromCcRegistry( 49 const std::string& type_url) { 50 auto key_manager_result = Registry::get_key_manager<P>(type_url); 51 if (!key_manager_result.ok()) { 52 throw TinkException( 53 util::Status(absl::StatusCode::kFailedPrecondition, 54 absl::StrCat("No manager for key type '", type_url, 55 "' found in the registry."))); 56 } 57 return absl::make_unique<CcKeyManager<P>>(key_manager_result.value()); 58 } 59 CcKeyManager(const KeyManager<P> * key_manager)60 explicit CcKeyManager(const KeyManager<P>* key_manager) 61 : key_manager_(key_manager) {} 62 63 // Constructs an instance of P for the given 'key_data'. GetPrimitive(const std::string & serialized_key_data)64 std::unique_ptr<P> GetPrimitive( 65 const std::string& serialized_key_data) const { 66 google::crypto::tink::KeyData key_data; 67 key_data.ParseFromString(serialized_key_data); 68 util::StatusOr<std::unique_ptr<P>> result = 69 key_manager_->GetPrimitive(key_data); 70 if (!result.ok()) { 71 throw TinkException(result.status()); 72 } 73 return *std::move(result); 74 } 75 76 // Creates a new random key, based on the specified 'key_format'. NewKeyData(const std::string & serialized_key_template)77 pybind11::bytes NewKeyData(const std::string& serialized_key_template) const { 78 google::crypto::tink::KeyTemplate key_template; 79 key_template.ParseFromString(serialized_key_template); 80 if (key_manager_->get_key_type() != key_template.type_url()) { 81 throw TinkException( 82 util::Status(absl::StatusCode::kInvalidArgument, 83 absl::StrCat("Key type '", key_template.type_url(), 84 "' is not supported by this manager."))); 85 } 86 87 auto key_data = 88 key_manager_->get_key_factory().NewKeyData(key_template.value()); 89 if (!key_data.ok()) { 90 throw TinkException(key_data.status()); 91 } 92 return pybind11::bytes(key_data.value()->SerializeAsString()); 93 } 94 95 // Returns public key data extracted from the given private_key_data. GetPublicKeyData(const std::string & serialized_private_key_data)96 pybind11::bytes GetPublicKeyData( 97 const std::string& serialized_private_key_data) const { 98 const PrivateKeyFactory* factory = dynamic_cast<const PrivateKeyFactory*>( 99 &key_manager_->get_key_factory()); 100 if (factory == nullptr) { 101 throw TinkException(util::Status( 102 absl::StatusCode::kInvalidArgument, 103 absl::StrCat("KeyManager for type '", key_manager_->get_key_type(), 104 "' does not have " 105 "a PrivateKeyFactory."))); 106 } 107 108 google::crypto::tink::KeyData private_key_data; 109 private_key_data.ParseFromString(serialized_private_key_data); 110 auto result = factory->GetPublicKeyData(private_key_data.value()); 111 if (!result.ok()) { 112 throw TinkException(result.status()); 113 } 114 return pybind11::bytes(result.value()->SerializeAsString()); 115 } 116 117 // Returns the type_url identifying the key type handled by this manager. KeyType()118 std::string KeyType() const { return key_manager_->get_key_type(); } 119 120 private: 121 const KeyManager<P>* key_manager_; 122 }; 123 124 } // namespace tink 125 } // namespace crypto 126 #endif // TINK_PYTHON_TINK_CC_CC_KEY_MANAGER_H_ 127