blob: 63a987754d055eb8cba232cdc0b5154ae307cb62 [file] [log] [blame]
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Zhiyi Zhanga67fa462020-04-19 13:48:03 -07002/**
3 * Copyright (c) 2017-2020, Regents of the University of California.
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -07004 *
5 * This file is part of ndncert, a certificate management system based on NDN.
6 *
7 * ndncert is free software: you can redistribute it and/or modify it under the terms
8 * of the GNU General Public License as published by the Free Software Foundation, either
9 * version 3 of the License, or (at your option) any later version.
10 *
11 * ndncert 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 General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License along with
16 * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * See AUTHORS.md for complete list of ndncert authors and contributors.
19 */
20
Zhiyi Zhangdc25ddf2020-10-20 14:28:55 -070021#include "crypto-helpers.hpp"
22
23#include <boost/endian/conversion.hpp>
Zhiyi Zhang222810b2020-10-16 21:50:35 -070024#include <cmath>
Davide Pesavento368341b2019-08-13 23:57:50 -040025#include <ndn-cxx/encoding/buffer-stream.hpp>
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070026#include <ndn-cxx/security/transform/base64-decode.hpp>
27#include <ndn-cxx/security/transform/base64-encode.hpp>
28#include <ndn-cxx/security/transform/buffer-source.hpp>
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070029#include <ndn-cxx/security/transform/stream-sink.hpp>
Zhiyi Zhangc5d93a92020-10-14 17:07:35 -070030#include <ndn-cxx/util/random.hpp>
Zhiyi Zhangdc25ddf2020-10-20 14:28:55 -070031#include <openssl/ec.h>
32#include <openssl/err.h>
Zhiyi Zhangdc25ddf2020-10-20 14:28:55 -070033#include <openssl/hmac.h>
34#include <openssl/kdf.h>
35#include <openssl/pem.h>
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070036
37namespace ndn {
38namespace ndncert {
39
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070040ECDHState::ECDHState()
41{
Zhiyi Zhangf12ee302020-10-14 17:46:44 -070042 auto EC_NID = NID_X9_62_prime256v1;
Zhiyi Zhangbed854c2020-10-20 18:25:35 -070043 // params context
44 EVP_PKEY_CTX* ctx_params = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr);
45 if (ctx_params == nullptr) {
Zhiyi Zhangdc25ddf2020-10-20 14:28:55 -070046 NDN_THROW(std::runtime_error("Could not create context."));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070047 }
Zhiyi Zhangbed854c2020-10-20 18:25:35 -070048 if (EVP_PKEY_paramgen_init(ctx_params) != 1) {
49 EVP_PKEY_CTX_free(ctx_params);
Zhiyi Zhang5c059452020-10-16 17:43:31 -070050 NDN_THROW(std::runtime_error("Could not initialize parameter generation."));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070051 }
Zhiyi Zhangbed854c2020-10-20 18:25:35 -070052 if (1 != EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx_params, EC_NID)) {
53 EVP_PKEY_CTX_free(ctx_params);
Zhiyi Zhang5c059452020-10-16 17:43:31 -070054 NDN_THROW(std::runtime_error("Likely unknown elliptical curve ID specified."));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070055 }
Zhiyi Zhangbed854c2020-10-20 18:25:35 -070056 // generate params
57 EVP_PKEY* params = nullptr;
58 if (!EVP_PKEY_paramgen(ctx_params, &params)) {
59 EVP_PKEY_CTX_free(ctx_params);
Zhiyi Zhang5c059452020-10-16 17:43:31 -070060 NDN_THROW(std::runtime_error("Could not create parameter object parameters."));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070061 }
Zhiyi Zhangbed854c2020-10-20 18:25:35 -070062 // key generation context
63 EVP_PKEY_CTX *ctx_keygen = EVP_PKEY_CTX_new(params, nullptr);
64 if (ctx_keygen == nullptr) {
65 EVP_PKEY_free(params);
66 EVP_PKEY_CTX_free(ctx_params);
Zhiyi Zhang5c059452020-10-16 17:43:31 -070067 NDN_THROW(std::runtime_error("Could not create the context for the key generation"));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070068 }
Zhiyi Zhangbed854c2020-10-20 18:25:35 -070069 if (1 != EVP_PKEY_keygen_init(ctx_keygen)) {
70 EVP_PKEY_CTX_free(ctx_keygen);
71 EVP_PKEY_free(params);
72 EVP_PKEY_CTX_free(ctx_params);
Zhiyi Zhang5c059452020-10-16 17:43:31 -070073 NDN_THROW(std::runtime_error("Could not init context for key generation."));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070074 }
Zhiyi Zhangbed854c2020-10-20 18:25:35 -070075 if (1 != EVP_PKEY_keygen(ctx_keygen, &m_privkey)) {
76 EVP_PKEY_CTX_free(ctx_keygen);
77 EVP_PKEY_free(params);
78 EVP_PKEY_CTX_free(ctx_params);
Zhiyi Zhang5c059452020-10-16 17:43:31 -070079 NDN_THROW(std::runtime_error("Could not generate DHE keys in final step"));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070080 }
Zhiyi Zhangbed854c2020-10-20 18:25:35 -070081 EVP_PKEY_CTX_free(ctx_keygen);
82 EVP_PKEY_free(params);
83 EVP_PKEY_CTX_free(ctx_params);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070084}
85
86ECDHState::~ECDHState()
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070087{
Zhiyi Zhangbed854c2020-10-20 18:25:35 -070088 if (m_privkey != nullptr) {
89 EVP_PKEY_free(m_privkey);
90 }
91}
92
93const std::vector<uint8_t>&
94ECDHState::getSelfPubKey()
95{
96 auto privECKey = EVP_PKEY_get1_EC_KEY(m_privkey);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070097 if (privECKey == nullptr) {
Zhiyi Zhang5c059452020-10-16 17:43:31 -070098 NDN_THROW(std::runtime_error("Could not get key when calling EVP_PKEY_get1_EC_KEY()."));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -070099 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700100 auto ecPoint = EC_KEY_get0_public_key(privECKey);
Zhiyi Zhangbed854c2020-10-20 18:25:35 -0700101 auto group = EC_KEY_get0_group(privECKey);
102 auto requiredBufLen = EC_POINT_point2oct(group, ecPoint, POINT_CONVERSION_COMPRESSED, nullptr, 0, nullptr);
103 m_pubKey.resize(requiredBufLen);
104 auto rev = EC_POINT_point2oct(group, ecPoint, POINT_CONVERSION_COMPRESSED,
105 m_pubKey.data(), requiredBufLen, nullptr);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700106 EC_KEY_free(privECKey);
Zhiyi Zhangbed854c2020-10-20 18:25:35 -0700107 if (rev == 0) {
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700108 NDN_THROW(std::runtime_error("Could not convert EC_POINTS to octet string when calling EC_POINT_point2oct."));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700109 }
Zhiyi Zhangbed854c2020-10-20 18:25:35 -0700110 return m_pubKey;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700111}
112
Zhiyi Zhangbed854c2020-10-20 18:25:35 -0700113const std::vector<uint8_t>&
114ECDHState::deriveSecret(const std::vector<uint8_t>& peerKey)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700115{
Zhiyi Zhangbed854c2020-10-20 18:25:35 -0700116 return deriveSecret(peerKey.data(), peerKey.size());
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700117}
118
Zhiyi Zhangbed854c2020-10-20 18:25:35 -0700119const std::vector<uint8_t>&
120ECDHState::deriveSecret(const uint8_t* peerKey, size_t peerKeySize)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700121{
Zhiyi Zhangbed854c2020-10-20 18:25:35 -0700122 // prepare self private key
123 auto privECKey = EVP_PKEY_get1_EC_KEY(m_privkey);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700124 if (privECKey == nullptr) {
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700125 NDN_THROW(std::runtime_error("Could not get key when calling EVP_PKEY_get1_EC_KEY()"));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700126 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700127 auto group = EC_KEY_get0_group(privECKey);
Zhiyi Zhangbed854c2020-10-20 18:25:35 -0700128 EC_KEY_free(privECKey);
129 // prepare the peer public key
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700130 auto peerPoint = EC_POINT_new(group);
Zhiyi Zhangbed854c2020-10-20 18:25:35 -0700131 if (peerPoint == nullptr) {
132 NDN_THROW(std::runtime_error("TBD"));
133 }
134 if (EC_POINT_oct2point(group, peerPoint, peerKey, peerKeySize, nullptr) == 0) {
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700135 EC_POINT_free(peerPoint);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700136 NDN_THROW(std::runtime_error("Cannot convert peer's key into a EC point when calling EC_POINT_oct2point()"));
Zhiyi Zhang8da54d62019-11-21 00:03:05 -0800137 }
Zhiyi Zhangbed854c2020-10-20 18:25:35 -0700138 EC_KEY *ecPeerkey = EC_KEY_new();
139 if (ecPeerkey == nullptr) {
Zhiyi Zhang8da54d62019-11-21 00:03:05 -0800140 EC_POINT_free(peerPoint);
Zhiyi Zhangbed854c2020-10-20 18:25:35 -0700141 NDN_THROW(std::runtime_error("TBD"));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700142 }
Zhiyi Zhangbed854c2020-10-20 18:25:35 -0700143 if (EC_KEY_set_group(ecPeerkey, group) != 1) {
144 EC_POINT_free(peerPoint);
145 NDN_THROW(std::runtime_error("TBD"));
146 }
147 if (EC_KEY_set_public_key(ecPeerkey, peerPoint) == 0) {
148 EC_KEY_free(ecPeerkey);
149 EC_POINT_free(peerPoint);
150 NDN_THROW(std::runtime_error("Cannot initialize peer EC_KEY with the EC_POINT."));
151 }
152 EVP_PKEY *evpPeerkey = EVP_PKEY_new();
153 if (EVP_PKEY_set1_EC_KEY(evpPeerkey, ecPeerkey) == 0) {
154 EC_KEY_free(ecPeerkey);
155 EC_POINT_free(peerPoint);
156 NDN_THROW(std::runtime_error("TBD."));
157 }
158 EC_KEY_free(ecPeerkey);
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700159 EC_POINT_free(peerPoint);
Zhiyi Zhangbed854c2020-10-20 18:25:35 -0700160 // ECDH context
161 EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(m_privkey, NULL);
162 if (ctx == nullptr) {
163 EVP_PKEY_free(evpPeerkey);
164 NDN_THROW(std::runtime_error("TBD"));
165 }
166 /* Initialise */
167 if(1 != EVP_PKEY_derive_init(ctx)) {
168 EVP_PKEY_CTX_free(ctx);
169 EVP_PKEY_free(evpPeerkey);
170 NDN_THROW(std::runtime_error("TBD"));
171 }
172 /* Provide the peer public key */
173 if(1 != EVP_PKEY_derive_set_peer(ctx, evpPeerkey)) {
174 EVP_PKEY_CTX_free(ctx);
175 EVP_PKEY_free(evpPeerkey);
176 NDN_THROW(std::runtime_error("TBD"));
177 }
178 /* Determine buffer length for shared secret */
179 size_t secretLen = 0;
180 if(1 != EVP_PKEY_derive(ctx, NULL, &secretLen)) {
181 EVP_PKEY_CTX_free(ctx);
182 EVP_PKEY_free(evpPeerkey);
183 NDN_THROW(std::runtime_error("TBD"));
184 }
185 m_secret.resize(secretLen);
186 /* Derive the shared secret */
187 if(1 != (EVP_PKEY_derive(ctx, m_secret.data(), &secretLen))) {
188 EVP_PKEY_CTX_free(ctx);
189 EVP_PKEY_free(evpPeerkey);
190 NDN_THROW(std::runtime_error("TBD"));
191 }
192 // result = ECDH_compute_key(m_sharedSecret, sizeof(m_sharedSecret), peerPoint, privECKey, nullptr);
193 // if (result == -1) {
194 // EC_POINT_free(peerPoint);
195 // EC_KEY_free(privECKey);
196 // EVP_PKEY_free(m_privkey);
197 // NDN_THROW(std::runtime_error("Cannot generate ECDH secret when calling ECDH_compute_key()"));
198 // }
199 // m_sharedSecretLen = static_cast<size_t>(result);
200 // EC_POINT_free(peerPoint);
201 // EC_KEY_free(privECKey);
202 // return m_sharedSecret;
203 EVP_PKEY_CTX_free(ctx);
204 EVP_PKEY_free(evpPeerkey);
205 return m_secret;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700206}
207
Zhiyi Zhangbed854c2020-10-20 18:25:35 -0700208// uint8_t*
209// ECDHState::deriveSecret(const std::string& peerKeyStr)
210// {
211// namespace t = ndn::security::transform;
212// OBufferStream os;
213// t::bufferSource(peerKeyStr) >> t::base64Decode(false) >> t::streamSink(os);
214// auto result = os.buf();
215// return this->deriveSecret(result->data(), result->size());
216// }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700217
Zhiyi Zhangf12ee302020-10-14 17:46:44 -0700218void
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700219hmacSha256(const uint8_t* data, size_t dataLen,
220 const uint8_t* key, size_t keyLen,
Zhiyi Zhangcfad98d2020-10-11 11:25:14 -0700221 uint8_t* result)
Davide Pesavento368341b2019-08-13 23:57:50 -0400222{
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700223 auto ret = HMAC(EVP_sha256(), key, keyLen,
224 static_cast<const unsigned char*>(data), dataLen,
Zhiyi Zhang159ba632020-10-20 15:09:12 -0700225 static_cast<unsigned char*>(result), nullptr);
Zhiyi Zhangf12ee302020-10-14 17:46:44 -0700226 if (ret == nullptr) {
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700227 NDN_THROW(std::runtime_error("Error computing HMAC when calling HMAC()"));
Zhiyi Zhangf12ee302020-10-14 17:46:44 -0700228 }
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700229}
230
Zhiyi Zhang159ba632020-10-20 15:09:12 -0700231size_t
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700232hkdf(const uint8_t* secret, size_t secretLen, const uint8_t* salt,
233 size_t saltLen, uint8_t* output, size_t outputLen,
234 const uint8_t* info, size_t infoLen)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700235{
Zhiyi Zhangf12ee302020-10-14 17:46:44 -0700236 EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr);
237 if (EVP_PKEY_derive_init(pctx) <= 0) {
Zhiyi Zhang222810b2020-10-16 21:50:35 -0700238 EVP_PKEY_CTX_free(pctx);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700239 NDN_THROW(std::runtime_error("HKDF: Cannot init ctx when calling EVP_PKEY_derive_init()."));
Zhiyi Zhanga2ce5992019-08-14 17:35:00 -0700240 }
Zhiyi Zhangf12ee302020-10-14 17:46:44 -0700241 if (EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256()) <= 0) {
Zhiyi Zhang222810b2020-10-16 21:50:35 -0700242 EVP_PKEY_CTX_free(pctx);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700243 NDN_THROW(std::runtime_error("HKDF: Cannot set md when calling EVP_PKEY_CTX_set_hkdf_md()."));
Zhiyi Zhanga2ce5992019-08-14 17:35:00 -0700244 }
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700245 if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, salt, saltLen) <= 0) {
Zhiyi Zhang222810b2020-10-16 21:50:35 -0700246 EVP_PKEY_CTX_free(pctx);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700247 NDN_THROW(std::runtime_error("HKDF: Cannot set salt when calling EVP_PKEY_CTX_set1_hkdf_salt()."));
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700248 }
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700249 if (EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, secretLen) <= 0) {
Zhiyi Zhang222810b2020-10-16 21:50:35 -0700250 EVP_PKEY_CTX_free(pctx);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700251 NDN_THROW(std::runtime_error("HKDF: Cannot set secret when calling EVP_PKEY_CTX_set1_hkdf_key()."));
Zhiyi Zhangf12ee302020-10-14 17:46:44 -0700252 }
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700253 if (EVP_PKEY_CTX_add1_hkdf_info(pctx, info, infoLen) <= 0) {
Zhiyi Zhang222810b2020-10-16 21:50:35 -0700254 EVP_PKEY_CTX_free(pctx);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700255 NDN_THROW(std::runtime_error("HKDF: Cannot set info when calling EVP_PKEY_CTX_add1_hkdf_info()."));
Zhiyi Zhangf12ee302020-10-14 17:46:44 -0700256 }
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700257 size_t outLen = outputLen;
Zhiyi Zhangf12ee302020-10-14 17:46:44 -0700258 if (EVP_PKEY_derive(pctx, output, &outLen) <= 0) {
Zhiyi Zhang222810b2020-10-16 21:50:35 -0700259 EVP_PKEY_CTX_free(pctx);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700260 NDN_THROW(std::runtime_error("HKDF: Cannot derive result when calling EVP_PKEY_derive()."));
Zhiyi Zhangf12ee302020-10-14 17:46:44 -0700261 }
Zhiyi Zhang222810b2020-10-16 21:50:35 -0700262 EVP_PKEY_CTX_free(pctx);
Zhiyi Zhang159ba632020-10-20 15:09:12 -0700263 return outLen;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700264}
265
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700266int
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700267aesGcm128Encrypt(const uint8_t* plaintext, size_t plaintextLen, const uint8_t* associated, size_t associatedLen,
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700268 const uint8_t* key, const uint8_t* iv, uint8_t* ciphertext, uint8_t* tag)
269{
Zhiyi Zhangb8cb0472020-05-05 20:55:05 -0700270 EVP_CIPHER_CTX* ctx;
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700271 int len;
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700272 int ciphertextLen;
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700273 if (!(ctx = EVP_CIPHER_CTX_new())) {
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700274 NDN_THROW(std::runtime_error("Cannot create and initialise the context when calling EVP_CIPHER_CTX_new()"));
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700275 }
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700276 if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr)) {
Zhiyi Zhangdc25ddf2020-10-20 14:28:55 -0700277 EVP_CIPHER_CTX_free(ctx);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700278 NDN_THROW(std::runtime_error("Cannot initialise the encryption operation when calling EVP_EncryptInit_ex()"));
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700279 }
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700280 if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, nullptr)) {
Zhiyi Zhangdc25ddf2020-10-20 14:28:55 -0700281 EVP_CIPHER_CTX_free(ctx);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700282 NDN_THROW(std::runtime_error("Cannot set IV length when calling EVP_CIPHER_CTX_ctrl()"));
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700283 }
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700284 if (1 != EVP_EncryptInit_ex(ctx, nullptr, nullptr, key, iv)) {
Zhiyi Zhangdc25ddf2020-10-20 14:28:55 -0700285 EVP_CIPHER_CTX_free(ctx);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700286 NDN_THROW(std::runtime_error("Cannot initialize key and IV when calling EVP_EncryptInit_ex()"));
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700287 }
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700288 if (1 != EVP_EncryptUpdate(ctx, nullptr, &len, associated, associatedLen)) {
Zhiyi Zhangdc25ddf2020-10-20 14:28:55 -0700289 EVP_CIPHER_CTX_free(ctx);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700290 NDN_THROW(std::runtime_error("Cannot set associated authentication data when calling EVP_EncryptUpdate()"));
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700291 }
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700292 if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintextLen)) {
Zhiyi Zhangdc25ddf2020-10-20 14:28:55 -0700293 EVP_CIPHER_CTX_free(ctx);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700294 NDN_THROW(std::runtime_error("Cannot encrypt when calling EVP_EncryptUpdate()"));
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700295 }
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700296 ciphertextLen = len;
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700297 if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) {
Zhiyi Zhangdc25ddf2020-10-20 14:28:55 -0700298 EVP_CIPHER_CTX_free(ctx);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700299 NDN_THROW(std::runtime_error("Cannot finalise the encryption when calling EVP_EncryptFinal_ex()"));
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700300 }
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700301 ciphertextLen += len;
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700302 if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag)) {
Zhiyi Zhangdc25ddf2020-10-20 14:28:55 -0700303 EVP_CIPHER_CTX_free(ctx);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700304 NDN_THROW(std::runtime_error("Cannot get tag when calling EVP_CIPHER_CTX_ctrl()"));
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700305 }
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700306 EVP_CIPHER_CTX_free(ctx);
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700307 return ciphertextLen;
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700308}
309
310int
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700311aesGcm128Decrypt(const uint8_t* ciphertext, size_t ciphertextLen, const uint8_t* associated, size_t associatedLen,
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700312 const uint8_t* tag, const uint8_t* key, const uint8_t* iv, uint8_t* plaintext)
313{
314 EVP_CIPHER_CTX* ctx;
315 int len;
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700316 int plaintextLen;
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700317 int ret;
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700318 if (!(ctx = EVP_CIPHER_CTX_new())) {
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700319 NDN_THROW(std::runtime_error("Cannot create and initialise the context when calling EVP_CIPHER_CTX_new()"));
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700320 }
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700321 if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr)) {
Zhiyi Zhangdc25ddf2020-10-20 14:28:55 -0700322 EVP_CIPHER_CTX_free(ctx);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700323 NDN_THROW(std::runtime_error("Cannot initialise the decryption operation when calling EVP_DecryptInit_ex()"));
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700324 }
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700325 if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, nullptr)) {
Zhiyi Zhangdc25ddf2020-10-20 14:28:55 -0700326 EVP_CIPHER_CTX_free(ctx);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700327 NDN_THROW(std::runtime_error("Cannot set IV length when calling EVP_CIPHER_CTX_ctrl"));
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700328 }
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700329 if (!EVP_DecryptInit_ex(ctx, nullptr, nullptr, key, iv)) {
Zhiyi Zhangdc25ddf2020-10-20 14:28:55 -0700330 EVP_CIPHER_CTX_free(ctx);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700331 NDN_THROW(std::runtime_error("Cannot initialise key and IV when calling EVP_DecryptInit_ex()"));
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700332 }
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700333 if (!EVP_DecryptUpdate(ctx, nullptr, &len, associated, associatedLen)) {
Zhiyi Zhangdc25ddf2020-10-20 14:28:55 -0700334 EVP_CIPHER_CTX_free(ctx);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700335 NDN_THROW(std::runtime_error("Cannot set associated authentication data when calling EVP_EncryptUpdate()"));
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700336 }
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700337 if (!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertextLen)) {
Zhiyi Zhangdc25ddf2020-10-20 14:28:55 -0700338 EVP_CIPHER_CTX_free(ctx);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700339 NDN_THROW(std::runtime_error("Cannot decrypt when calling EVP_DecryptUpdate()"));
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700340 }
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700341 plaintextLen = len;
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700342 if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, (void*)tag)) {
Zhiyi Zhangdc25ddf2020-10-20 14:28:55 -0700343 EVP_CIPHER_CTX_free(ctx);
Zhiyi Zhang5c059452020-10-16 17:43:31 -0700344 NDN_THROW(std::runtime_error("Cannot set tag value when calling EVP_CIPHER_CTX_ctrl"));
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700345 }
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700346 ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700347 EVP_CIPHER_CTX_free(ctx);
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700348 if (ret > 0) {
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700349 plaintextLen += len;
350 return plaintextLen;
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700351 }
352 else {
Zhiyi Zhanga67fa462020-04-19 13:48:03 -0700353 return -1;
354 }
355}
356
Zhiyi Zhangc5d93a92020-10-14 17:07:35 -0700357Block
Zhiyi Zhang159ba632020-10-20 15:09:12 -0700358encodeBlockWithAesGcm128(uint32_t tlvType, const uint8_t* key, const uint8_t* payload, size_t payloadSize,
Zhiyi Zhang222810b2020-10-16 21:50:35 -0700359 const uint8_t* associatedData, size_t associatedDataSize, uint32_t& counter)
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700360{
Zhiyi Zhang222810b2020-10-16 21:50:35 -0700361 Buffer iv(12);
Zhiyi Zhangc5d93a92020-10-14 17:07:35 -0700362 random::generateSecureBytes(iv.data(), iv.size());
Zhiyi Zhang159ba632020-10-20 15:09:12 -0700363 if (tlvType == ndn::tlv::ApplicationParameters) {
Zhiyi Zhang222810b2020-10-16 21:50:35 -0700364 // requester
365 iv[0] &= ~(1UL << 7);
366 }
367 else {
368 // CA
369 iv[0] |= 1UL << 7;
370 }
Zhiyi Zhang159ba632020-10-20 15:09:12 -0700371 uint32_t temp = boost::endian::native_to_big(counter);
Zhiyi Zhang222810b2020-10-16 21:50:35 -0700372 std::memcpy(&iv[8], reinterpret_cast<const uint8_t*>(&temp), 4);
Zhiyi Zhang159ba632020-10-20 15:09:12 -0700373 uint32_t increment = std::ceil((payloadSize + 16 - 1)/16);
374 if (std::numeric_limits<uint32_t>::max() - counter < increment) {
375 // simply set counter to be 0. Will not hurt the property of being unique.
376 counter = 0;
377 }
378 else {
379 counter += increment;
380 }
Zhiyi Zhangc5d93a92020-10-14 17:07:35 -0700381
Zhiyi Zhang222810b2020-10-16 21:50:35 -0700382 Buffer encryptedPayload(payloadSize);
Zhiyi Zhangc5d93a92020-10-14 17:07:35 -0700383 uint8_t tag[16];
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700384 size_t encryptedPayloadLen = aesGcm128Encrypt(payload, payloadSize, associatedData, associatedDataSize,
Zhiyi Zhang222810b2020-10-16 21:50:35 -0700385 key, iv.data(), encryptedPayload.data(), tag);
Zhiyi Zhang159ba632020-10-20 15:09:12 -0700386 auto content = makeEmptyBlock(tlvType);
Zhiyi Zhangc5d93a92020-10-14 17:07:35 -0700387 content.push_back(makeBinaryBlock(tlv::InitializationVector, iv.data(), iv.size()));
388 content.push_back(makeBinaryBlock(tlv::AuthenticationTag, tag, 16));
Zhiyi Zhang222810b2020-10-16 21:50:35 -0700389 content.push_back(makeBinaryBlock(tlv::EncryptedPayload, encryptedPayload.data(), encryptedPayloadLen));
Zhiyi Zhangc5d93a92020-10-14 17:07:35 -0700390 content.encode();
Zhiyi Zhangc5d93a92020-10-14 17:07:35 -0700391 return content;
392}
393
394Buffer
395decodeBlockWithAesGcm128(const Block& block, const uint8_t* key, const uint8_t* associatedData, size_t associatedDataSize)
396{
397 block.parse();
Zhiyi Zhangcace6ab2020-10-16 21:51:44 -0700398 Buffer result(block.get(tlv::EncryptedPayload).value_size());
Zhiyi Zhang11cf7eb2020-10-20 15:43:36 -0700399 int resultLen = aesGcm128Decrypt(block.get(tlv::EncryptedPayload).value(),
Zhiyi Zhangc5d93a92020-10-14 17:07:35 -0700400 block.get(tlv::EncryptedPayload).value_size(),
401 associatedData, associatedDataSize, block.get(tlv::AuthenticationTag).value(),
402 key, block.get(tlv::InitializationVector).value(), result.data());
403 if (resultLen == -1 || resultLen != (int)block.get(tlv::EncryptedPayload).value_size()) {
404 return Buffer();
405 }
406 return result;
Zhiyi Zhangaf7c2902019-03-14 22:13:21 -0700407}
408
Zhiyi Zhange4891b72020-10-10 15:11:57 -0700409} // namespace ndncert
410} // namespace ndn