ndn-embeds 0.1.0
Lightweight NDN protocol stack for embedded systems
Loading...
Searching...
No Matches
crypto.cpp
Go to the documentation of this file.
1
6#include "ndn/crypto.hpp"
7#include "ndn/signature.hpp"
8
9#include <cstring>
10#include <mbedtls/ctr_drbg.h>
11#include <mbedtls/ecdsa.h>
12#include <mbedtls/ecp.h>
13#include <mbedtls/entropy.h>
14#include <mbedtls/md.h>
15#include <mbedtls/sha256.h>
16
17namespace ndn::crypto {
18
19Error sha256(const uint8_t* data, size_t len, uint8_t* out) {
20 if (data == nullptr || out == nullptr) {
21 return Error::InvalidParam;
22 }
23
24 mbedtls_sha256_context ctx;
25 mbedtls_sha256_init(&ctx);
26
27 int ret = mbedtls_sha256_starts(&ctx, 0); // 0 = SHA-256 (not SHA-224)
28 if (ret != 0) {
29 mbedtls_sha256_free(&ctx);
30 return Error::DecodeFailed;
31 }
32
33 ret = mbedtls_sha256_update(&ctx, data, len);
34 if (ret != 0) {
35 mbedtls_sha256_free(&ctx);
36 return Error::DecodeFailed;
37 }
38
39 ret = mbedtls_sha256_finish(&ctx, out);
40 mbedtls_sha256_free(&ctx);
41
42 return (ret == 0) ? Error::Success : Error::DecodeFailed;
43}
44
45Error hmacSha256(const uint8_t* key, size_t keyLen, const uint8_t* data, size_t dataLen,
46 uint8_t* out) {
47 if (key == nullptr || data == nullptr || out == nullptr) {
48 return Error::InvalidParam;
49 }
50
51 const mbedtls_md_info_t* mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
52 if (mdInfo == nullptr) {
53 return Error::DecodeFailed;
54 }
55
56 int ret = mbedtls_md_hmac(mdInfo, key, keyLen, data, dataLen, out);
57 return (ret == 0) ? Error::Success : Error::DecodeFailed;
58}
59
60bool constantTimeCompare(const uint8_t* lhs, const uint8_t* rhs, size_t len) {
61 if (lhs == nullptr || rhs == nullptr) {
62 return false;
63 }
64
65 volatile uint8_t result = 0;
66 for (size_t i = 0; i < len; ++i) {
67 result |= lhs[i] ^ rhs[i];
68 }
69 return result == 0;
70}
71
72Error ecdsaP256GenerateKeyPair(uint8_t* privKey, uint8_t* pubKey) {
73 if (privKey == nullptr || pubKey == nullptr) {
74 return Error::InvalidParam;
75 }
76
77 mbedtls_entropy_context entropy;
78 mbedtls_ctr_drbg_context ctrDrbg;
79 mbedtls_ecdsa_context ecdsa;
80
81 mbedtls_entropy_init(&entropy);
82 mbedtls_ctr_drbg_init(&ctrDrbg);
83 mbedtls_ecdsa_init(&ecdsa);
84
85 Error err = Error::Success;
86 size_t pubKeyLen = 0;
87 const char* pers = "ndn_ecdsa_keygen";
88
89 // Initialize random number generator
90 int ret = mbedtls_ctr_drbg_seed(&ctrDrbg, mbedtls_entropy_func, &entropy,
91 reinterpret_cast<const unsigned char*>(pers), strlen(pers));
92 if (ret != 0) {
93 err = Error::DecodeFailed;
94 goto cleanup;
95 }
96
97 // Generate P-256 key pair
98 ret = mbedtls_ecdsa_genkey(&ecdsa, MBEDTLS_ECP_DP_SECP256R1, mbedtls_ctr_drbg_random, &ctrDrbg);
99 if (ret != 0) {
100 err = Error::DecodeFailed;
101 goto cleanup;
102 }
103
104 // Export private key (32 bytes, big-endian)
105 ret = mbedtls_ecp_write_key_ext(&ecdsa, &pubKeyLen, privKey, ECDSA_P256_PRIVKEY_SIZE);
106 if (ret != 0) {
107 err = Error::DecodeFailed;
108 goto cleanup;
109 }
110
111 // Export public key (65 bytes, uncompressed format: 0x04 || X || Y)
112 ret = mbedtls_ecp_write_public_key(&ecdsa, MBEDTLS_ECP_PF_UNCOMPRESSED, &pubKeyLen, pubKey,
114 if (ret != 0 || pubKeyLen != ECDSA_P256_PUBKEY_SIZE) {
115 err = Error::DecodeFailed;
116 goto cleanup;
117 }
118
119cleanup:
120 mbedtls_ecdsa_free(&ecdsa);
121 mbedtls_ctr_drbg_free(&ctrDrbg);
122 mbedtls_entropy_free(&entropy);
123 return err;
124}
125
126Error ecdsaP256Sign(const uint8_t* privKey, const uint8_t* data, size_t dataLen, uint8_t* sig,
127 size_t* sigLen) {
128 if (privKey == nullptr || data == nullptr || sig == nullptr || sigLen == nullptr) {
129 return Error::InvalidParam;
130 }
131
132 mbedtls_entropy_context entropy;
133 mbedtls_ctr_drbg_context ctrDrbg;
134 mbedtls_ecdsa_context ecdsa;
135
136 mbedtls_entropy_init(&entropy);
137 mbedtls_ctr_drbg_init(&ctrDrbg);
138 mbedtls_ecdsa_init(&ecdsa);
139
140 Error err = Error::Success;
141 uint8_t hash[SHA256_DIGEST_SIZE];
142 const char* pers = "ndn_ecdsa_sign";
143
144 // Initialize random number generator
145 int ret = mbedtls_ctr_drbg_seed(&ctrDrbg, mbedtls_entropy_func, &entropy,
146 reinterpret_cast<const unsigned char*>(pers), strlen(pers));
147 if (ret != 0) {
148 err = Error::DecodeFailed;
149 goto cleanup;
150 }
151
152 // Import private key (group is also set automatically)
153 ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &ecdsa, privKey, ECDSA_P256_PRIVKEY_SIZE);
154 if (ret != 0) {
155 err = Error::DecodeFailed;
156 goto cleanup;
157 }
158
159 // Compute SHA-256 hash of the data
160 err = sha256(data, dataLen, hash);
161 if (err != Error::Success) {
162 goto cleanup;
163 }
164
165 // Generate ECDSA signature (DER format)
166 ret = mbedtls_ecdsa_write_signature(&ecdsa, MBEDTLS_MD_SHA256, hash, sizeof(hash), sig,
167 ECDSA_P256_SIG_MAX_SIZE, sigLen, mbedtls_ctr_drbg_random,
168 &ctrDrbg);
169 if (ret != 0) {
170 err = Error::DecodeFailed;
171 goto cleanup;
172 }
173
174cleanup:
175 mbedtls_ecdsa_free(&ecdsa);
176 mbedtls_ctr_drbg_free(&ctrDrbg);
177 mbedtls_entropy_free(&entropy);
178 return err;
179}
180
181bool ecdsaP256Verify(const uint8_t* pubKey, const uint8_t* data, size_t dataLen, const uint8_t* sig,
182 size_t sigLen) {
183 if (pubKey == nullptr || data == nullptr || sig == nullptr || sigLen == 0) {
184 return false;
185 }
186
187 mbedtls_ecdsa_context ecdsa;
188 mbedtls_ecp_group grp;
189 mbedtls_ecp_point Q;
190
191 mbedtls_ecdsa_init(&ecdsa);
192 mbedtls_ecp_group_init(&grp);
193 mbedtls_ecp_point_init(&Q);
194
195 bool valid = false;
196 uint8_t hash[SHA256_DIGEST_SIZE];
197
198 // Set up elliptic curve group
199 int ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1);
200 if (ret != 0) {
201 goto cleanup;
202 }
203
204 // Load public key as a point (uncompressed format: 0x04 || X || Y)
205 ret = mbedtls_ecp_point_read_binary(&grp, &Q, pubKey, ECDSA_P256_PUBKEY_SIZE);
206 if (ret != 0) {
207 goto cleanup;
208 }
209
210 // Set public key in the ECDSA context
211 ret = mbedtls_ecp_set_public_key(MBEDTLS_ECP_DP_SECP256R1, &ecdsa, &Q);
212 if (ret != 0) {
213 goto cleanup;
214 }
215
216 // Compute SHA-256 hash of the data
217 if (sha256(data, dataLen, hash) != Error::Success) {
218 goto cleanup;
219 }
220
221 // Verify ECDSA signature
222 ret = mbedtls_ecdsa_read_signature(&ecdsa, hash, sizeof(hash), sig, sigLen);
223 valid = (ret == 0);
224
225cleanup:
226 mbedtls_ecp_point_free(&Q);
227 mbedtls_ecp_group_free(&grp);
228 mbedtls_ecdsa_free(&ecdsa);
229 return valid;
230}
231
232} // namespace ndn::crypto
Error
Error codes.
Definition common.hpp:24
NDN cryptographic utilities.
Error ecdsaP256GenerateKeyPair(uint8_t *privKey, uint8_t *pubKey)
Generate an ECDSA P-256 key pair.
Definition crypto.cpp:72
Error hmacSha256(const uint8_t *key, size_t keyLen, const uint8_t *data, size_t dataLen, uint8_t *out)
Compute HMAC-SHA256.
Definition crypto.cpp:45
bool ecdsaP256Verify(const uint8_t *pubKey, const uint8_t *data, size_t dataLen, const uint8_t *sig, size_t sigLen)
Verify an ECDSA P-256 signature.
Definition crypto.cpp:181
bool constantTimeCompare(const uint8_t *lhs, const uint8_t *rhs, size_t len)
Compare two buffers in constant time.
Definition crypto.cpp:60
Error ecdsaP256Sign(const uint8_t *privKey, const uint8_t *data, size_t dataLen, uint8_t *sig, size_t *sigLen)
Sign with ECDSA P-256.
Definition crypto.cpp:126
Error sha256(const uint8_t *data, size_t len, uint8_t *out)
Compute SHA-256 hash.
Definition crypto.cpp:19
NDN signature types and constants.
constexpr size_t ECDSA_P256_PUBKEY_SIZE
ECDSA P-256 public key size (uncompressed form)
Definition signature.hpp:44
constexpr size_t ECDSA_P256_SIG_MAX_SIZE
ECDSA P-256 signature max size (DER format)
Definition signature.hpp:35
constexpr size_t ECDSA_P256_PRIVKEY_SIZE
ECDSA P-256 private key size.
Definition signature.hpp:45
constexpr size_t SHA256_DIGEST_SIZE
SHA-256 digest size (bytes)
Definition signature.hpp:33