34 #include <boost/lexical_cast.hpp>
37 #define ENSURE_PRIVATE_KEY_LOADED(key) \
39 if ((key) == nullptr) \
40 NDN_THROW(Error("Private key has not been loaded yet")); \
43 #define ENSURE_PRIVATE_KEY_NOT_LOADED(key) \
45 if ((key) != nullptr) \
46 NDN_THROW(Error("Private key has already been loaded")); \
56 #if OPENSSL_VERSION_NUMBER < 0x1010000fL
57 static bool isInitialized =
false;
59 OpenSSL_add_all_algorithms();
62 #endif // OPENSSL_VERSION_NUMBER < 0x1010000fL
74 EVP_PKEY*
key =
nullptr;
76 #if OPENSSL_VERSION_NUMBER < 0x1010100fL
82 : m_impl(make_unique<Impl>())
112 return static_cast<size_t>(EVP_PKEY_bits(m_impl->key));
114 #if OPENSSL_VERSION_NUMBER >= 0x1010100fL
116 EVP_PKEY_get_raw_private_key(m_impl->key,
nullptr, &nBytes);
119 return m_impl->keySize;
132 boost::lexical_cast<std::string>(
getKeyType())));
134 const uint8_t*
buf =
nullptr;
136 #if OPENSSL_VERSION_NUMBER >= 0x1010000fL
137 buf = EVP_PKEY_get0_hmac(m_impl->key, &len);
139 const auto* octstr =
reinterpret_cast<ASN1_OCTET_STRING*
>(EVP_PKEY_get0(m_impl->key));
141 len = octstr->length;
161 pkeyType = EVP_PKEY_HMAC;
164 NDN_THROW(std::invalid_argument(
"Unsupported key type " + boost::lexical_cast<std::string>(type)));
168 #if OPENSSL_VERSION_NUMBER >= 0x1010100fL
169 EVP_PKEY_new_raw_private_key(pkeyType,
nullptr,
buf, size);
171 EVP_PKEY_new_mac_key(pkeyType,
nullptr,
buf,
static_cast<int>(size));
173 if (m_impl->key ==
nullptr)
176 #if OPENSSL_VERSION_NUMBER < 0x1010100fL
177 m_impl->keySize = size * 8;
187 if (d2i_AutoPrivateKey(&m_impl->key, &
buf,
static_cast<long>(size)) ==
nullptr)
218 BOOST_ASSERT(std::strlen(pw) == pwLen);
226 if (d2i_PKCS8PrivateKey_bio(membio, &m_impl->key,
nullptr,
const_cast<char*
>(pw)) ==
nullptr)
233 BOOST_ASSERT(size >= 0);
235 return (*cb)(
buf,
static_cast<size_t>(size), rwflag);
251 m_impl->key = d2i_PKCS8PrivateKey_bio(membio,
nullptr,
nullptr,
nullptr);
253 if (m_impl->key ==
nullptr)
346 uint8_t* pkcs8 =
nullptr;
347 int len = i2d_PUBKEY(m_impl->key, &pkcs8);
351 auto result = make_shared<Buffer>(pkcs8, len);
367 return rsaDecrypt(cipherText, cipherLen);
374 PrivateKey::getEvpPkey()
const
380 PrivateKey::toPkcs1()
const
386 if (!i2d_PrivateKey_bio(membio, m_impl->key))
387 NDN_THROW(Error(
"Cannot convert key to PKCS #1 format"));
389 auto buffer = make_shared<Buffer>(BIO_pending(membio));
390 if (!membio.read(buffer->data(), buffer->size()))
391 NDN_THROW(Error(
"Read error during PKCS #1 conversion"));
397 PrivateKey::toPkcs8(
const char* pw,
size_t pwLen)
const
399 BOOST_ASSERT(std::strlen(pw) == pwLen);
403 detail::Bio membio(BIO_s_mem());
404 if (!i2d_PKCS8PrivateKey_bio(membio, m_impl->key, EVP_aes_256_cbc(),
nullptr, 0,
405 nullptr,
const_cast<char*
>(pw)))
406 NDN_THROW(Error(
"Cannot convert key to PKCS #8 format"));
408 auto buffer = make_shared<Buffer>(BIO_pending(membio));
409 if (!membio.read(buffer->data(), buffer->size()))
410 NDN_THROW(Error(
"Read error during PKCS #8 conversion"));
416 PrivateKey::toPkcs8(PasswordCallback pwCallback)
const
421 detail::Bio membio(BIO_s_mem());
422 if (!i2d_PKCS8PrivateKey_bio(membio, m_impl->key, EVP_aes_256_cbc(),
nullptr, 0,
424 NDN_THROW(Error(
"Cannot convert key to PKCS #8 format"));
426 auto buffer = make_shared<Buffer>(BIO_pending(membio));
427 if (!membio.read(buffer->data(), buffer->size()))
428 NDN_THROW(Error(
"Read error during PKCS #8 conversion"));
434 PrivateKey::rsaDecrypt(
const uint8_t* cipherText,
size_t cipherLen)
const
436 detail::EvpPkeyCtx ctx(m_impl->key);
438 if (EVP_PKEY_decrypt_init(ctx) <= 0)
439 NDN_THROW(Error(
"Failed to initialize decryption context"));
441 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0)
442 NDN_THROW(Error(
"Failed to set padding"));
446 if (EVP_PKEY_decrypt(ctx,
nullptr, &outlen, cipherText, cipherLen) <= 0)
447 NDN_THROW(Error(
"Failed to estimate output length"));
449 auto out = make_shared<Buffer>(outlen);
450 if (EVP_PKEY_decrypt(ctx, out->data(), &outlen, cipherText, cipherLen) <= 0)
451 NDN_THROW(Error(
"Failed to decrypt ciphertext"));
457 unique_ptr<PrivateKey>
458 PrivateKey::generateRsaKey(uint32_t keySize)
460 detail::EvpPkeyCtx kctx(EVP_PKEY_RSA);
462 if (EVP_PKEY_keygen_init(kctx) <= 0)
463 NDN_THROW(PrivateKey::Error(
"Failed to initialize RSA keygen context"));
465 if (EVP_PKEY_CTX_set_rsa_keygen_bits(kctx,
static_cast<int>(keySize)) <= 0)
466 NDN_THROW(PrivateKey::Error(
"Failed to set RSA key length"));
468 auto privateKey = make_unique<PrivateKey>();
469 if (EVP_PKEY_keygen(kctx, &privateKey->m_impl->key) <= 0)
470 NDN_THROW(PrivateKey::Error(
"Failed to generate RSA key"));
475 unique_ptr<PrivateKey>
476 PrivateKey::generateEcKey(uint32_t keySize)
478 detail::EvpPkeyCtx pctx(EVP_PKEY_EC);
480 if (EVP_PKEY_paramgen_init(pctx) <= 0)
481 NDN_THROW(PrivateKey::Error(
"Failed to initialize EC paramgen context"));
486 ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_secp224r1);
489 ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1);
492 ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_secp384r1);
495 ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_secp521r1);
501 NDN_THROW(PrivateKey::Error(
"Failed to set EC curve"));
504 if (EVP_PKEY_paramgen(pctx, ¶ms.key) <= 0)
505 NDN_THROW(PrivateKey::Error(
"Failed to generate EC parameters"));
507 detail::EvpPkeyCtx kctx(params.key);
508 if (EVP_PKEY_keygen_init(kctx) <= 0)
509 NDN_THROW(PrivateKey::Error(
"Failed to initialize EC keygen context"));
511 auto privateKey = make_unique<PrivateKey>();
512 if (EVP_PKEY_keygen(kctx, &privateKey->m_impl->key) <= 0)
513 NDN_THROW(PrivateKey::Error(
"Failed to generate EC key"));
518 unique_ptr<PrivateKey>
519 PrivateKey::generateHmacKey(uint32_t keySize)
521 std::vector<uint8_t> rawKey(keySize / 8);
524 auto privateKey = make_unique<PrivateKey>();
526 privateKey->loadRaw(
KeyType::HMAC, rawKey.data(), rawKey.size());
528 catch (
const PrivateKey::Error&) {
529 NDN_THROW(PrivateKey::Error(
"Failed to generate HMAC key"));
535 unique_ptr<PrivateKey>
541 return PrivateKey::generateRsaKey(rsaParams.
getKeySize());
545 return PrivateKey::generateEcKey(ecParams.
getKeySize());
549 return PrivateKey::generateHmacKey(hmacParams.
getKeySize());
552 NDN_THROW(std::invalid_argument(
"Unsupported key type " +
553 boost::lexical_cast<std::string>(keyParams.
getKeyType())));