esp8266ndn
NDN Arduino library for ESP8266 and more
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
mbed-common.hpp
Go to the documentation of this file.
1 #ifndef NDNPH_PORT_MBED_COMMON_HPP
2 #define NDNPH_PORT_MBED_COMMON_HPP
3 #ifdef NDNPH_HAVE_MBED
4 
5 #include "../keychain/iv.hpp"
6 #include "random/port.hpp"
7 #include <mbedtls/bignum.h>
8 #include <mbedtls/ecdh.h>
9 #include <mbedtls/ecp.h>
10 #include <mbedtls/gcm.h>
11 #include <mbedtls/md.h>
12 #include <mbedtls/sha256.h>
13 
14 #ifndef MBEDTLS_ECDSA_DETERMINISTIC
15 #error MBEDTLS_ECDSA_DETERMINISTIC must be declared
16 #endif
17 
18 #if MBEDTLS_VERSION_MAJOR >= 3
19 #define NDNPH_MBEDTLS_RET2(func) func
20 #else
21 #define NDNPH_MBEDTLS_RET2(func) func##_ret
22 #endif
23 
24 namespace ndnph {
26 namespace mbedtls {
27 
29 inline int
30 rng(void*, uint8_t* output, size_t count) {
31  bool ok = port::RandomSource::generate(output, count);
32  return ok ? 0 : -1;
33 }
34 
36 class Sha256 {
37 public:
38  explicit Sha256() {
39  mbedtls_sha256_init(&m_ctx);
40  m_ok = NDNPH_MBEDTLS_RET2(mbedtls_sha256_starts)(&m_ctx, 0) == 0;
41  }
42 
43  ~Sha256() {
44  mbedtls_sha256_free(&m_ctx);
45  }
46 
47  void update(const uint8_t* chunk, size_t size) {
48  m_ok = m_ok && NDNPH_MBEDTLS_RET2(mbedtls_sha256_update)(&m_ctx, chunk, size) == 0;
49  }
50 
51  bool final(uint8_t digest[NDNPH_SHA256_LEN]) {
52  m_ok = m_ok && NDNPH_MBEDTLS_RET2(mbedtls_sha256_finish)(&m_ctx, digest) == 0;
53  return m_ok;
54  }
55 
56 private:
57  mbedtls_sha256_context m_ctx;
58  bool m_ok = false;
59 };
60 
66 template<mbedtls_md_type_t mdType, size_t mdSize>
67 class Hmac {
68 public:
70  explicit Hmac(const uint8_t* key, size_t keyLen) {
71  mbedtls_md_init(&m_ctx);
72  m_ok = mbedtls_md_setup(&m_ctx, mbedtls_md_info_from_type(mdType), 1) == 0 &&
73  mbedtls_md_hmac_starts(&m_ctx, key, keyLen) == 0;
74  }
75 
76  ~Hmac() {
77  mbedtls_md_free(&m_ctx);
78  }
79 
81  void update(const uint8_t* chunk, size_t size) {
82  m_ok = m_ok && mbedtls_md_hmac_update(&m_ctx, chunk, size) == 0;
83  }
84 
90  bool final(uint8_t result[mdSize]) {
91  m_ok =
92  m_ok && mbedtls_md_hmac_finish(&m_ctx, result) == 0 && mbedtls_md_hmac_reset(&m_ctx) == 0;
93  return m_ok;
94  }
95 
96 private:
97  mbedtls_md_context_t m_ctx;
98  bool m_ok = false;
99 };
100 
102 class Mpi {
103 public:
105  explicit Mpi() {
106  mbedtls_mpi_init(&m_value);
107  }
108 
110  explicit Mpi(const mbedtls_mpi* src)
111  : Mpi() {
112  mbedtls_mpi_copy(&m_value, src);
113  }
114 
116  explicit Mpi(mbedtls_mpi_sint src)
117  : Mpi() {
118  mbedtls_mpi_lset(&m_value, src);
119  }
120 
121  ~Mpi() {
122  mbedtls_mpi_free(&m_value);
123  }
124 
125  operator mbedtls_mpi*() {
126  return &m_value;
127  }
128 
129  operator const mbedtls_mpi*() const {
130  return &m_value;
131  }
132 
134  Mpi& operator=(const Mpi&) = delete;
135 
140  Mpi& operator=(Mpi&& y) {
141  mbedtls_mpi_swap(&m_value, &y.m_value);
142  return *this;
143  }
144 
145 private:
146  mbedtls_mpi m_value;
147 };
148 
150 class EcPoint {
151 public:
153  explicit EcPoint() {
154  mbedtls_ecp_point_init(&m_value);
155  }
156 
158  explicit EcPoint(const mbedtls_ecp_point* q)
159  : EcPoint() {
160  if (q != nullptr) {
161  mbedtls_ecp_copy(&m_value, q);
162  }
163  }
164 
166  mbedtls_ecp_point_free(&m_value);
167  }
168 
169  operator mbedtls_ecp_point*() {
170  return &m_value;
171  }
172 
173  operator const mbedtls_ecp_point*() const {
174  return &m_value;
175  }
176 
178  EcPoint& operator=(const EcPoint&) = delete;
179 
180  bool writeBinary(mbedtls_ecp_group* group, uint8_t* room, size_t length) const {
181  size_t actualLength = 0;
182  return mbedtls_ecp_point_write_binary(group, *this, MBEDTLS_ECP_PF_UNCOMPRESSED, &actualLength,
183  room, length) == 0 &&
184  actualLength == length;
185  }
186 
187  void encodeTo(mbedtls_ecp_group* group, Encoder& encoder, size_t length) const {
188  uint8_t* room = encoder.prependRoom(length);
189  if (room == nullptr) {
190  return;
191  }
192 
193  if (!writeBinary(group, room, length)) {
194  encoder.setError();
195  }
196  }
197 
198  bool readBinary(mbedtls_ecp_group* group, const uint8_t* value, size_t length) {
199  return mbedtls_ecp_point_read_binary(group, *this, value, length) == 0 &&
200  mbedtls_ecp_check_pubkey(group, *this) == 0;
201  }
202 
203  bool decodeFrom(mbedtls_ecp_group* group, const Decoder::Tlv& d) {
204  return readBinary(group, d.value, d.length);
205  }
206 
207 private:
208  mbedtls_ecp_point m_value;
209 };
210 
212 template<typename Curve>
213 class EcCurvePoint : public EcPoint {
214 public:
215  bool writeBinary(uint8_t room[Curve::PubLen::value]) const {
216  return EcPoint::writeBinary(Curve::group(), room, Curve::PubLen::value);
217  }
218 
219  void encodeTo(Encoder& encoder) const {
220  return EcPoint::encodeTo(Curve::group(), encoder, Curve::PubLen::value);
221  }
222 
223  bool readBinary(const uint8_t* value, size_t length) {
224  return EcPoint::readBinary(Curve::group(), value, length);
225  }
226 
227  bool decodeFrom(const Decoder::Tlv& d) {
228  return EcPoint::decodeFrom(Curve::group(), d);
229  }
230 };
231 
233 class P256 {
234 public:
235  using PvtLen = std::integral_constant<size_t, 32>;
236  using PubLen = std::integral_constant<size_t, 65>;
237  using MaxSigLen = std::integral_constant<size_t, 74>;
239 
240  static mbedtls_ecp_group* group() {
241  static struct S {
242  S() {
243  int res = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1);
244  NDNPH_ASSERT(res == 0);
245  }
246  mbedtls_ecp_group grp;
247  } s;
248  return &s.grp;
249  };
250 
252  using SharedSecret = std::array<uint8_t, PvtLen::value>;
253 
255  static bool ecdh(const mbedtls_mpi* pvt, const mbedtls_ecp_point* pub, SharedSecret& shared) {
256  Mpi z;
257  return mbedtls_ecdh_compute_shared(group(), z, pub, pvt, rng, nullptr) == 0 &&
258  mbedtls_mpi_write_binary(z, shared.data(), shared.size()) == 0;
259  }
260 };
261 
269 template<int keyBits>
270 class AesGcm {
271 public:
272  static_assert(keyBits == 128 || keyBits == 256, "");
273  using Key = std::array<uint8_t, keyBits / 8>;
275  using TagLen = std::integral_constant<size_t, 16>;
276 
277  explicit AesGcm() {
278  mbedtls_gcm_init(&m_ctx);
279  }
280 
282  mbedtls_gcm_free(&m_ctx);
283  }
284 
285  AesGcm(const AesGcm&) = delete;
286  AesGcm& operator=(const AesGcm&) = delete;
287 
292  bool import(const Key& key) {
293  m_ok = mbedtls_gcm_setkey(&m_ctx, MBEDTLS_CIPHER_ID_AES, key.data(), keyBits) == 0 &&
294  m_ivEncrypt.randomize();
295  return m_ok;
296  }
297 
308  template<typename Encrypted>
309  tlv::Value encrypt(Region& region, tlv::Value plaintext, const uint8_t* aad = nullptr,
310  size_t aadLen = 0) {
311  checkEncryptedMessage<Encrypted>();
312  Encoder encoder(region);
313  auto place = Encrypted::prependInPlace(encoder, plaintext.size());
314  encoder.trim();
315 
316  bool ok = m_ok && !!encoder && m_ivEncrypt.write(place.iv) &&
317  mbedtls_gcm_crypt_and_tag(&m_ctx, MBEDTLS_GCM_ENCRYPT, plaintext.size(), place.iv,
318  IvLen::value, aad, aadLen, plaintext.begin(),
319  place.ciphertext, TagLen::value, place.tag) == 0 &&
320  m_ivEncrypt.advance(plaintext.size());
321  if (!ok) {
322  encoder.discard();
323  return tlv::Value();
324  }
325  return tlv::Value(encoder);
326  }
327 
343  template<typename Encrypted>
344  tlv::Value decrypt(Region& region, const Encrypted& encrypted, const uint8_t* aad = nullptr,
345  size_t aadLen = 0) {
346  checkEncryptedMessage<Encrypted>();
347  uint8_t* plaintext = region.alloc(encrypted.ciphertext.size());
348  bool ok =
349  m_ok && m_ivDecrypt.check(encrypted.iv.data(), encrypted.ciphertext.size()) &&
350  plaintext != nullptr &&
351  mbedtls_gcm_auth_decrypt(&m_ctx, encrypted.ciphertext.size(), encrypted.iv.data(),
352  encrypted.iv.size(), aad, aadLen, encrypted.tag.data(),
353  encrypted.tag.size(), encrypted.ciphertext.begin(), plaintext) == 0;
354  if (!ok) {
355  region.free(plaintext, encrypted.ciphertext.size());
356  return tlv::Value();
357  }
358  return tlv::Value(plaintext, encrypted.ciphertext.size());
359  }
360 
362  m_ivDecrypt = AesGcmIvHelper();
363  }
364 
365 private:
366  template<typename Encrypted>
367  static void checkEncryptedMessage() {
368  static_assert(Encrypted::IvLen::value == IvLen::value, "");
369  static_assert(Encrypted::TagLen::value == TagLen::value, "");
370  }
371 
372 private:
373  mbedtls_gcm_context m_ctx;
374  AesGcmIvHelper m_ivEncrypt;
375  AesGcmIvHelper m_ivDecrypt;
376  bool m_ok = false;
377 };
378 
379 } // namespace mbedtls
380 } // namespace ndnph
381 
382 #endif // NDNPH_HAVE_MBED
383 #endif // NDNPH_PORT_MBED_COMMON_HPP
static bool generate(uint8_t *output, size_t count)
AES-GCM Initialization Vector generator and checker.
Definition: iv.hpp:18
bool check(const uint8_t *iv, size_t size)
Check received IV.
Definition: iv.hpp:59
std::integral_constant< size_t, 12 > IvLen
IV length.
Definition: iv.hpp:21
bool write(uint8_t room[12])
Write IV to room .
Definition: iv.hpp:33
bool randomize()
Randomize the random number portion.
Definition: iv.hpp:27
bool advance(size_t size)
Advance the counter portion.
Definition: iv.hpp:43
Decoded TLV.
Definition: decoder.hpp:13
size_t length
Definition: decoder.hpp:39
const uint8_t * value
Definition: decoder.hpp:40
TLV encoder that accepts items in reverse order.
Definition: encoder.hpp:10
void trim() const
Release unused space to the Region.
Definition: encoder.hpp:58
void discard()
Release all space to the Region.
Definition: encoder.hpp:72
uint8_t * prependRoom(size_t size)
Make room to prepend an object.
Definition: encoder.hpp:90
void setError()
Indicate an error has occurred.
Definition: encoder.hpp:166
Region-based memory allocator thats owns memory of NDNph objects.
Definition: region.hpp:9
uint8_t * alloc(size_t size)
Allocate a buffer with no alignment requirement.
Definition: region.hpp:27
bool free(const uint8_t *first, const uint8_t *last)
Deallocate (part of) last allocated buffer.
Definition: region.hpp:51
AES-GCM secret key.
Definition: mbed-common.hpp:270
AesGcm & operator=(const AesGcm &)=delete
tlv::Value encrypt(Region &region, tlv::Value plaintext, const uint8_t *aad=nullptr, size_t aadLen=0)
Encrypt to encrypted-message.
Definition: mbed-common.hpp:309
AesGcm()
Definition: mbed-common.hpp:277
~AesGcm()
Definition: mbed-common.hpp:281
tlv::Value decrypt(Region &region, const Encrypted &encrypted, const uint8_t *aad=nullptr, size_t aadLen=0)
Decrypt from encrypted-message.
Definition: mbed-common.hpp:344
AesGcm(const AesGcm &)=delete
std::integral_constant< size_t, 16 > TagLen
Definition: mbed-common.hpp:275
std::array< uint8_t, keyBits/8 > Key
Definition: mbed-common.hpp:273
void clearDecryptIvChecker()
Definition: mbed-common.hpp:361
AesGcmIvHelper::IvLen IvLen
Definition: mbed-common.hpp:274
EC point associated with a curve.
Definition: mbed-common.hpp:213
bool readBinary(const uint8_t *value, size_t length)
Definition: mbed-common.hpp:223
bool decodeFrom(const Decoder::Tlv &d)
Definition: mbed-common.hpp:227
void encodeTo(Encoder &encoder) const
Definition: mbed-common.hpp:219
bool writeBinary(uint8_t room[Curve::PubLen::value]) const
Definition: mbed-common.hpp:215
EC point.
Definition: mbed-common.hpp:150
~EcPoint()
Definition: mbed-common.hpp:165
EcPoint(const mbedtls_ecp_point *q)
Construct from EC point.
Definition: mbed-common.hpp:158
EcPoint & operator=(const EcPoint &)=delete
Copy assignment is disallowed due to lack of error handling.
void encodeTo(mbedtls_ecp_group *group, Encoder &encoder, size_t length) const
Definition: mbed-common.hpp:187
bool decodeFrom(mbedtls_ecp_group *group, const Decoder::Tlv &d)
Definition: mbed-common.hpp:203
bool readBinary(mbedtls_ecp_group *group, const uint8_t *value, size_t length)
Definition: mbed-common.hpp:198
EcPoint()
Construct zero.
Definition: mbed-common.hpp:153
bool writeBinary(mbedtls_ecp_group *group, uint8_t *room, size_t length) const
Definition: mbed-common.hpp:180
HMAC algorithm.
Definition: mbed-common.hpp:67
~Hmac()
Definition: mbed-common.hpp:76
void update(const uint8_t *chunk, size_t size)
Append bytes into hash state.
Definition: mbed-common.hpp:81
Hmac(const uint8_t *key, size_t keyLen)
Start HMAC operation and set key.
Definition: mbed-common.hpp:70
Multi-Precision Integer.
Definition: mbed-common.hpp:102
Mpi()
Construct zero.
Definition: mbed-common.hpp:105
Mpi & operator=(const Mpi &)=delete
Copy assignment is disallowed due to lack of error handling.
Mpi(const mbedtls_mpi *src)
Construct from MPI.
Definition: mbed-common.hpp:110
Mpi & operator=(Mpi &&y)
Move assignment.
Definition: mbed-common.hpp:140
Mpi(mbedtls_mpi_sint src)
Construct from integer.
Definition: mbed-common.hpp:116
~Mpi()
Definition: mbed-common.hpp:121
EC curve P256.
Definition: mbed-common.hpp:233
static mbedtls_ecp_group * group()
Definition: mbed-common.hpp:240
std::integral_constant< size_t, 74 > MaxSigLen
Definition: mbed-common.hpp:237
std::array< uint8_t, PvtLen::value > SharedSecret
ECDH shared secret buffer.
Definition: mbed-common.hpp:252
static bool ecdh(const mbedtls_mpi *pvt, const mbedtls_ecp_point *pub, SharedSecret &shared)
Compute ECDH shared secret.
Definition: mbed-common.hpp:255
std::integral_constant< size_t, 65 > PubLen
Definition: mbed-common.hpp:236
std::integral_constant< size_t, 32 > PvtLen
Definition: mbed-common.hpp:235
SHA256 hash function.
Definition: mbed-common.hpp:36
Sha256()
Definition: mbed-common.hpp:38
~Sha256()
Definition: mbed-common.hpp:43
void update(const uint8_t *chunk, size_t size)
Definition: mbed-common.hpp:47
A sequence of bytes, usually TLV-VALUE.
Definition: value.hpp:11
const uint8_t * begin() const
Definition: value.hpp:38
size_t size() const
Definition: value.hpp:46
#define NDNPH_ASSERT(x)
Definition: common.hpp:30
#define NDNPH_SHA256_LEN
SHA256 digest length.
Definition: common.hpp:34
#define NDNPH_MBEDTLS_RET2(func)
Definition: mbed-common.hpp:21
void output(const Encodable &packet, std::ostream &os=std::cout)
Write an Encodable to output stream.
Definition: io.hpp:33
int rng(void *, uint8_t *output, size_t count)
Random number generator for various Mbed TLS library functions.
Definition: mbed-common.hpp:30
Definition: fs.hpp:33