Kagome
Polkadot Runtime Engine in C++17
key_file_storage.cpp
Go to the documentation of this file.
1 
7 
8 #include "common/hexutil.hpp"
10 
13  switch (e) {
14  case E::WRONG_KEYFILE_NAME:
15  return "specified file name is not a valid key file";
16  case E::NOT_REGULAR_FILE:
17  return "provided key file is not regular";
18  case E::FAILED_OPEN_FILE:
19  return "failed to open key file for reading";
20  case E::FILE_DOESNT_EXIST:
21  return "key file doesn't exist";
22  case E::INVALID_FILE_FORMAT:
23  return "specified key file is invalid";
24  case E::INCONSISTENT_KEYFILE:
25  return "key file is inconsistent, public key != derived public key";
26  case E::KEYS_PATH_IS_NOT_DIRECTORY:
27  return "specified key storage directory path is not a directory";
28  case E::FAILED_CREATE_KEYS_DIRECTORY:
29  return "failed to create key storage directory";
30  }
31  return "unknown KeyFileStorage error";
32 }
33 
34 namespace kagome::crypto {
35 
36  using common::Buffer;
37 
38  outcome::result<std::unique_ptr<KeyFileStorage>> KeyFileStorage::createAt(
39  Path keystore_path) {
40  std::unique_ptr<KeyFileStorage> kfs{new KeyFileStorage(keystore_path)};
41  OUTCOME_TRY(kfs->initialize());
42  return kfs;
43  }
44 
46  : keystore_path_{std::move(keystore_path)},
47  logger_{log::createLogger("KeyFileStorage", "crypto_store")} {}
48 
49  outcome::result<std::pair<KeyTypeId, Buffer>>
50  KeyFileStorage::parseKeyFileName(std::string_view file_name) const {
51  if (file_name.size() < 4) {
53  }
54 
55  auto key_type_str = file_name.substr(0, 4);
56  auto key_type = decodeKeyTypeIdFromStr(key_type_str);
57  if (!isSupportedKeyType(key_type)) {
58  logger_->warn(
59  "key type <ascii: {}, hex: {:08x}> is not officially supported",
60  key_type_str,
61  key_type);
62  }
63  auto public_key_hex = file_name.substr(4);
64 
65  OUTCOME_TRY(public_key, Buffer::fromHex(public_key_hex));
66 
67  return {key_type, public_key};
68  }
69 
71  KeyTypeId key_type, gsl::span<const uint8_t> public_key) const {
72  auto &&key_type_str = encodeKeyTypeIdToStr(key_type);
73  auto &&public_key_hex = common::hex_lower(public_key);
74 
75  return keystore_path_ / (key_type_str + public_key_hex);
76  }
77 
78  outcome::result<void> KeyFileStorage::saveKeyPair(
79  KeyTypeId type,
80  gsl::span<const uint8_t> public_key,
81  gsl::span<const uint8_t> seed) const {
82  auto &&path = composeKeyPath(type, public_key);
83  OUTCOME_TRY(saveKeyHexAtPath(seed, path));
84  SL_TRACE(logger_,
85  "Saving keypair (public: {}) to {}",
86  common::hex_lower(public_key),
87  path.native());
88  return outcome::success();
89  }
90 
91  outcome::result<void> KeyFileStorage::initialize() {
92  boost::system::error_code ec{};
93  bool does_exist = boost::filesystem::exists(keystore_path_, ec);
94  if (ec and ec != boost::system::errc::no_such_file_or_directory) {
95  logger_->error("Error initializing key storage: {}", ec.message());
96  return outcome::failure(ec);
97  }
98  if (does_exist) {
99  // check whether specified path is a directory
100  if (not boost::filesystem::is_directory(keystore_path_, ec)) {
102  }
103  if (ec) {
104  logger_->error("Error scanning key storage: {}", ec.message());
105  return outcome::failure(ec);
106  }
107  } else {
108  // try create directory
109  if (not boost::filesystem::create_directories(keystore_path_, ec)) {
111  }
112  if (ec) {
113  logger_->error("Error creating keystore dir: {}", ec.message());
114  return outcome::failure(ec);
115  }
116  }
117 
118  return outcome::success();
119  }
120 
121  outcome::result<std::string> KeyFileStorage::loadFileContent(
122  const Path &file_path) const {
123  if (!boost::filesystem::exists(file_path)) {
125  }
126 
127  std::ifstream file;
128 
129  file.open(file_path.string(), std::ios::in | std::ios::binary);
130  if (!file.is_open()) {
132  }
133 
134  std::string content;
135  file >> content;
136  SL_TRACE(logger_, "Loaded seed {} from {}", content, file_path.native());
137  return content;
138  }
139 
140  outcome::result<void> KeyFileStorage::saveKeyHexAtPath(
141  gsl::span<const uint8_t> private_key,
142  const KeyFileStorage::Path &path) const {
143  std::ofstream file;
144  file.open(path.native(), std::ios::out | std::ios::trunc);
145  if (!file.is_open()) {
147  }
148  auto hex = common::hex_lower_0x(private_key);
149  file << hex;
150  SL_TRACE(logger_, "Saving key to {}", path.native());
151  return outcome::success();
152  }
153 
154  outcome::result<std::vector<Buffer>> KeyFileStorage::collectPublicKeys(
155  KeyTypeId type) const {
156  namespace fs = boost::filesystem;
157 
158  boost::system::error_code ec{};
159 
160  std::vector<Buffer> keys;
161 
162  fs::directory_iterator it{keystore_path_, ec}, end{};
163  if (ec) {
164  logger_->error("Error scanning keystore: {}", ec.message());
166  }
167  for (; it != end; ++it) {
168  if (!fs::is_regular_file(*it)) {
169  continue;
170  }
171  auto info = parseKeyFileName(it->path().filename().string());
172  if (!info) {
173  continue;
174  }
175  auto &[id, pk] = info.value();
176 
177  if (id == type) {
178  keys.push_back(pk);
179  }
180  }
181  return keys;
182  }
183 
184  outcome::result<std::optional<Buffer>> KeyFileStorage::searchForSeed(
185  KeyTypeId type, gsl::span<const uint8_t> public_key_bytes) const {
186  auto key_path = composeKeyPath(type, public_key_bytes);
187  namespace fs = boost::filesystem;
188  boost::system::error_code ec{};
189 
190  if (not fs::exists(key_path, ec)) {
191  return std::nullopt;
192  }
193  OUTCOME_TRY(content, loadFileContent(key_path));
194  OUTCOME_TRY(seed_bytes, common::unhexWith0x(content));
195  return Buffer{std::move(seed_bytes)};
196  }
197 
198 } // namespace kagome::crypto
static outcome::result< SLBuffer > fromHex(std::string_view hex)
Construct SLBuffer from hex string.
Definition: buffer.hpp:177
Class represents arbitrary (including empty) byte buffer.
Definition: buffer.hpp:29
outcome::result< void > initialize()
std::string hex_lower(const gsl::span< const uint8_t > bytes) noexcept
Converts bytes to hex representation.
Definition: hexutil.cpp:52
outcome::result< std::pair< KeyTypeId, Buffer > > parseKeyFileName(std::string_view file_name) const
outcome::result< std::vector< uint8_t > > unhexWith0x(std::string_view hex_with_prefix)
Unhex hex-string with 0x in the begining.
Definition: hexutil.cpp:89
OUTCOME_CPP_DEFINE_CATEGORY(kagome::crypto, KeyFileStorage::Error, e)
outcome::result< std::vector< Buffer > > collectPublicKeys(KeyTypeId type) const
outcome::result< void > saveKeyPair(KeyTypeId type, gsl::span< const uint8_t > public_key, gsl::span< const uint8_t > seed) const
uint32_t KeyTypeId
Key type identifier.
Definition: key_type.hpp:21
SLBuffer< std::numeric_limits< size_t >::max()> Buffer
Definition: buffer.hpp:244
outcome::result< std::string > loadFileContent(const Path &file_path) const
std::string hex_lower_0x(gsl::span< const uint8_t > bytes) noexcept
Converts bytes to hex representation with prefix 0x.
Definition: hexutil.cpp:58
outcome::result< void > saveKeyHexAtPath(gsl::span< const uint8_t > private_key, const Path &path) const
std::string encodeKeyTypeIdToStr(KeyTypeId key_type_id)
makes string representation of KeyTypeId
Definition: key_type.cpp:29
Path composeKeyPath(KeyTypeId key_type, gsl::span< const uint8_t > public_key) const
static outcome::result< std::unique_ptr< KeyFileStorage > > createAt(Path keystore_path)
Logger createLogger(const std::string &tag)
Definition: logger.cpp:112
outcome::result< std::optional< Buffer > > searchForSeed(KeyTypeId type, gsl::span< const uint8_t > public_key_bytes) const
bool isSupportedKeyType(KeyTypeId k)
checks whether key type value is supported
Definition: key_type.cpp:14
boost::filesystem::path Path
KeyFileStorage(Path keystore_path)
KeyTypeId decodeKeyTypeIdFromStr(std::string_view str)
restores KeyTypeId from its string representation
Definition: key_type.cpp:35