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