Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
crypto.cc
1 #include "crypto.h"
2 
3 #include <array>
4 #include <iostream>
5 
6 #include <sodium.h>
7 #include <boost/algorithm/hex.hpp>
8 #include <boost/scoped_array.hpp>
9 
10 #include "libaktualizr/types.h"
11 #include "logging/logging.h"
12 #include "openssl_compat.h"
13 #include "utilities/utils.h"
14 
15 PublicKey::PublicKey(const boost::filesystem::path &path) : value_(Utils::readFile(path)) {
16  type_ = Crypto::IdentifyRSAKeyType(value_);
17 }
18 
19 PublicKey::PublicKey(Json::Value uptane_json) {
20  if (!uptane_json["keytype"].isString()) {
21  type_ = KeyType::kUnknown;
22  return;
23  }
24  if (!uptane_json["keyval"].isObject()) {
25  type_ = KeyType::kUnknown;
26  return;
27  }
28 
29  if (!uptane_json["keyval"]["public"].isString()) {
30  type_ = KeyType::kUnknown;
31  return;
32  }
33 
34  std::string keytype = uptane_json["keytype"].asString();
35  std::string keyvalue = uptane_json["keyval"]["public"].asString();
36 
37  std::transform(keytype.begin(), keytype.end(), keytype.begin(), ::tolower);
38 
39  KeyType type;
40  if (keytype == "ed25519") {
41  type = KeyType::kED25519;
42  } else if (keytype == "rsa") {
43  type = Crypto::IdentifyRSAKeyType(keyvalue);
44  if (type == KeyType::kUnknown) {
45  LOG_WARNING << "Couldn't identify length of RSA key";
46  }
47  } else {
48  type = KeyType::kUnknown;
49  }
50  type_ = type;
51  value_ = keyvalue;
52 }
53 
54 PublicKey::PublicKey(const std::string &value, KeyType type) : value_(value), type_(type) {
55  if (Crypto::IsRsaKeyType(type)) {
56  if (type != Crypto::IdentifyRSAKeyType(value)) {
57  std::logic_error("RSA key length is incorrect");
58  }
59  }
60 }
61 
62 bool PublicKey::VerifySignature(const std::string &signature, const std::string &message) const {
63  switch (type_) {
64  case KeyType::kED25519:
65  return Crypto::ED25519Verify(boost::algorithm::unhex(value_), Utils::fromBase64(signature), message);
66  case KeyType::kRSA2048:
67  case KeyType::kRSA3072:
68  case KeyType::kRSA4096:
69  return Crypto::RSAPSSVerify(value_, Utils::fromBase64(signature), message);
70  default:
71  return false;
72  }
73 }
74 
75 bool PublicKey::operator==(const PublicKey &rhs) const { return value_ == rhs.value_ && type_ == rhs.type_; }
76 Json::Value PublicKey::ToUptane() const {
77  Json::Value res;
78  switch (type_) {
79  case KeyType::kRSA2048:
80  case KeyType::kRSA3072:
81  case KeyType::kRSA4096:
82  res["keytype"] = "RSA";
83  break;
84  case KeyType::kED25519:
85  res["keytype"] = "ED25519";
86  break;
87  case KeyType::kUnknown:
88  res["keytype"] = "unknown";
89  break;
90  default:
91  throw std::range_error("Unknown key type in PublicKey::ToUptane");
92  }
93  res["keyval"]["public"] = value_;
94  return res;
95 }
96 
97 std::string PublicKey::KeyId() const {
98  std::string key_content = value_;
99  // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
100  boost::algorithm::trim_right_if(key_content, boost::algorithm::is_any_of("\n"));
101  std::string keyid = boost::algorithm::hex(Crypto::sha256digest(Utils::jsonToCanonicalStr(Json::Value(key_content))));
102  std::transform(keyid.begin(), keyid.end(), keyid.begin(), ::tolower);
103  return keyid;
104 }
105 
106 std::string Crypto::sha256digest(const std::string &text) {
107  std::array<unsigned char, crypto_hash_sha256_BYTES> sha256_hash{};
108  crypto_hash_sha256(sha256_hash.data(), reinterpret_cast<const unsigned char *>(text.c_str()), text.size());
109  return std::string(reinterpret_cast<char *>(sha256_hash.data()), crypto_hash_sha256_BYTES);
110 }
111 
112 std::string Crypto::sha512digest(const std::string &text) {
113  std::array<unsigned char, crypto_hash_sha512_BYTES> sha512_hash{};
114  crypto_hash_sha512(sha512_hash.data(), reinterpret_cast<const unsigned char *>(text.c_str()), text.size());
115  return std::string(reinterpret_cast<char *>(sha512_hash.data()), crypto_hash_sha512_BYTES);
116 }
117 
118 std::string Crypto::RSAPSSSign(ENGINE *engine, const std::string &private_key, const std::string &message) {
119  StructGuard<EVP_PKEY> key(nullptr, EVP_PKEY_free);
120  StructGuard<RSA> rsa(nullptr, RSA_free);
121  if (engine != nullptr) {
122  // TODO(OTA-2138): this call leaks memory somehow...
123  key.reset(ENGINE_load_private_key(engine, private_key.c_str(), nullptr, nullptr));
124 
125  if (key == nullptr) {
126  LOG_ERROR << "ENGINE_load_private_key failed with error " << ERR_error_string(ERR_get_error(), nullptr);
127  return std::string();
128  }
129 
130  rsa.reset(EVP_PKEY_get1_RSA(key.get()));
131  if (rsa == nullptr) {
132  LOG_ERROR << "EVP_PKEY_get1_RSA failed with error " << ERR_error_string(ERR_get_error(), nullptr);
133  return std::string();
134  }
135  } else {
136  StructGuard<BIO> bio(BIO_new_mem_buf(const_cast<char *>(private_key.c_str()), static_cast<int>(private_key.size())),
137  BIO_vfree);
138  key.reset(PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
139  if (key != nullptr) {
140  rsa.reset(EVP_PKEY_get1_RSA(key.get()));
141  }
142 
143  if (rsa == nullptr) {
144  LOG_ERROR << "PEM_read_bio_PrivateKey failed with error " << ERR_error_string(ERR_get_error(), nullptr);
145  return std::string();
146  }
147 
148 #if AKTUALIZR_OPENSSL_PRE_11
149  RSA_set_method(rsa.get(), RSA_PKCS1_SSLeay());
150 #else
151  RSA_set_method(rsa.get(), RSA_PKCS1_OpenSSL());
152 #endif
153  }
154 
155  const auto sign_size = static_cast<unsigned int>(RSA_size(rsa.get()));
156  boost::scoped_array<unsigned char> EM(new unsigned char[sign_size]);
157  boost::scoped_array<unsigned char> pSignature(new unsigned char[sign_size]);
158 
159  std::string digest = Crypto::sha256digest(message);
160  int status = RSA_padding_add_PKCS1_PSS(rsa.get(), EM.get(), reinterpret_cast<const unsigned char *>(digest.c_str()),
161  EVP_sha256(), -1 /* maximum salt length*/);
162  if (status == 0) {
163  LOG_ERROR << "RSA_padding_add_PKCS1_PSS failed with error " << ERR_error_string(ERR_get_error(), nullptr);
164  return std::string();
165  }
166 
167  /* perform digital signature */
168  status = RSA_private_encrypt(RSA_size(rsa.get()), EM.get(), pSignature.get(), rsa.get(), RSA_NO_PADDING);
169  if (status == -1) {
170  LOG_ERROR << "RSA_private_encrypt failed with error " << ERR_error_string(ERR_get_error(), nullptr);
171  return std::string();
172  }
173  std::string retval = std::string(reinterpret_cast<char *>(pSignature.get()), sign_size);
174  return retval;
175 }
176 
177 std::string Crypto::Sign(KeyType key_type, ENGINE *engine, const std::string &private_key, const std::string &message) {
178  if (key_type == KeyType::kED25519) {
179  return Crypto::ED25519Sign(boost::algorithm::unhex(private_key), message);
180  }
181  return Crypto::RSAPSSSign(engine, private_key, message);
182 }
183 
184 std::string Crypto::ED25519Sign(const std::string &private_key, const std::string &message) {
185  std::array<unsigned char, crypto_sign_BYTES> sig{};
186  crypto_sign_detached(sig.data(), nullptr, reinterpret_cast<const unsigned char *>(message.c_str()), message.size(),
187  reinterpret_cast<const unsigned char *>(private_key.c_str()));
188  return std::string(reinterpret_cast<char *>(sig.data()), crypto_sign_BYTES);
189 }
190 
191 bool Crypto::RSAPSSVerify(const std::string &public_key, const std::string &signature, const std::string &message) {
192  StructGuard<RSA> rsa(nullptr, RSA_free);
193  StructGuard<BIO> bio(BIO_new_mem_buf(const_cast<char *>(public_key.c_str()), static_cast<int>(public_key.size())),
194  BIO_vfree);
195  {
196  RSA *r = nullptr;
197  if (PEM_read_bio_RSA_PUBKEY(bio.get(), &r, nullptr, nullptr) == nullptr) {
198  LOG_ERROR << "PEM_read_bio_RSA_PUBKEY failed with error " << ERR_error_string(ERR_get_error(), nullptr);
199  return false;
200  }
201  rsa.reset(r);
202  }
203 
204 #if AKTUALIZR_OPENSSL_PRE_11
205  RSA_set_method(rsa.get(), RSA_PKCS1_SSLeay());
206 #else
207  RSA_set_method(rsa.get(), RSA_PKCS1_OpenSSL());
208 #endif
209 
210  const auto size = static_cast<unsigned int>(RSA_size(rsa.get()));
211  boost::scoped_array<unsigned char> pDecrypted(new unsigned char[size]);
212  /* now we will verify the signature
213  Start by a RAW decrypt of the signature
214  */
215  int status =
216  RSA_public_decrypt(static_cast<int>(signature.size()), reinterpret_cast<const unsigned char *>(signature.c_str()),
217  pDecrypted.get(), rsa.get(), RSA_NO_PADDING);
218  if (status == -1) {
219  LOG_ERROR << "RSA_public_decrypt failed with error " << ERR_error_string(ERR_get_error(), nullptr);
220  return false;
221  }
222 
223  std::string digest = Crypto::sha256digest(message);
224 
225  /* verify the data */
226  status = RSA_verify_PKCS1_PSS(rsa.get(), reinterpret_cast<const unsigned char *>(digest.c_str()), EVP_sha256(),
227  pDecrypted.get(), -2 /* salt length recovered from signature*/);
228 
229  return status == 1;
230 }
231 bool Crypto::ED25519Verify(const std::string &public_key, const std::string &signature, const std::string &message) {
232  if (public_key.size() < crypto_sign_PUBLICKEYBYTES || signature.size() < crypto_sign_BYTES) {
233  return false;
234  }
235  return crypto_sign_verify_detached(reinterpret_cast<const unsigned char *>(signature.c_str()),
236  reinterpret_cast<const unsigned char *>(message.c_str()), message.size(),
237  reinterpret_cast<const unsigned char *>(public_key.c_str())) == 0;
238 }
239 
240 bool Crypto::parseP12(BIO *p12_bio, const std::string &p12_password, std::string *out_pkey, std::string *out_cert,
241  std::string *out_ca) {
242 #if AKTUALIZR_OPENSSL_PRE_11
243  SSLeay_add_all_algorithms();
244 #endif
245  StructGuard<PKCS12> p12(d2i_PKCS12_bio(p12_bio, nullptr), PKCS12_free);
246  if (p12 == nullptr) {
247  LOG_ERROR << "Could not read from " << p12_bio << " file pointer";
248  return false;
249  }
250 
251  // use a lambda here because sk_X509_pop_free is a macro
252  auto stackx509_free = [](STACK_OF(X509) * stack) {
253  sk_X509_pop_free(stack, X509_free); // NOLINT
254  };
255 
256  StructGuard<EVP_PKEY> pkey(nullptr, EVP_PKEY_free);
257  StructGuard<X509> x509_cert(nullptr, X509_free);
258  StructGuard<STACK_OF(X509)> ca_certs(nullptr, stackx509_free);
259  {
260  EVP_PKEY *pk;
261  X509 *x509c = nullptr;
262  STACK_OF(X509) *cacs = nullptr;
263  if (PKCS12_parse(p12.get(), p12_password.c_str(), &pk, &x509c, &cacs) == 0) {
264  LOG_ERROR << "Could not parse file from " << p12_bio << " source pointer";
265  return false;
266  }
267  pkey.reset(pk);
268  x509_cert.reset(x509c);
269  ca_certs.reset(cacs);
270  }
271 
272  StructGuard<BIO> pkey_pem_sink(BIO_new(BIO_s_mem()), BIO_vfree);
273  if (pkey_pem_sink == nullptr) {
274  LOG_ERROR << "Could not open pkey buffer for writing";
275  return false;
276  }
277  PEM_write_bio_PrivateKey(pkey_pem_sink.get(), pkey.get(), nullptr, nullptr, 0, nullptr, nullptr);
278 
279  char *pkey_buf;
280  auto pkey_len = BIO_get_mem_data(pkey_pem_sink.get(), &pkey_buf); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
281  *out_pkey = std::string(pkey_buf, static_cast<size_t>(pkey_len));
282 
283  char *cert_buf;
284  size_t cert_len;
285  StructGuard<BIO> cert_sink(BIO_new(BIO_s_mem()), BIO_vfree);
286  if (cert_sink == nullptr) {
287  LOG_ERROR << "Could not open certificate buffer for writing";
288  return false;
289  }
290  PEM_write_bio_X509(cert_sink.get(), x509_cert.get());
291 
292  char *ca_buf;
293  size_t ca_len;
294  StructGuard<BIO> ca_sink(BIO_new(BIO_s_mem()), BIO_vfree);
295  if (ca_sink == nullptr) {
296  LOG_ERROR << "Could not open ca buffer for writing";
297  return false;
298  }
299  X509 *ca_cert = nullptr;
300  for (int i = 0; i < sk_X509_num(ca_certs.get()); i++) { // NOLINT
301  ca_cert = sk_X509_value(ca_certs.get(), i); // NOLINT
302  PEM_write_bio_X509(ca_sink.get(), ca_cert);
303  PEM_write_bio_X509(cert_sink.get(), ca_cert);
304  }
305  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
306  ca_len = static_cast<size_t>(BIO_get_mem_data(ca_sink.get(), &ca_buf));
307  *out_ca = std::string(ca_buf, ca_len);
308 
309  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
310  cert_len = static_cast<size_t>(BIO_get_mem_data(cert_sink.get(), &cert_buf));
311  *out_cert = std::string(cert_buf, cert_len);
312 
313  return true;
314 }
315 
316 bool Crypto::extractSubjectCN(const std::string &cert, std::string *cn) {
317  StructGuard<BIO> bio(BIO_new_mem_buf(const_cast<char *>(cert.c_str()), static_cast<int>(cert.size())), BIO_vfree);
318  StructGuard<X509> x(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr), X509_free);
319  if (x == nullptr) {
320  return false;
321  }
322 
323  int len = X509_NAME_get_text_by_NID(X509_get_subject_name(x.get()), NID_commonName, nullptr, 0);
324  if (len < 0) {
325  return false;
326  }
327  boost::scoped_array<char> buf(new char[len + 1]);
328  X509_NAME_get_text_by_NID(X509_get_subject_name(x.get()), NID_commonName, buf.get(), len + 1);
329  *cn = std::string(buf.get());
330  return true;
331 }
332 
333 StructGuard<EVP_PKEY> Crypto::generateRSAKeyPairEVP(KeyType key_type) {
334  int bits;
335  switch (key_type) {
336  case KeyType::kRSA2048:
337  bits = 2048;
338  break;
339  case KeyType::kRSA3072:
340  bits = 3072;
341  break;
342  case KeyType::kRSA4096:
343  bits = 4096;
344  break;
345  default:
346  return {nullptr, EVP_PKEY_free};
347  }
348 
349  int ret;
350 
351  ret = RAND_status();
352  if (ret != 1) { /* random generator has NOT been seeded with enough data */
353  ret = RAND_poll();
354  if (ret != 1) { /* seed data was NOT generated */
355  return {nullptr, EVP_PKEY_free};
356  }
357  }
358 
359  StructGuard<BIGNUM> bne(BN_new(), BN_free);
360  ret = BN_set_word(bne.get(), RSA_F4);
361  if (ret != 1) {
362  return {nullptr, EVP_PKEY_free};
363  }
364  StructGuard<RSA> rsa(RSA_new(), RSA_free);
365  ret = RSA_generate_key_ex(rsa.get(), bits, /* number of bits for the key - 2048 is a sensible value */
366  bne.get(), /* exponent - RSA_F4 is defined as 0x10001L */
367  nullptr); /* callback argument - not needed in this case */
368  if (ret != 1) {
369  return {nullptr, EVP_PKEY_free};
370  }
371 
372  StructGuard<EVP_PKEY> pkey(EVP_PKEY_new(), EVP_PKEY_free);
373  // release the rsa pointer here, pkey is the new owner
374  EVP_PKEY_assign_RSA(pkey.get(), rsa.release()); // NOLINT
375  return pkey;
376 }
377 
378 /**
379  * Generate a RSA keypair
380  * @param key_type Algorithm used to generate the key
381  * @param public_key Generated public part of key
382  * @param private_key Generated private part of key
383  * @return true if the keys are present at the end of this function (either they were created or existed already)
384  * false if key generation failed
385  */
386 bool Crypto::generateRSAKeyPair(KeyType key_type, std::string *public_key, std::string *private_key) {
387  int ret = 0;
388  StructGuard<EVP_PKEY> pkey = generateRSAKeyPairEVP(key_type);
389  if (pkey == nullptr) {
390  return false;
391  }
392 
393  char *pubkey_buf;
394  StructGuard<BIO> pubkey_sink(BIO_new(BIO_s_mem()), BIO_vfree);
395  if (pubkey_sink == nullptr) {
396  return false;
397  }
398  ret = PEM_write_bio_PUBKEY(pubkey_sink.get(), pkey.get());
399  if (ret != 1) {
400  return false;
401  }
402  auto pubkey_len = BIO_get_mem_data(pubkey_sink.get(), &pubkey_buf); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
403  *public_key = std::string(pubkey_buf, static_cast<size_t>(pubkey_len));
404 
405  char *privkey_buf;
406  StructGuard<BIO> privkey_sink(BIO_new(BIO_s_mem()), BIO_vfree);
407  if (privkey_sink == nullptr) {
408  return false;
409  }
410 
411  ret = PEM_write_bio_RSAPrivateKey(privkey_sink.get(), static_cast<RSA *>(EVP_PKEY_get0(pkey.get())), nullptr, nullptr,
412  0, nullptr, nullptr);
413  if (ret != 1) {
414  return false;
415  }
416  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
417  auto privkey_len = BIO_get_mem_data(privkey_sink.get(), &privkey_buf);
418  *private_key = std::string(privkey_buf, static_cast<size_t>(privkey_len));
419  return true;
420 }
421 
422 bool Crypto::generateEDKeyPair(std::string *public_key, std::string *private_key) {
423  std::array<unsigned char, crypto_sign_PUBLICKEYBYTES> pk{};
424  std::array<unsigned char, crypto_sign_SECRETKEYBYTES> sk{};
425  crypto_sign_keypair(pk.data(), sk.data());
426  *public_key = boost::algorithm::hex(std::string(reinterpret_cast<char *>(pk.data()), crypto_sign_PUBLICKEYBYTES));
427  // std::transform(public_key->begin(), public_key->end(), public_key->begin(), ::tolower);
428  *private_key = boost::algorithm::hex(std::string(reinterpret_cast<char *>(sk.data()), crypto_sign_SECRETKEYBYTES));
429  // std::transform(private_key->begin(), private_key->end(), private_key->begin(), ::tolower);
430  return true;
431 }
432 
433 bool Crypto::generateKeyPair(KeyType key_type, std::string *public_key, std::string *private_key) {
434  if (key_type == KeyType::kED25519) {
435  return Crypto::generateEDKeyPair(public_key, private_key);
436  }
437  return Crypto::generateRSAKeyPair(key_type, public_key, private_key);
438 }
439 
440 bool Crypto::IsRsaKeyType(KeyType type) {
441  switch (type) {
442  case KeyType::kRSA2048:
443  case KeyType::kRSA3072:
444  case KeyType::kRSA4096:
445  return true;
446  default:
447  return false;
448  }
449 }
450 KeyType Crypto::IdentifyRSAKeyType(const std::string &public_key_pem) {
451  StructGuard<BIO> bufio(BIO_new_mem_buf(reinterpret_cast<const void *>(public_key_pem.c_str()),
452  static_cast<int>(public_key_pem.length())),
453  BIO_vfree);
454  if (bufio.get() == nullptr) {
455  throw std::runtime_error("BIO_new_mem_buf failed");
456  }
457  StructGuard<::RSA> rsa(PEM_read_bio_RSA_PUBKEY(bufio.get(), nullptr, nullptr, nullptr), RSA_free);
458 
459  if (rsa.get() == nullptr) {
460  return KeyType::kUnknown;
461  }
462 
463  int key_length = RSA_size(rsa.get()) * 8;
464  // It is not clear from the OpenSSL documentation if RSA_size returns
465  // exactly 2048 or 4096, or if this can vary. For now we will assume that if
466  // OpenSSL has been asked to generate a 'N bit' key, RSA_size() will return
467  // exactly N
468  switch (key_length) {
469  case 2048:
470  return KeyType::kRSA2048;
471  case 3072:
472  return KeyType::kRSA3072;
473  case 4096:
474  return KeyType::kRSA4096;
475  default:
476  LOG_WARNING << "Weird key length:" << key_length;
477  return KeyType::kUnknown;
478  }
479 }
480 
481 MultiPartHasher::Ptr MultiPartHasher::create(Hash::Type hash_type) {
482  switch (hash_type) {
483  case Hash::Type::kSha256: {
484  return std::make_shared<MultiPartSHA256Hasher>();
485  }
486  case Hash::Type::kSha512: {
487  return std::make_shared<MultiPartSHA512Hasher>();
488  }
489  default: {
490  LOG_ERROR << "Unsupported type of hashing: " << Hash::TypeString(hash_type);
491  return nullptr;
492  }
493  }
494 }
495 
496 Hash Hash::generate(Type type, const std::string &data) {
497  std::string hash;
498 
499  switch (type) {
500  case Type::kSha256: {
501  hash = boost::algorithm::hex(Crypto::sha256digest(data));
502  break;
503  }
504  case Type::kSha512: {
505  hash = boost::algorithm::hex(Crypto::sha512digest(data));
506  break;
507  }
508  default: {
509  throw std::invalid_argument("Unsupported hash type");
510  }
511  }
512 
513  return Hash(type, hash);
514 }
515 
516 Hash::Hash(const std::string &type, const std::string &hash) : hash_(boost::algorithm::to_upper_copy(hash)) {
517  if (type == "sha512") {
518  type_ = Hash::Type::kSha512;
519  } else if (type == "sha256") {
520  type_ = Hash::Type::kSha256;
521  } else {
522  type_ = Hash::Type::kUnknownAlgorithm;
523  }
524 }
525 
526 Hash::Hash(Type type, const std::string &hash) : type_(type), hash_(boost::algorithm::to_upper_copy(hash)) {}
527 
528 bool Hash::operator==(const Hash &other) const { return type_ == other.type_ && hash_ == other.hash_; }
529 
530 std::string Hash::TypeString(Type type) {
531  switch (type) {
532  case Type::kSha256:
533  return "sha256";
534  case Type::kSha512:
535  return "sha512";
536  default:
537  return "unknown";
538  }
539 }
540 
541 std::string Hash::TypeString() const { return TypeString(type_); }
542 
543 Hash::Type Hash::type() const { return type_; }
544 
545 std::ostream &operator<<(std::ostream &os, const Hash &h) {
546  os << "Hash: " << h.hash_;
547  return os;
548 }
General data structures.
Definition: types.h:215
Json::Value ToUptane() const
Uptane Json representation of this public key.
Definition: crypto.cc:76
bool VerifySignature(const std::string &signature, const std::string &message) const
Verify a signature using this public key.
Definition: crypto.cc:62
Definition: utils.h:13
The Hash class The hash of a file or Uptane metadata.
Definition: types.h:157
static bool generateRSAKeyPair(KeyType key_type, std::string *public_key, std::string *private_key)
Generate a RSA keypair.
Definition: crypto.cc:386