ndn-cxx: NDN C++ Library 0.9.0-33-g832ea91d
Loading...
Searching...
No Matches
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-2023 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
28#include "ndn-cxx/security/impl/openssl-helper.hpp"
30
31#include <openssl/rsa.h>
32#include <openssl/x509.h>
33
34#define ENSURE_PUBLIC_KEY_LOADED(key) \
35 do { \
36 if ((key) == nullptr) \
37 NDN_THROW(Error("Public key has not been loaded yet")); \
38 } while (false)
39
40#define ENSURE_PUBLIC_KEY_NOT_LOADED(key) \
41 do { \
42 if ((key) != nullptr) \
43 NDN_THROW(Error("Public key has already been loaded")); \
44 } while (false)
45
47
48class PublicKey::Impl : noncopyable
49{
50public:
51 Impl() noexcept
52 : key(nullptr)
53 {
54 }
55
56 ~Impl()
57 {
58 EVP_PKEY_free(key);
59 }
60
61public:
62 EVP_PKEY* key;
63};
64
66 : m_impl(make_unique<Impl>())
67{
68}
69
70PublicKey::~PublicKey() = default;
71
74{
75 if (!m_impl->key)
76 return KeyType::NONE;
77
78 switch (detail::getEvpPkeyType(m_impl->key)) {
79 case EVP_PKEY_RSA:
80 return KeyType::RSA;
81 case EVP_PKEY_EC:
82 return KeyType::EC;
83 default:
84 return KeyType::NONE;
85 }
86}
87
88size_t
90{
91 switch (getKeyType()) {
92 case KeyType::RSA:
93 case KeyType::EC:
94 return static_cast<size_t>(EVP_PKEY_bits(m_impl->key));
95 default:
96 return 0;
97 }
98}
99
100void
101PublicKey::loadPkcs8(span<const uint8_t> buf)
102{
103 ENSURE_PUBLIC_KEY_NOT_LOADED(m_impl->key);
104
105 auto ptr = buf.data();
106 if (d2i_PUBKEY(&m_impl->key, &ptr, static_cast<long>(buf.size())) == nullptr)
107 NDN_THROW(Error("Failed to load public key"));
108}
109
110void
111PublicKey::loadPkcs8(std::istream& is)
112{
113 OBufferStream os;
114 streamSource(is) >> streamSink(os);
115 loadPkcs8(*os.buf());
116}
117
118void
119PublicKey::loadPkcs8Base64(span<const uint8_t> buf)
120{
121 OBufferStream os;
122 bufferSource(buf) >> base64Decode() >> streamSink(os);
123 loadPkcs8(*os.buf());
124}
125
126void
128{
129 OBufferStream os;
130 streamSource(is) >> base64Decode() >> streamSink(os);
131 loadPkcs8(*os.buf());
132}
133
134void
135PublicKey::savePkcs8(std::ostream& os) const
136{
137 bufferSource(*toPkcs8()) >> streamSink(os);
138}
139
140void
141PublicKey::savePkcs8Base64(std::ostream& os) const
142{
143 bufferSource(*toPkcs8()) >> base64Encode() >> streamSink(os);
144}
145
147PublicKey::encrypt(span<const uint8_t> plainText) const
148{
149 ENSURE_PUBLIC_KEY_LOADED(m_impl->key);
150
151 int keyType = detail::getEvpPkeyType(m_impl->key);
152 switch (keyType) {
153 case EVP_PKEY_NONE:
154 NDN_THROW(Error("Failed to determine key type"));
155 case EVP_PKEY_RSA:
156 return rsaEncrypt(plainText);
157 default:
158 NDN_THROW(Error("Encryption is not supported for key type " + to_string(keyType)));
159 }
160}
161
162void*
163PublicKey::getEvpPkey() const
164{
165 return m_impl->key;
166}
167
169PublicKey::toPkcs8() const
170{
171 ENSURE_PUBLIC_KEY_LOADED(m_impl->key);
172
173 uint8_t* pkcs8 = nullptr;
174 int len = i2d_PUBKEY(m_impl->key, &pkcs8);
175 if (len < 0)
176 NDN_THROW(Error("Cannot convert key to PKCS #8 format"));
177
178 auto buffer = make_shared<Buffer>(pkcs8, len);
179 OPENSSL_free(pkcs8);
180
181 return buffer;
182}
183
185PublicKey::rsaEncrypt(span<const uint8_t> plainText) const
186{
187 detail::EvpPkeyCtx ctx(m_impl->key);
188
189 if (EVP_PKEY_encrypt_init(ctx) <= 0)
190 NDN_THROW(Error("Failed to initialize encryption context"));
191
192 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0)
193 NDN_THROW(Error("Failed to set padding"));
194
195 size_t outlen = 0;
196 // Determine buffer length
197 if (EVP_PKEY_encrypt(ctx, nullptr, &outlen, plainText.data(), plainText.size()) <= 0)
198 NDN_THROW(Error("Failed to estimate output length"));
199
200 auto out = make_shared<Buffer>(outlen);
201 if (EVP_PKEY_encrypt(ctx, out->data(), &outlen, plainText.data(), plainText.size()) <= 0)
202 NDN_THROW(Error("Failed to encrypt plaintext"));
203
204 out->resize(outlen);
205 return out;
206}
207
208} // namespace ndn::security::transform
An output stream that writes to a Buffer.
std::shared_ptr< Buffer > buf()
Return a shared pointer to the underlying buffer.
void loadPkcs8Base64(span< const uint8_t > buf)
Load the public key in base64-encoded PKCS#8 format from a buffer buf.
void loadPkcs8(span< const uint8_t > buf)
Load the public key in PKCS#8 format from a buffer buf.
KeyType getKeyType() const
Return the type of the public key.
void savePkcs8Base64(std::ostream &os) const
Save the public key in base64-encoded PKCS#8 format into a stream os.
ConstBufferPtr encrypt(span< const uint8_t > plainText) const
void savePkcs8(std::ostream &os) const
Save the public key in PKCS#8 format into a stream os.
size_t getKeySize() const
Return the size of the public key in bits.
PublicKey()
Create an empty public key instance.
#define NDN_THROW(e)
Definition exception.hpp:56
unique_ptr< Sink > streamSink(std::ostream &os)
unique_ptr< Transform > base64Encode(bool needBreak)
unique_ptr< Transform > base64Decode(bool expectNewlineEvery64Bytes)
KeyType
The type of a cryptographic key.
@ EC
Elliptic Curve key (e.g. for ECDSA), supports sign/verify operations.
@ RSA
RSA key, supports sign/verify and encrypt/decrypt operations.
@ NONE
Unknown or unsupported key type.
std::shared_ptr< const Buffer > ConstBufferPtr
Definition buffer.hpp:140
#define ENSURE_PUBLIC_KEY_NOT_LOADED(key)
#define ENSURE_PUBLIC_KEY_LOADED(key)