public-key.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2017 Regents of the University of California.
4  *
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 
22 #include "public-key.hpp"
23 #include "base64-decode.hpp"
24 #include "base64-encode.hpp"
25 #include "buffer-source.hpp"
26 #include "stream-sink.hpp"
27 #include "stream-source.hpp"
28 #include "../detail/openssl-helper.hpp"
29 #include "../../encoding/buffer-stream.hpp"
30 
31 #define ENSURE_PUBLIC_KEY_LOADED(key) \
32  do { \
33  if ((key) == nullptr) \
34  BOOST_THROW_EXCEPTION(Error("Public key has not been loaded yet")); \
35  } while (false)
36 
37 #define ENSURE_PUBLIC_KEY_NOT_LOADED(key) \
38  do { \
39  if ((key) != nullptr) \
40  BOOST_THROW_EXCEPTION(Error("Public key has already been loaded")); \
41  } while (false)
42 
43 namespace ndn {
44 namespace security {
45 namespace transform {
46 
47 class PublicKey::Impl
48 {
49 public:
50  Impl() noexcept
51  : key(nullptr)
52  {
53  }
54 
55  ~Impl()
56  {
57  EVP_PKEY_free(key);
58  }
59 
60 public:
61  EVP_PKEY* key;
62 };
63 
65  : m_impl(make_unique<Impl>())
66 {
67 }
68 
69 PublicKey::~PublicKey() = default;
70 
71 KeyType
73 {
74  if (!m_impl->key)
75  return KeyType::NONE;
76 
77  switch (detail::getEvpPkeyType(m_impl->key)) {
78  case EVP_PKEY_RSA:
79  return KeyType::RSA;
80  case EVP_PKEY_EC:
81  return KeyType::EC;
82  default:
83  return KeyType::NONE;
84  }
85 }
86 
87 void
88 PublicKey::loadPkcs8(const uint8_t* buf, size_t size)
89 {
90  ENSURE_PUBLIC_KEY_NOT_LOADED(m_impl->key);
91 
92  if (d2i_PUBKEY(&m_impl->key, &buf, static_cast<long>(size)) == nullptr)
93  BOOST_THROW_EXCEPTION(Error("Failed to load public key"));
94 }
95 
96 void
97 PublicKey::loadPkcs8(std::istream& is)
98 {
99  OBufferStream os;
100  streamSource(is) >> streamSink(os);
101  this->loadPkcs8(os.buf()->data(), os.buf()->size());
102 }
103 
104 void
105 PublicKey::loadPkcs8Base64(const uint8_t* buf, size_t size)
106 {
107  OBufferStream os;
108  bufferSource(buf, size) >> base64Decode() >> streamSink(os);
109  this->loadPkcs8(os.buf()->data(), os.buf()->size());
110 }
111 
112 void
113 PublicKey::loadPkcs8Base64(std::istream& is)
114 {
115  OBufferStream os;
116  streamSource(is) >> base64Decode() >> streamSink(os);
117  this->loadPkcs8(os.buf()->data(), os.buf()->size());
118 }
119 
120 void
121 PublicKey::savePkcs8(std::ostream& os) const
122 {
123  bufferSource(*this->toPkcs8()) >> streamSink(os);
124 }
125 
126 void
127 PublicKey::savePkcs8Base64(std::ostream& os) const
128 {
129  bufferSource(*this->toPkcs8()) >> base64Encode() >> streamSink(os);
130 }
131 
133 PublicKey::encrypt(const uint8_t* plainText, size_t plainLen) const
134 {
135  ENSURE_PUBLIC_KEY_LOADED(m_impl->key);
136 
137  int keyType = detail::getEvpPkeyType(m_impl->key);
138  switch (keyType) {
139  case EVP_PKEY_NONE:
140  BOOST_THROW_EXCEPTION(Error("Failed to determine key type"));
141  case EVP_PKEY_RSA:
142  return rsaEncrypt(plainText, plainLen);
143  default:
144  BOOST_THROW_EXCEPTION(Error("Encryption is not supported for key type " + to_string(keyType)));
145  }
146 }
147 
148 void*
149 PublicKey::getEvpPkey() const
150 {
151  return m_impl->key;
152 }
153 
155 PublicKey::toPkcs8() const
156 {
157  ENSURE_PUBLIC_KEY_LOADED(m_impl->key);
158 
159  uint8_t* pkcs8 = nullptr;
160  int len = i2d_PUBKEY(m_impl->key, &pkcs8);
161  if (len < 0)
162  BOOST_THROW_EXCEPTION(Error("Cannot convert key to PKCS #8 format"));
163 
164  auto buffer = make_shared<Buffer>(pkcs8, len);
165  OPENSSL_free(pkcs8);
166 
167  return buffer;
168 }
169 
171 PublicKey::rsaEncrypt(const uint8_t* plainText, size_t plainLen) const
172 {
173  detail::EvpPkeyCtx ctx(m_impl->key);
174 
175  if (EVP_PKEY_encrypt_init(ctx) <= 0)
176  BOOST_THROW_EXCEPTION(Error("Failed to initialize encryption context"));
177 
178  if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0)
179  BOOST_THROW_EXCEPTION(Error("Failed to set padding"));
180 
181  size_t outlen = 0;
182  // Determine buffer length
183  if (EVP_PKEY_encrypt(ctx, nullptr, &outlen, plainText, plainLen) <= 0)
184  BOOST_THROW_EXCEPTION(Error("Failed to estimate output length"));
185 
186  auto out = make_shared<Buffer>(outlen);
187  if (EVP_PKEY_encrypt(ctx, out->data(), &outlen, plainText, plainLen) <= 0)
188  BOOST_THROW_EXCEPTION(Error("Failed to encrypt plaintext"));
189 
190  out->resize(outlen);
191  return out;
192 }
193 
194 } // namespace transform
195 } // namespace security
196 } // namespace ndn
Copyright (c) 2013-2017 Regents of the University of California.
Definition: common.hpp:66
Unknown key type.
ConstBufferPtr encrypt(const uint8_t *plainText, size_t plainLen) const
Definition: public-key.cpp:133
unique_ptr< Transform > base64Decode(bool expectNewlineEvery64Bytes)
RSA key, supports sign/verify and encrypt/decrypt operations.
unique_ptr< T > make_unique(Args &&...args)
Definition: backports.hpp:73
KeyType
The type of a cryptographic key.
void savePkcs8(std::ostream &os) const
Save the public key in PKCS#8 format into a stream os.
Definition: public-key.cpp:121
unique_ptr< Sink > streamSink(std::ostream &os)
Definition: stream-sink.cpp:53
void loadPkcs8(const uint8_t *buf, size_t size)
Load the public key in PKCS#8 format from a buffer buf.
Definition: public-key.cpp:88
Elliptic Curve key (e.g. for ECDSA), supports sign/verify operations.
void loadPkcs8Base64(const uint8_t *buf, size_t size)
Load the public key in base64-encoded PKCS#8 format from a buffer buf.
Definition: public-key.cpp:105
PublicKey()
Create an empty public key instance.
Definition: public-key.cpp:64
shared_ptr< Buffer > buf()
Flush written data to the stream and return shared pointer to the underlying buffer.
#define ENSURE_PUBLIC_KEY_NOT_LOADED(key)
Definition: public-key.cpp:37
implements an output stream that constructs ndn::Buffer
std::string to_string(const V &v)
Definition: backports.hpp:84
#define ENSURE_PUBLIC_KEY_LOADED(key)
Definition: public-key.cpp:31
void savePkcs8Base64(std::ostream &os) const
Save the public key in base64-encoded PKCS#8 format into a stream os.
Definition: public-key.cpp:127
shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:89
unique_ptr< Transform > base64Encode(bool needBreak)
KeyType getKeyType() const
Get the type of the public key.
Definition: public-key.cpp:72