NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.3: NDN, CCN, CCNx, content centric networks
API Documentation
private-key.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
22 #include "private-key.hpp"
23 #include "buffer-source.hpp"
24 #include "stream-source.hpp"
25 #include "base64-encode.hpp"
26 #include "base64-decode.hpp"
27 #include "stream-sink.hpp"
28 #include "../../encoding/buffer-stream.hpp"
29 #include "../detail/openssl-helper.hpp"
30 #include "../key-params.hpp"
31 
32 #include <string.h>
33 
34 #define ENSURE_PRIVATE_KEY_LOADED(key) \
35  do { \
36  if (key == nullptr) \
37  BOOST_THROW_EXCEPTION(Error("Private key has not been loaded yet")); \
38  } while (false)
39 
40 namespace ndn {
41 namespace security {
42 namespace transform {
43 
45 {
46 public:
47  Impl()
48  : key(nullptr)
49  {
50  }
51 
53  {
54  EVP_PKEY_free(key);
55  }
56 
57 public:
58  EVP_PKEY* key;
59 };
60 
62  : m_impl(new Impl)
63 {
64 }
65 
66 PrivateKey::~PrivateKey() = default;
67 
68 void
69 PrivateKey::loadPkcs1(const uint8_t* buf, size_t size)
70 {
71  detail::Bio mem(BIO_s_mem());
72  BIO_write(mem.get(), buf, size);
73 
74  d2i_PrivateKey_bio(mem.get(), &m_impl->key);
75 
76  ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
77 }
78 
79 void
80 PrivateKey::loadPkcs1(std::istream& is)
81 {
82  OBufferStream os;
83  streamSource(is) >> streamSink(os);
84  this->loadPkcs1(os.buf()->buf(), os.buf()->size());
85 }
86 
87 void
88 PrivateKey::loadPkcs1Base64(const uint8_t* buf, size_t size)
89 {
90  OBufferStream os;
91  bufferSource(buf, size) >> base64Decode() >> streamSink(os);
92  this->loadPkcs1(os.buf()->buf(), os.buf()->size());
93 }
94 
95 void
96 PrivateKey::loadPkcs1Base64(std::istream& is)
97 {
98  OBufferStream os;
99  streamSource(is) >> base64Decode() >> streamSink(os);
100  this->loadPkcs1(os.buf()->buf(), os.buf()->size());
101 }
102 
103 void
104 PrivateKey::loadPkcs8(const uint8_t* buf, size_t size, const char* pw, size_t pwLen)
105 {
106  BOOST_ASSERT(std::strlen(pw) == pwLen);
107 
108  detail::Bio mem(BIO_s_mem());
109  BIO_write(mem.get(), buf, size);
110 
111  m_impl->key = d2i_PKCS8PrivateKey_bio(mem.get(), &m_impl->key, nullptr, const_cast<char*>(pw));
112 
113  ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
114 }
115 
116 static inline int
117 passwordCallback(char* buf, int size, int rwflag, void* u)
118 {
119  auto cb = reinterpret_cast<PrivateKey::PasswordCallback*>(u);
120  return (*cb)(buf, size, rwflag);
121 }
122 
123 void
124 PrivateKey::loadPkcs8(const uint8_t* buf, size_t size, PasswordCallback pwCallback)
125 {
126  OpenSSL_add_all_algorithms();
127  detail::Bio mem(BIO_s_mem());
128  BIO_write(mem.get(), buf, size);
129 
130  if (pwCallback)
131  m_impl->key = d2i_PKCS8PrivateKey_bio(mem.get(), &m_impl->key, passwordCallback, &pwCallback);
132  else
133  m_impl->key = d2i_PKCS8PrivateKey_bio(mem.get(), &m_impl->key, nullptr, nullptr);
134 
135  ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
136 }
137 
138 void
139 PrivateKey::loadPkcs8(std::istream& is, const char* pw, size_t pwLen)
140 {
141  OBufferStream os;
142  streamSource(is) >> streamSink(os);
143  this->loadPkcs8(os.buf()->buf(), os.buf()->size(), pw, pwLen);
144 }
145 
146 void
147 PrivateKey::loadPkcs8(std::istream& is, PasswordCallback pwCallback)
148 {
149  OBufferStream os;
150  streamSource(is) >> streamSink(os);
151  this->loadPkcs8(os.buf()->buf(), os.buf()->size(), pwCallback);
152 }
153 
154 void
155 PrivateKey::loadPkcs8Base64(const uint8_t* buf, size_t size, const char* pw, size_t pwLen)
156 {
157  OBufferStream os;
158  bufferSource(buf, size) >> base64Decode() >> streamSink(os);
159  this->loadPkcs8(os.buf()->buf(), os.buf()->size(), pw, pwLen);
160 }
161 
162 void
163 PrivateKey::loadPkcs8Base64(const uint8_t* buf, size_t size, PasswordCallback pwCallback)
164 {
165  OBufferStream os;
166  bufferSource(buf, size) >> base64Decode() >> streamSink(os);
167  this->loadPkcs8(os.buf()->buf(), os.buf()->size(), pwCallback);
168 }
169 
170 void
171 PrivateKey::loadPkcs8Base64(std::istream& is, const char* pw, size_t pwLen)
172 {
173  OBufferStream os;
174  streamSource(is) >> base64Decode() >> streamSink(os);
175  this->loadPkcs8(os.buf()->buf(), os.buf()->size(), pw, pwLen);
176 }
177 
178 void
179 PrivateKey::loadPkcs8Base64(std::istream& is, PasswordCallback pwCallback)
180 {
181  OBufferStream os;
182  streamSource(is) >> base64Decode() >> streamSink(os);
183  this->loadPkcs8(os.buf()->buf(), os.buf()->size(), pwCallback);
184 }
185 
186 void
187 PrivateKey::savePkcs1(std::ostream& os) const
188 {
189  bufferSource(*this->toPkcs1()) >> streamSink(os);
190 }
191 
192 void
193 PrivateKey::savePkcs1Base64(std::ostream& os) const
194 {
195  bufferSource(*this->toPkcs1()) >> base64Encode() >> streamSink(os);
196 }
197 
198 void
199 PrivateKey::savePkcs8(std::ostream& os, const char* pw, size_t pwLen) const
200 {
201  bufferSource(*this->toPkcs8(pw, pwLen)) >> streamSink(os);
202 }
203 
204 void
205 PrivateKey::savePkcs8(std::ostream& os, PasswordCallback pwCallback) const
206 {
207  bufferSource(*this->toPkcs8(pwCallback)) >> streamSink(os);
208 }
209 
210 void
211 PrivateKey::savePkcs8Base64(std::ostream& os, const char* pw, size_t pwLen) const
212 {
213  bufferSource(*this->toPkcs8(pw, pwLen)) >> base64Encode() >> streamSink(os);
214 }
215 
216 void
217 PrivateKey::savePkcs8Base64(std::ostream& os, PasswordCallback pwCallback) const
218 {
219  bufferSource(*this->toPkcs8(pwCallback)) >> base64Encode() >> streamSink(os);
220 }
221 
224 {
225  ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
226 
227  uint8_t* pkcs8 = nullptr;
228  int len = i2d_PUBKEY(m_impl->key, &pkcs8);
229 
230  if (len <= 0)
231  BOOST_THROW_EXCEPTION(Error("Failed to derive public key"));
232 
233  auto result = make_shared<Buffer>(pkcs8, len);
234  OPENSSL_free(pkcs8);
235 
236  return result;
237 }
238 
240 PrivateKey::decrypt(const uint8_t* cipherText, size_t cipherLen) const
241 {
242  ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
243 
244 #if OPENSSL_VERSION_NUMBER < 0x1010000fL
245  switch (EVP_PKEY_type(m_impl->key->type)) {
246 #else
247  switch (EVP_PKEY_base_id(m_impl->key)) {
248 #endif // OPENSSL_VERSION_NUMBER < 0x1010000fL
249  case EVP_PKEY_RSA:
250  return rsaDecrypt(cipherText, cipherLen);
251  default:
252  BOOST_THROW_EXCEPTION(Error("Decryption is not supported for this key type"));
253  }
254 }
255 
256 void*
257 PrivateKey::getEvpPkey() const
258 {
259  return m_impl->key;
260 }
261 
263 PrivateKey::toPkcs1() const
264 {
265  ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
266 
267  OpenSSL_add_all_algorithms();
268  detail::Bio mem(BIO_s_mem());
269  int ret = i2d_PrivateKey_bio(mem.get(), m_impl->key);
270  if (ret != 1)
271  BOOST_THROW_EXCEPTION(Error("Cannot convert key into PKCS1 format"));
272 
273  int len8 = BIO_pending(mem.get());
274  auto buffer = make_shared<Buffer>(len8);
275  BIO_read(mem.get(), buffer->buf(), len8);
276 
277  return buffer;
278 }
279 
281 PrivateKey::toPkcs8(const char* pw, size_t pwLen) const
282 {
283  ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
284 
285  BOOST_ASSERT(std::strlen(pw) == pwLen);
286 
287  OpenSSL_add_all_algorithms();
288  detail::Bio mem(BIO_s_mem());
289  int ret = i2d_PKCS8PrivateKey_bio(mem.get(), m_impl->key, EVP_des_cbc(),
290  const_cast<char*>(pw), pwLen, nullptr, nullptr);
291  if (ret != 1)
292  BOOST_THROW_EXCEPTION(Error("Cannot convert key into PKCS8 format"));
293 
294  int len8 = BIO_pending(mem.get());
295  auto buffer = make_shared<Buffer>(len8);
296  BIO_read(mem.get(), buffer->buf(), len8);
297 
298  return buffer;
299 }
300 
302 PrivateKey::toPkcs8(PasswordCallback pwCallback) const
303 {
304  ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
305 
306  OpenSSL_add_all_algorithms();
307  detail::Bio mem(BIO_s_mem());
308  int ret = i2d_PKCS8PrivateKey_bio(mem.get(), m_impl->key, EVP_des_cbc(),
309  nullptr, 0,
310  passwordCallback, &pwCallback);
311  if (ret != 1)
312  BOOST_THROW_EXCEPTION(Error("Cannot convert key into PKCS8 format"));
313 
314  int len8 = BIO_pending(mem.get());
315  auto buffer = make_shared<Buffer>(len8);
316  BIO_read(mem.get(), buffer->buf(), len8);
317 
318  return buffer;
319 }
320 
322 PrivateKey::rsaDecrypt(const uint8_t* cipherText, size_t cipherLen) const
323 {
324  detail::EvpPkeyCtx ctx(m_impl->key);
325 
326  if (EVP_PKEY_decrypt_init(ctx.get()) <= 0)
327  BOOST_THROW_EXCEPTION(Error("Failed to initialize decryption context"));
328 
329  if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING) <= 0)
330  BOOST_THROW_EXCEPTION(Error("Failed to set padding"));
331 
332  size_t outlen = 0;
333  // Determine buffer length
334  if (EVP_PKEY_decrypt(ctx.get(), nullptr, &outlen, cipherText, cipherLen) <= 0)
335  BOOST_THROW_EXCEPTION(Error("Failed to estimate output length"));
336 
337  auto out = make_shared<Buffer>(outlen);
338 
339  if (EVP_PKEY_decrypt(ctx.get(), out->buf(), &outlen, cipherText, cipherLen) <= 0)
340  BOOST_THROW_EXCEPTION(Error("Failed to decrypt cipher text"));
341 
342  out->resize(outlen);
343  return out;
344 }
345 
346 static unique_ptr<PrivateKey>
347 generateRsaKey(uint32_t keySize)
348 {
349  detail::EvpPkeyCtx kctx(EVP_PKEY_RSA);
350 
351  int ret = EVP_PKEY_keygen_init(kctx.get());
352  if (ret != 1)
353  BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate RSA key"));
354 
355  ret = EVP_PKEY_CTX_set_rsa_keygen_bits(kctx.get(), keySize);
356  if (ret != 1)
357  BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate RSA key"));
358 
359  detail::EvpPkey key;
360  ret = EVP_PKEY_keygen(kctx.get(), &key);
361  if (ret != 1)
362  BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate RSA key"));
363 
364  detail::Bio mem(BIO_s_mem());
365  i2d_PrivateKey_bio(mem.get(), key.get());
366  int len = BIO_pending(mem.get());
367  Buffer buffer(len);
368  BIO_read(mem.get(), buffer.buf(), len);
369 
370  auto privateKey = make_unique<PrivateKey>();
371  privateKey->loadPkcs1(buffer.buf(), buffer.size());
372 
373  return privateKey;
374 }
375 
376 static unique_ptr<PrivateKey>
377 generateEcKey(uint32_t keySize)
378 {
379  detail::EvpPkeyCtx ctx(EVP_PKEY_EC);
380 
381  int ret = EVP_PKEY_paramgen_init(ctx.get());
382  if (ret != 1)
383  BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key"));
384 
385  switch (keySize) {
386  case 256:
387  ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), NID_X9_62_prime256v1);
388  break;
389  case 384:
390  ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), NID_secp384r1);
391  break;
392  default:
393  BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key"));
394  }
395  if (ret != 1)
396  BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key"));
397 
398  detail::EvpPkey params;
399  ret = EVP_PKEY_paramgen(ctx.get(), &params);
400  if (ret != 1)
401  BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key"));
402 
403  detail::EvpPkeyCtx kctx(params.get());
404  ret = EVP_PKEY_keygen_init(kctx.get());
405  if (ret != 1)
406  BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key"));
407 
408  detail::EvpPkey key;
409  ret = EVP_PKEY_keygen(kctx.get(), &key);
410  if (ret != 1)
411  BOOST_THROW_EXCEPTION(PrivateKey::Error("Fail to generate EC key"));
412 
413  detail::Bio mem(BIO_s_mem());
414  i2d_PrivateKey_bio(mem.get(), key.get());
415  int len = BIO_pending(mem.get());
416  Buffer buffer(len);
417  BIO_read(mem.get(), buffer.buf(), len);
418 
419  auto privateKey = make_unique<PrivateKey>();
420  privateKey->loadPkcs1(buffer.buf(), buffer.size());
421 
422  return privateKey;
423 }
424 
425 unique_ptr<PrivateKey>
426 generatePrivateKey(const KeyParams& keyParams)
427 {
428  switch (keyParams.getKeyType()) {
429  case KeyType::RSA: {
430  const RsaKeyParams& rsaParams = static_cast<const RsaKeyParams&>(keyParams);
431  return generateRsaKey(rsaParams.getKeySize());
432  }
433  case KeyType::EC: {
434  const EcdsaKeyParams& ecdsaParams = static_cast<const EcdsaKeyParams&>(keyParams);
435  return generateEcKey(ecdsaParams.getKeySize());
436  }
437  default:
438  BOOST_THROW_EXCEPTION(std::invalid_argument("Unsupported asymmetric key type"));
439  }
440 }
441 
442 } // namespace transform
443 } // namespace security
444 } // namespace ndn
Copyright (c) 2011-2015 Regents of the University of California.
void loadPkcs8(const uint8_t *buf, size_t size, const char *pw, size_t pwLen)
Load the private key in encrypted PKCS#8 format from a buffer buf with passphrase pw...
void loadPkcs1Base64(const uint8_t *buf, size_t size)
Load the private key in base64-encoded PKCS#1 format from a buffer buf.
Definition: private-key.cpp:88
function< int(char *buf, size_t bufSize, bool shouldConfirm)> PasswordCallback
Callback for application to handle password input.
Definition: private-key.hpp:60
void loadPkcs1(const uint8_t *buf, size_t size)
Load the private key in PKCS#1 format from a buffer buf.
Definition: private-key.cpp:69
unique_ptr< Transform > base64Decode(bool expectNewlineEvery64Bytes)
void savePkcs8(std::ostream &os, const char *pw, size_t pwLen) const
Save the private key in encrypted PKCS#8 format into a stream os.
#define ENSURE_PRIVATE_KEY_LOADED(key)
Copyright (c) 2013-2016 Regents of the University of California.
Definition: private-key.cpp:34
void savePkcs8Base64(std::ostream &os, const char *pw, size_t pwLen) const
Save the private key in base64-encoded encrypted PKCS#8 format into a stream os.
unique_ptr< PrivateKey > generatePrivateKey(const KeyParams &keyParams)
generate a private key according to keyParams.
static int passwordCallback(char *buf, int size, int rwflag, void *u)
PrivateKey()
Create a private key instance.
Definition: private-key.cpp:61
void loadPkcs8Base64(const uint8_t *buf, size_t size, const char *pw, size_t pwLen)
Load the private key in base64-encoded encrypted PKCS#8 format from a buffer buf with passphrase pw...
unique_ptr< Sink > streamSink(std::ostream &os)
Definition: stream-sink.cpp:51
ConstBufferPtr decrypt(const uint8_t *cipherText, size_t cipherLen) const
KeyType getKeyType() const
Definition: key-params.hpp:54
static unique_ptr< PrivateKey > generateRsaKey(uint32_t keySize)
shared_ptr< Buffer > buf()
Flush written data to the stream and return shared pointer to the underlying buffer.
Base class of key parameters.
Definition: key-params.hpp:35
uint32_t getKeySize() const
Definition: key-params.hpp:135
ConstBufferPtr derivePublicKey() const
static unique_ptr< PrivateKey > generateEcKey(uint32_t keySize)
implements an output stream that constructs ndn::Buffer
shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:33
SimplePublicKeyParams is a template for public keys with only one parameter: size.
Definition: key-params.hpp:110
Class representing a general-use automatically managed/resized buffer.
Definition: buffer.hpp:44
void savePkcs1Base64(std::ostream &os) const
Save the private key in base64-encoded PKCS#1 format into a stream os.
void savePkcs1(std::ostream &os) const
Save the private key in PKCS#1 format into a stream os.
unique_ptr< Transform > base64Encode(bool needBreak)