blob: 570c18c0a6ad533bdec5497503fd5c11a37266ca [file] [log] [blame]
Yingdi Yu202a2e92015-07-12 16:49:25 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Luca Keidel941fd8c2017-07-24 15:21:22 +02002/*
Davide Pesavento923ba442019-02-12 22:00:38 -05003 * Copyright (c) 2013-2019 Regents of the University of California.
Yingdi Yu202a2e92015-07-12 16:49:25 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
Davide Pesavento7e780642018-11-24 15:51:34 -050022#include "ndn-cxx/security/transform/private-key.hpp"
23#include "ndn-cxx/security/transform/base64-decode.hpp"
24#include "ndn-cxx/security/transform/base64-encode.hpp"
25#include "ndn-cxx/security/transform/buffer-source.hpp"
26#include "ndn-cxx/security/transform/stream-sink.hpp"
27#include "ndn-cxx/security/transform/stream-source.hpp"
Junxiao Shi24c5a002018-12-12 04:47:15 +000028#include "ndn-cxx/security/impl/openssl-helper.hpp"
Davide Pesavento7e780642018-11-24 15:51:34 -050029#include "ndn-cxx/security/key-params.hpp"
30#include "ndn-cxx/encoding/buffer-stream.hpp"
Laqin Fan0fe72ea2019-05-22 16:42:59 -050031#include "ndn-cxx/util/random.hpp"
Yingdi Yu202a2e92015-07-12 16:49:25 -070032
Davide Pesaventof45fa212017-09-14 17:23:56 -040033#include <boost/lexical_cast.hpp>
Davide Pesaventoe1789892017-02-26 15:50:52 -050034#include <cstring>
Yingdi Yu202a2e92015-07-12 16:49:25 -070035
36#define ENSURE_PRIVATE_KEY_LOADED(key) \
37 do { \
Davide Pesaventof45fa212017-09-14 17:23:56 -040038 if ((key) == nullptr) \
Davide Pesavento923ba442019-02-12 22:00:38 -050039 NDN_THROW(Error("Private key has not been loaded yet")); \
Yingdi Yu202a2e92015-07-12 16:49:25 -070040 } while (false)
41
Davide Pesaventof45fa212017-09-14 17:23:56 -040042#define ENSURE_PRIVATE_KEY_NOT_LOADED(key) \
43 do { \
44 if ((key) != nullptr) \
Davide Pesavento923ba442019-02-12 22:00:38 -050045 NDN_THROW(Error("Private key has already been loaded")); \
Davide Pesaventof45fa212017-09-14 17:23:56 -040046 } while (false)
47
Yingdi Yu202a2e92015-07-12 16:49:25 -070048namespace ndn {
49namespace security {
50namespace transform {
51
Luca Keidel941fd8c2017-07-24 15:21:22 +020052static void
53opensslInitAlgorithms()
54{
55#if OPENSSL_VERSION_NUMBER < 0x1010000fL
56 static bool isInitialized = false;
57 if (!isInitialized) {
58 OpenSSL_add_all_algorithms();
59 isInitialized = true;
60 }
61#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL
62}
63
Laqin Fan0fe72ea2019-05-22 16:42:59 -050064class PrivateKey::Impl : noncopyable
Yingdi Yu202a2e92015-07-12 16:49:25 -070065{
66public:
Yingdi Yu202a2e92015-07-12 16:49:25 -070067 ~Impl()
68 {
69 EVP_PKEY_free(key);
70 }
71
72public:
Laqin Fan0fe72ea2019-05-22 16:42:59 -050073 EVP_PKEY* key = nullptr;
Davide Pesavento1bac1112019-06-13 21:48:46 -040074
75#if OPENSSL_VERSION_NUMBER < 0x1010100fL
76 size_t keySize = 0; // in bits, used only for HMAC
77#endif
Yingdi Yu202a2e92015-07-12 16:49:25 -070078};
79
80PrivateKey::PrivateKey()
Davide Pesaventof45fa212017-09-14 17:23:56 -040081 : m_impl(make_unique<Impl>())
Yingdi Yu202a2e92015-07-12 16:49:25 -070082{
83}
84
85PrivateKey::~PrivateKey() = default;
86
Davide Pesavento06f1bdf2017-09-16 18:59:15 -040087KeyType
88PrivateKey::getKeyType() const
89{
90 if (!m_impl->key)
91 return KeyType::NONE;
92
93 switch (detail::getEvpPkeyType(m_impl->key)) {
94 case EVP_PKEY_RSA:
95 return KeyType::RSA;
96 case EVP_PKEY_EC:
97 return KeyType::EC;
Laqin Fan0fe72ea2019-05-22 16:42:59 -050098 case EVP_PKEY_HMAC:
99 return KeyType::HMAC;
Davide Pesavento06f1bdf2017-09-16 18:59:15 -0400100 default:
101 return KeyType::NONE;
102 }
103}
104
Davide Pesavento1bac1112019-06-13 21:48:46 -0400105size_t
106PrivateKey::getKeySize() const
107{
108 switch (getKeyType()) {
109 case KeyType::RSA:
110 case KeyType::EC:
111 return static_cast<size_t>(EVP_PKEY_bits(m_impl->key));
112 case KeyType::HMAC: {
113#if OPENSSL_VERSION_NUMBER >= 0x1010100fL
114 size_t nBytes = 0;
115 EVP_PKEY_get_raw_private_key(m_impl->key, nullptr, &nBytes);
116 return nBytes * 8;
117#else
118 return m_impl->keySize;
119#endif
120 }
121 default:
122 return 0;
123 }
124}
125
Yingdi Yu202a2e92015-07-12 16:49:25 -0700126void
laqinfan48f97242019-06-03 15:33:58 -0500127PrivateKey::loadRaw(KeyType type, const uint8_t* buf, size_t size)
128{
129 ENSURE_PRIVATE_KEY_NOT_LOADED(m_impl->key);
130
131 int pkeyType;
132 switch (type) {
133 case KeyType::HMAC:
134 pkeyType = EVP_PKEY_HMAC;
135 break;
136 default:
137 NDN_THROW(std::invalid_argument("Unsupported key type " + boost::lexical_cast<std::string>(type)));
138 }
139
140 m_impl->key =
141#if OPENSSL_VERSION_NUMBER >= 0x1010100fL
142 EVP_PKEY_new_raw_private_key(pkeyType, nullptr, buf, size);
143#else
144 EVP_PKEY_new_mac_key(pkeyType, nullptr, buf, static_cast<int>(size));
145#endif
146 if (m_impl->key == nullptr)
147 NDN_THROW(Error("Failed to load private key"));
148
Davide Pesavento1bac1112019-06-13 21:48:46 -0400149#if OPENSSL_VERSION_NUMBER < 0x1010100fL
150 m_impl->keySize = size * 8;
151#endif
laqinfan48f97242019-06-03 15:33:58 -0500152}
153
154void
Yingdi Yu202a2e92015-07-12 16:49:25 -0700155PrivateKey::loadPkcs1(const uint8_t* buf, size_t size)
156{
Davide Pesaventof45fa212017-09-14 17:23:56 -0400157 ENSURE_PRIVATE_KEY_NOT_LOADED(m_impl->key);
158 opensslInitAlgorithms();
Yingdi Yu202a2e92015-07-12 16:49:25 -0700159
Davide Pesaventof45fa212017-09-14 17:23:56 -0400160 if (d2i_AutoPrivateKey(&m_impl->key, &buf, static_cast<long>(size)) == nullptr)
Davide Pesavento923ba442019-02-12 22:00:38 -0500161 NDN_THROW(Error("Failed to load private key"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700162}
163
164void
165PrivateKey::loadPkcs1(std::istream& is)
166{
167 OBufferStream os;
168 streamSource(is) >> streamSink(os);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400169 this->loadPkcs1(os.buf()->data(), os.buf()->size());
Yingdi Yu202a2e92015-07-12 16:49:25 -0700170}
171
172void
173PrivateKey::loadPkcs1Base64(const uint8_t* buf, size_t size)
174{
175 OBufferStream os;
176 bufferSource(buf, size) >> base64Decode() >> streamSink(os);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400177 this->loadPkcs1(os.buf()->data(), os.buf()->size());
Yingdi Yu202a2e92015-07-12 16:49:25 -0700178}
179
180void
181PrivateKey::loadPkcs1Base64(std::istream& is)
182{
183 OBufferStream os;
184 streamSource(is) >> base64Decode() >> streamSink(os);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400185 this->loadPkcs1(os.buf()->data(), os.buf()->size());
Yingdi Yu202a2e92015-07-12 16:49:25 -0700186}
187
188void
189PrivateKey::loadPkcs8(const uint8_t* buf, size_t size, const char* pw, size_t pwLen)
190{
191 BOOST_ASSERT(std::strlen(pw) == pwLen);
Davide Pesaventof45fa212017-09-14 17:23:56 -0400192 ENSURE_PRIVATE_KEY_NOT_LOADED(m_impl->key);
Luca Keidel941fd8c2017-07-24 15:21:22 +0200193 opensslInitAlgorithms();
Yingdi Yu202a2e92015-07-12 16:49:25 -0700194
Davide Pesaventof45fa212017-09-14 17:23:56 -0400195 detail::Bio membio(BIO_s_mem());
196 if (!membio.write(buf, size))
Davide Pesavento923ba442019-02-12 22:00:38 -0500197 NDN_THROW(Error("Failed to copy buffer"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700198
Davide Pesaventof45fa212017-09-14 17:23:56 -0400199 if (d2i_PKCS8PrivateKey_bio(membio, &m_impl->key, nullptr, const_cast<char*>(pw)) == nullptr)
Davide Pesavento923ba442019-02-12 22:00:38 -0500200 NDN_THROW(Error("Failed to load private key"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700201}
202
203static inline int
Davide Pesaventof45fa212017-09-14 17:23:56 -0400204passwordCallbackWrapper(char* buf, int size, int rwflag, void* u)
Yingdi Yu202a2e92015-07-12 16:49:25 -0700205{
Luca Keidel941fd8c2017-07-24 15:21:22 +0200206 BOOST_ASSERT(size >= 0);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700207 auto cb = reinterpret_cast<PrivateKey::PasswordCallback*>(u);
Luca Keidel941fd8c2017-07-24 15:21:22 +0200208 return (*cb)(buf, static_cast<size_t>(size), rwflag);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700209}
210
211void
212PrivateKey::loadPkcs8(const uint8_t* buf, size_t size, PasswordCallback pwCallback)
213{
Davide Pesaventof45fa212017-09-14 17:23:56 -0400214 ENSURE_PRIVATE_KEY_NOT_LOADED(m_impl->key);
Luca Keidel941fd8c2017-07-24 15:21:22 +0200215 opensslInitAlgorithms();
216
Davide Pesaventof45fa212017-09-14 17:23:56 -0400217 detail::Bio membio(BIO_s_mem());
218 if (!membio.write(buf, size))
Davide Pesavento923ba442019-02-12 22:00:38 -0500219 NDN_THROW(Error("Failed to copy buffer"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700220
221 if (pwCallback)
Davide Pesaventof45fa212017-09-14 17:23:56 -0400222 m_impl->key = d2i_PKCS8PrivateKey_bio(membio, nullptr, &passwordCallbackWrapper, &pwCallback);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700223 else
Davide Pesaventof45fa212017-09-14 17:23:56 -0400224 m_impl->key = d2i_PKCS8PrivateKey_bio(membio, nullptr, nullptr, nullptr);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700225
Davide Pesaventof45fa212017-09-14 17:23:56 -0400226 if (m_impl->key == nullptr)
Davide Pesavento923ba442019-02-12 22:00:38 -0500227 NDN_THROW(Error("Failed to load private key"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700228}
229
230void
231PrivateKey::loadPkcs8(std::istream& is, const char* pw, size_t pwLen)
232{
233 OBufferStream os;
234 streamSource(is) >> streamSink(os);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400235 this->loadPkcs8(os.buf()->data(), os.buf()->size(), pw, pwLen);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700236}
237
238void
239PrivateKey::loadPkcs8(std::istream& is, PasswordCallback pwCallback)
240{
241 OBufferStream os;
242 streamSource(is) >> streamSink(os);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400243 this->loadPkcs8(os.buf()->data(), os.buf()->size(), pwCallback);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700244}
245
246void
247PrivateKey::loadPkcs8Base64(const uint8_t* buf, size_t size, const char* pw, size_t pwLen)
248{
249 OBufferStream os;
250 bufferSource(buf, size) >> base64Decode() >> streamSink(os);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400251 this->loadPkcs8(os.buf()->data(), os.buf()->size(), pw, pwLen);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700252}
253
254void
255PrivateKey::loadPkcs8Base64(const uint8_t* buf, size_t size, PasswordCallback pwCallback)
256{
257 OBufferStream os;
258 bufferSource(buf, size) >> base64Decode() >> streamSink(os);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400259 this->loadPkcs8(os.buf()->data(), os.buf()->size(), pwCallback);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700260}
261
262void
263PrivateKey::loadPkcs8Base64(std::istream& is, const char* pw, size_t pwLen)
264{
265 OBufferStream os;
266 streamSource(is) >> base64Decode() >> streamSink(os);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400267 this->loadPkcs8(os.buf()->data(), os.buf()->size(), pw, pwLen);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700268}
269
270void
271PrivateKey::loadPkcs8Base64(std::istream& is, PasswordCallback pwCallback)
272{
273 OBufferStream os;
274 streamSource(is) >> base64Decode() >> streamSink(os);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400275 this->loadPkcs8(os.buf()->data(), os.buf()->size(), pwCallback);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700276}
277
278void
279PrivateKey::savePkcs1(std::ostream& os) const
280{
281 bufferSource(*this->toPkcs1()) >> streamSink(os);
282}
283
284void
285PrivateKey::savePkcs1Base64(std::ostream& os) const
286{
287 bufferSource(*this->toPkcs1()) >> base64Encode() >> streamSink(os);
288}
289
290void
291PrivateKey::savePkcs8(std::ostream& os, const char* pw, size_t pwLen) const
292{
293 bufferSource(*this->toPkcs8(pw, pwLen)) >> streamSink(os);
294}
295
296void
297PrivateKey::savePkcs8(std::ostream& os, PasswordCallback pwCallback) const
298{
299 bufferSource(*this->toPkcs8(pwCallback)) >> streamSink(os);
300}
301
302void
303PrivateKey::savePkcs8Base64(std::ostream& os, const char* pw, size_t pwLen) const
304{
305 bufferSource(*this->toPkcs8(pw, pwLen)) >> base64Encode() >> streamSink(os);
306}
307
308void
309PrivateKey::savePkcs8Base64(std::ostream& os, PasswordCallback pwCallback) const
310{
311 bufferSource(*this->toPkcs8(pwCallback)) >> base64Encode() >> streamSink(os);
312}
313
314ConstBufferPtr
315PrivateKey::derivePublicKey() const
316{
317 ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
318
319 uint8_t* pkcs8 = nullptr;
320 int len = i2d_PUBKEY(m_impl->key, &pkcs8);
Davide Pesaventof45fa212017-09-14 17:23:56 -0400321 if (len < 0)
Davide Pesavento923ba442019-02-12 22:00:38 -0500322 NDN_THROW(Error("Failed to derive public key"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700323
324 auto result = make_shared<Buffer>(pkcs8, len);
325 OPENSSL_free(pkcs8);
326
327 return result;
328}
329
330ConstBufferPtr
331PrivateKey::decrypt(const uint8_t* cipherText, size_t cipherLen) const
332{
333 ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
334
Davide Pesaventoc21979d2017-09-16 14:52:17 -0400335 int keyType = detail::getEvpPkeyType(m_impl->key);
Davide Pesaventof45fa212017-09-14 17:23:56 -0400336 switch (keyType) {
337 case EVP_PKEY_NONE:
Davide Pesavento923ba442019-02-12 22:00:38 -0500338 NDN_THROW(Error("Failed to determine key type"));
Luca Keidel941fd8c2017-07-24 15:21:22 +0200339 case EVP_PKEY_RSA:
340 return rsaDecrypt(cipherText, cipherLen);
341 default:
Davide Pesavento923ba442019-02-12 22:00:38 -0500342 NDN_THROW(Error("Decryption is not supported for key type " + to_string(keyType)));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700343 }
344}
345
346void*
347PrivateKey::getEvpPkey() const
348{
349 return m_impl->key;
350}
351
352ConstBufferPtr
353PrivateKey::toPkcs1() const
354{
355 ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
Luca Keidel941fd8c2017-07-24 15:21:22 +0200356 opensslInitAlgorithms();
Yingdi Yu202a2e92015-07-12 16:49:25 -0700357
Davide Pesaventof45fa212017-09-14 17:23:56 -0400358 detail::Bio membio(BIO_s_mem());
359 if (!i2d_PrivateKey_bio(membio, m_impl->key))
Davide Pesavento923ba442019-02-12 22:00:38 -0500360 NDN_THROW(Error("Cannot convert key to PKCS #1 format"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700361
Davide Pesaventof45fa212017-09-14 17:23:56 -0400362 auto buffer = make_shared<Buffer>(BIO_pending(membio));
Davide Pesavento140e9cb2019-08-19 00:02:05 -0400363 if (!membio.read(buffer->data(), buffer->size()))
364 NDN_THROW(Error("Read error during PKCS #1 conversion"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700365
366 return buffer;
367}
368
369ConstBufferPtr
370PrivateKey::toPkcs8(const char* pw, size_t pwLen) const
371{
Yingdi Yu202a2e92015-07-12 16:49:25 -0700372 BOOST_ASSERT(std::strlen(pw) == pwLen);
Luca Keidel941fd8c2017-07-24 15:21:22 +0200373 ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
374 opensslInitAlgorithms();
Yingdi Yu202a2e92015-07-12 16:49:25 -0700375
Davide Pesaventof45fa212017-09-14 17:23:56 -0400376 detail::Bio membio(BIO_s_mem());
Davide Pesaventoee77ca02018-10-10 01:45:24 -0400377 if (!i2d_PKCS8PrivateKey_bio(membio, m_impl->key, EVP_aes_256_cbc(), nullptr, 0,
Davide Pesaventof45fa212017-09-14 17:23:56 -0400378 nullptr, const_cast<char*>(pw)))
Davide Pesavento923ba442019-02-12 22:00:38 -0500379 NDN_THROW(Error("Cannot convert key to PKCS #8 format"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700380
Davide Pesaventof45fa212017-09-14 17:23:56 -0400381 auto buffer = make_shared<Buffer>(BIO_pending(membio));
Davide Pesavento140e9cb2019-08-19 00:02:05 -0400382 if (!membio.read(buffer->data(), buffer->size()))
383 NDN_THROW(Error("Read error during PKCS #8 conversion"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700384
385 return buffer;
386}
387
388ConstBufferPtr
389PrivateKey::toPkcs8(PasswordCallback pwCallback) const
390{
391 ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
Luca Keidel941fd8c2017-07-24 15:21:22 +0200392 opensslInitAlgorithms();
Yingdi Yu202a2e92015-07-12 16:49:25 -0700393
Davide Pesaventof45fa212017-09-14 17:23:56 -0400394 detail::Bio membio(BIO_s_mem());
Davide Pesaventoee77ca02018-10-10 01:45:24 -0400395 if (!i2d_PKCS8PrivateKey_bio(membio, m_impl->key, EVP_aes_256_cbc(), nullptr, 0,
Davide Pesaventof45fa212017-09-14 17:23:56 -0400396 &passwordCallbackWrapper, &pwCallback))
Davide Pesavento923ba442019-02-12 22:00:38 -0500397 NDN_THROW(Error("Cannot convert key to PKCS #8 format"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700398
Davide Pesaventof45fa212017-09-14 17:23:56 -0400399 auto buffer = make_shared<Buffer>(BIO_pending(membio));
Davide Pesavento140e9cb2019-08-19 00:02:05 -0400400 if (!membio.read(buffer->data(), buffer->size()))
401 NDN_THROW(Error("Read error during PKCS #8 conversion"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700402
403 return buffer;
404}
405
406ConstBufferPtr
407PrivateKey::rsaDecrypt(const uint8_t* cipherText, size_t cipherLen) const
408{
409 detail::EvpPkeyCtx ctx(m_impl->key);
410
Davide Pesaventof45fa212017-09-14 17:23:56 -0400411 if (EVP_PKEY_decrypt_init(ctx) <= 0)
Davide Pesavento923ba442019-02-12 22:00:38 -0500412 NDN_THROW(Error("Failed to initialize decryption context"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700413
Davide Pesaventof45fa212017-09-14 17:23:56 -0400414 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0)
Davide Pesavento923ba442019-02-12 22:00:38 -0500415 NDN_THROW(Error("Failed to set padding"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700416
417 size_t outlen = 0;
418 // Determine buffer length
Davide Pesaventof45fa212017-09-14 17:23:56 -0400419 if (EVP_PKEY_decrypt(ctx, nullptr, &outlen, cipherText, cipherLen) <= 0)
Davide Pesavento923ba442019-02-12 22:00:38 -0500420 NDN_THROW(Error("Failed to estimate output length"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700421
422 auto out = make_shared<Buffer>(outlen);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400423 if (EVP_PKEY_decrypt(ctx, out->data(), &outlen, cipherText, cipherLen) <= 0)
Davide Pesavento923ba442019-02-12 22:00:38 -0500424 NDN_THROW(Error("Failed to decrypt ciphertext"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700425
426 out->resize(outlen);
427 return out;
428}
429
Davide Pesaventof45fa212017-09-14 17:23:56 -0400430unique_ptr<PrivateKey>
431PrivateKey::generateRsaKey(uint32_t keySize)
Yingdi Yu202a2e92015-07-12 16:49:25 -0700432{
433 detail::EvpPkeyCtx kctx(EVP_PKEY_RSA);
434
Davide Pesaventof45fa212017-09-14 17:23:56 -0400435 if (EVP_PKEY_keygen_init(kctx) <= 0)
Davide Pesavento923ba442019-02-12 22:00:38 -0500436 NDN_THROW(PrivateKey::Error("Failed to initialize RSA keygen context"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700437
Davide Pesaventof45fa212017-09-14 17:23:56 -0400438 if (EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, static_cast<int>(keySize)) <= 0)
Davide Pesavento923ba442019-02-12 22:00:38 -0500439 NDN_THROW(PrivateKey::Error("Failed to set RSA key length"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700440
441 auto privateKey = make_unique<PrivateKey>();
Davide Pesaventof45fa212017-09-14 17:23:56 -0400442 if (EVP_PKEY_keygen(kctx, &privateKey->m_impl->key) <= 0)
Davide Pesavento923ba442019-02-12 22:00:38 -0500443 NDN_THROW(PrivateKey::Error("Failed to generate RSA key"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700444
445 return privateKey;
446}
447
Davide Pesaventof45fa212017-09-14 17:23:56 -0400448unique_ptr<PrivateKey>
449PrivateKey::generateEcKey(uint32_t keySize)
Yingdi Yu202a2e92015-07-12 16:49:25 -0700450{
Davide Pesaventof45fa212017-09-14 17:23:56 -0400451 detail::EvpPkeyCtx pctx(EVP_PKEY_EC);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700452
Davide Pesaventof45fa212017-09-14 17:23:56 -0400453 if (EVP_PKEY_paramgen_init(pctx) <= 0)
Davide Pesavento923ba442019-02-12 22:00:38 -0500454 NDN_THROW(PrivateKey::Error("Failed to initialize EC paramgen context"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700455
Davide Pesaventof45fa212017-09-14 17:23:56 -0400456 int ret;
Yingdi Yu202a2e92015-07-12 16:49:25 -0700457 switch (keySize) {
Davide Pesavento3c7969f2018-09-08 15:31:35 -0400458 case 224:
459 ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_secp224r1);
460 break;
461 case 256:
462 ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1); // same as secp256r1
463 break;
464 case 384:
465 ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_secp384r1);
466 break;
467 case 521:
468 ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_secp521r1);
469 break;
470 default:
Davide Pesavento923ba442019-02-12 22:00:38 -0500471 NDN_THROW(std::invalid_argument("Unsupported EC key length " + to_string(keySize)));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700472 }
Davide Pesaventof45fa212017-09-14 17:23:56 -0400473 if (ret <= 0)
Davide Pesavento923ba442019-02-12 22:00:38 -0500474 NDN_THROW(PrivateKey::Error("Failed to set EC curve"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700475
Davide Pesaventof45fa212017-09-14 17:23:56 -0400476 Impl params;
477 if (EVP_PKEY_paramgen(pctx, &params.key) <= 0)
Davide Pesavento923ba442019-02-12 22:00:38 -0500478 NDN_THROW(PrivateKey::Error("Failed to generate EC parameters"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700479
Davide Pesaventof45fa212017-09-14 17:23:56 -0400480 detail::EvpPkeyCtx kctx(params.key);
481 if (EVP_PKEY_keygen_init(kctx) <= 0)
Davide Pesavento923ba442019-02-12 22:00:38 -0500482 NDN_THROW(PrivateKey::Error("Failed to initialize EC keygen context"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700483
484 auto privateKey = make_unique<PrivateKey>();
Davide Pesaventof45fa212017-09-14 17:23:56 -0400485 if (EVP_PKEY_keygen(kctx, &privateKey->m_impl->key) <= 0)
Davide Pesavento923ba442019-02-12 22:00:38 -0500486 NDN_THROW(PrivateKey::Error("Failed to generate EC key"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700487
Laqin Fan0fe72ea2019-05-22 16:42:59 -0500488 return privateKey;
489}
490
491unique_ptr<PrivateKey>
492PrivateKey::generateHmacKey(uint32_t keySize)
493{
494 std::vector<uint8_t> rawKey(keySize / 8);
495 random::generateSecureBytes(rawKey.data(), rawKey.size());
496
497 auto privateKey = make_unique<PrivateKey>();
laqinfan48f97242019-06-03 15:33:58 -0500498 try {
499 privateKey->loadRaw(KeyType::HMAC, rawKey.data(), rawKey.size());
500 }
501 catch (const PrivateKey::Error&) {
Laqin Fan0fe72ea2019-05-22 16:42:59 -0500502 NDN_THROW(PrivateKey::Error("Failed to generate HMAC key"));
laqinfan48f97242019-06-03 15:33:58 -0500503 }
Laqin Fan0fe72ea2019-05-22 16:42:59 -0500504
Yingdi Yu202a2e92015-07-12 16:49:25 -0700505 return privateKey;
506}
507
508unique_ptr<PrivateKey>
509generatePrivateKey(const KeyParams& keyParams)
510{
511 switch (keyParams.getKeyType()) {
512 case KeyType::RSA: {
513 const RsaKeyParams& rsaParams = static_cast<const RsaKeyParams&>(keyParams);
Davide Pesaventof45fa212017-09-14 17:23:56 -0400514 return PrivateKey::generateRsaKey(rsaParams.getKeySize());
Yingdi Yu202a2e92015-07-12 16:49:25 -0700515 }
516 case KeyType::EC: {
Spyridon Mastorakis1ece2e32015-08-27 18:52:21 -0700517 const EcKeyParams& ecParams = static_cast<const EcKeyParams&>(keyParams);
Davide Pesaventof45fa212017-09-14 17:23:56 -0400518 return PrivateKey::generateEcKey(ecParams.getKeySize());
Yingdi Yu202a2e92015-07-12 16:49:25 -0700519 }
Laqin Fan0fe72ea2019-05-22 16:42:59 -0500520 case KeyType::HMAC: {
521 const HmacKeyParams& hmacParams = static_cast<const HmacKeyParams&>(keyParams);
522 return PrivateKey::generateHmacKey(hmacParams.getKeySize());
523 }
Yingdi Yu202a2e92015-07-12 16:49:25 -0700524 default:
laqinfan48f97242019-06-03 15:33:58 -0500525 NDN_THROW(std::invalid_argument("Unsupported key type " +
Davide Pesavento923ba442019-02-12 22:00:38 -0500526 boost::lexical_cast<std::string>(keyParams.getKeyType())));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700527 }
528}
529
530} // namespace transform
531} // namespace security
532} // namespace ndn