fix little endian vs big endian in the macros... again... but this time correct
[RRG-proxmark3.git] / client / src / crypto / libpcrypto.c
blob723753d5fe88c594df38cc696e47bfb18d1ad34d
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2018 Merlok
3 // Copyright (C) 2018 drHatson
4 //
5 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
6 // at your option, any later version. See the LICENSE.txt file for the text of
7 // the license.
8 //-----------------------------------------------------------------------------
9 // crypto commands
10 //-----------------------------------------------------------------------------
12 #include "crypto/libpcrypto.h"
13 #include "crypto/asn1utils.h"
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <string.h>
17 #include <mbedtls/asn1.h>
18 #include <mbedtls/aes.h>
19 #include <mbedtls/cmac.h>
20 #include <mbedtls/pk.h>
21 #include <mbedtls/ecdsa.h>
22 #include <mbedtls/sha1.h>
23 #include <mbedtls/sha256.h>
24 #include <mbedtls/sha512.h>
25 #include <mbedtls/ctr_drbg.h>
26 #include <mbedtls/entropy.h>
27 #include <mbedtls/error.h>
28 #include "util.h"
29 #include "ui.h"
30 // NIST Special Publication 800-38A — Recommendation for block cipher modes of operation: methods and techniques, 2001.
31 int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length) {
32 uint8_t iiv[16] = {0};
33 if (iv)
34 memcpy(iiv, iv, 16);
36 mbedtls_aes_context aes;
37 mbedtls_aes_init(&aes);
38 if (mbedtls_aes_setkey_enc(&aes, key, 128))
39 return 1;
40 if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, length, iiv, input, output))
41 return 2;
42 mbedtls_aes_free(&aes);
44 return 0;
47 int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length) {
48 uint8_t iiv[16] = {0};
49 if (iv)
50 memcpy(iiv, iv, 16);
52 mbedtls_aes_context aes;
53 mbedtls_aes_init(&aes);
54 if (mbedtls_aes_setkey_dec(&aes, key, 128))
55 return 1;
56 if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, length, iiv, input, output))
57 return 2;
58 mbedtls_aes_free(&aes);
60 return 0;
63 // NIST Special Publication 800-38B — Recommendation for block cipher modes of operation: The CMAC mode for authentication.
64 // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CMAC.pdf
65 int aes_cmac(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length) {
66 memset(mac, 0x00, 16);
68 // NIST 800-38B
69 return mbedtls_aes_cmac_prf_128(key, MBEDTLS_AES_BLOCK_SIZE, input, length, mac);
72 int aes_cmac8(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length) {
73 uint8_t cmac_tmp[16] = {0};
74 memset(mac, 0x00, 8);
76 int res = aes_cmac(iv, key, input, cmac_tmp, length);
77 if (res)
78 return res;
80 for (int i = 0; i < 8; i++)
81 mac[i] = cmac_tmp[i * 2 + 1];
83 return 0;
86 static uint8_t fixed_rand_value[250] = {0};
87 static int fixed_rand(void *rng_state, unsigned char *output, size_t len) {
88 if (len <= 250) {
89 memcpy(output, fixed_rand_value, len);
90 } else {
91 memset(output, 0x00, len);
94 return 0;
97 int sha1hash(uint8_t *input, int length, uint8_t *hash) {
98 if (!hash || !input)
99 return 1;
101 mbedtls_sha1(input, length, hash);
103 return 0;
106 int sha256hash(uint8_t *input, int length, uint8_t *hash) {
107 if (!hash || !input)
108 return 1;
110 mbedtls_sha256_context sctx;
111 mbedtls_sha256_init(&sctx);
112 mbedtls_sha256_starts(&sctx, 0); // SHA-256, not 224
113 mbedtls_sha256_update(&sctx, input, length);
114 mbedtls_sha256_finish(&sctx, hash);
115 mbedtls_sha256_free(&sctx);
117 return 0;
120 int sha512hash(uint8_t *input, int length, uint8_t *hash) {
121 if (!hash || !input)
122 return 1;
124 mbedtls_sha512_context sctx;
125 mbedtls_sha512_init(&sctx);
126 mbedtls_sha512_starts(&sctx, 0); //SHA-512, not 384
127 mbedtls_sha512_update(&sctx, input, length);
128 mbedtls_sha512_finish(&sctx, hash);
129 mbedtls_sha512_free(&sctx);
131 return 0;
134 static int ecdsa_init_str(mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id curveid, const char *key_d, const char *key_x, const char *key_y) {
135 if (!ctx)
136 return 1;
138 int res;
140 mbedtls_ecdsa_init(ctx);
141 res = mbedtls_ecp_group_load(&ctx->grp, curveid);
142 if (res)
143 return res;
145 if (key_d) {
146 res = mbedtls_mpi_read_string(&ctx->d, 16, key_d);
147 if (res)
148 return res;
151 if (key_x && key_y) {
152 res = mbedtls_ecp_point_read_string(&ctx->Q, 16, key_x, key_y);
153 if (res)
154 return res;
157 return 0;
160 static int ecdsa_init(mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id curveid, uint8_t *key_d, uint8_t *key_xy) {
161 if (!ctx)
162 return 1;
164 int res;
166 mbedtls_ecdsa_init(ctx);
167 res = mbedtls_ecp_group_load(&ctx->grp, curveid);
168 if (res)
169 return res;
171 size_t keylen = (ctx->grp.nbits + 7) / 8;
172 if (key_d) {
173 res = mbedtls_mpi_read_binary(&ctx->d, key_d, keylen);
174 if (res)
175 return res;
178 if (key_xy) {
179 res = mbedtls_ecp_point_read_binary(&ctx->grp, &ctx->Q, key_xy, keylen * 2 + 1);
180 if (res)
181 return res;
184 return 0;
187 int ecdsa_key_create(mbedtls_ecp_group_id curveid, uint8_t *key_d, uint8_t *key_xy) {
188 int res;
189 mbedtls_ecdsa_context ctx;
190 res = ecdsa_init(&ctx, curveid, NULL, NULL);
191 if (res)
192 goto exit;
194 mbedtls_entropy_context entropy;
195 mbedtls_ctr_drbg_context ctr_drbg;
196 const char *pers = "ecdsaproxmark";
198 mbedtls_entropy_init(&entropy);
199 mbedtls_ctr_drbg_init(&ctr_drbg);
201 res = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers));
202 if (res)
203 goto exit;
205 res = mbedtls_ecdsa_genkey(&ctx, curveid, mbedtls_ctr_drbg_random, &ctr_drbg);
206 if (res)
207 goto exit;
209 size_t keylen = (ctx.grp.nbits + 7) / 8;
210 res = mbedtls_mpi_write_binary(&ctx.d, key_d, keylen);
211 if (res)
212 goto exit;
214 size_t public_keylen = 0;
215 uint8_t public_key[200] = {0};
216 res = mbedtls_ecp_point_write_binary(&ctx.grp, &ctx.Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &public_keylen, public_key, sizeof(public_key));
217 if (res)
218 goto exit;
220 if (public_keylen != 1 + 2 * keylen) { // 0x04 <key x><key y>
221 res = 1;
222 goto exit;
224 memcpy(key_xy, public_key, public_keylen);
226 exit:
227 mbedtls_entropy_free(&entropy);
228 mbedtls_ctr_drbg_free(&ctr_drbg);
229 mbedtls_ecdsa_free(&ctx);
230 return res;
233 char *ecdsa_get_error(int ret) {
234 static char retstr[300];
235 memset(retstr, 0x00, sizeof(retstr));
236 mbedtls_strerror(ret, retstr, sizeof(retstr));
237 return retstr;
240 int ecdsa_public_key_from_pk(mbedtls_pk_context *pk, mbedtls_ecp_group_id curveid, uint8_t *key, size_t keylen) {
241 int res = 0;
242 size_t realkeylen = 0;
244 mbedtls_ecdsa_context ctx;
245 mbedtls_ecdsa_init(&ctx);
247 res = mbedtls_ecp_group_load(&ctx.grp, curveid);
248 if (res)
249 goto exit;
251 size_t private_keylen = (ctx.grp.nbits + 7) / 8;
252 if (keylen < 1 + 2 * private_keylen) {
253 res = 1;
254 goto exit;
257 res = mbedtls_ecdsa_from_keypair(&ctx, mbedtls_pk_ec(*pk));
258 if (res)
259 goto exit;
261 res = mbedtls_ecp_point_write_binary(&ctx.grp, &ctx.Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &realkeylen, key, keylen);
262 if (realkeylen != 1 + 2 * private_keylen)
263 res = 2;
264 exit:
265 mbedtls_ecdsa_free(&ctx);
266 return res;
269 int ecdsa_signature_create(mbedtls_ecp_group_id curveid, uint8_t *key_d, uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t *signaturelen, bool hash) {
270 int res;
271 *signaturelen = 0;
273 uint8_t shahash[32] = {0};
274 res = sha256hash(input, length, shahash);
275 if (res)
276 return res;
278 mbedtls_entropy_context entropy;
279 mbedtls_ctr_drbg_context ctr_drbg;
280 const char *pers = "ecdsaproxmark";
282 mbedtls_entropy_init(&entropy);
283 mbedtls_ctr_drbg_init(&ctr_drbg);
285 res = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers));
286 if (res)
287 goto exit;
289 mbedtls_ecdsa_context ctx;
290 res = ecdsa_init(&ctx, curveid, key_d, key_xy);
291 if (res)
292 goto exit;
294 res = mbedtls_ecdsa_write_signature(
295 &ctx,
296 MBEDTLS_MD_SHA256,
297 hash ? shahash : input,
298 hash ? sizeof(shahash) : length,
299 signature,
300 signaturelen,
301 mbedtls_ctr_drbg_random,
302 &ctr_drbg
306 exit:
307 mbedtls_ctr_drbg_free(&ctr_drbg);
308 mbedtls_ecdsa_free(&ctx);
309 return res;
312 static int ecdsa_signature_create_test(mbedtls_ecp_group_id curveid, const char *key_d, const char *key_x, const char *key_y, const char *random, uint8_t *input, int length, uint8_t *signature, size_t *signaturelen) {
313 int res;
314 *signaturelen = 0;
316 uint8_t shahash[32] = {0};
317 res = sha256hash(input, length, shahash);
318 if (res)
319 return res;
321 int rndlen = 0;
322 param_gethex_to_eol(random, 0, fixed_rand_value, sizeof(fixed_rand_value), &rndlen);
324 mbedtls_ecdsa_context ctx;
325 res = ecdsa_init_str(&ctx, curveid, key_d, key_x, key_y);
326 if (res)
327 return res;
329 res = mbedtls_ecdsa_write_signature(&ctx, MBEDTLS_MD_SHA256, shahash, sizeof(shahash), signature, signaturelen, fixed_rand, NULL);
331 mbedtls_ecdsa_free(&ctx);
332 return res;
335 static int ecdsa_signature_verify_keystr(mbedtls_ecp_group_id curveid, const char *key_x, const char *key_y, uint8_t *input, int length, uint8_t *signature, size_t signaturelen, bool hash) {
336 int res;
337 uint8_t shahash[32] = {0};
338 res = sha256hash(input, length, shahash);
339 if (res)
340 return res;
342 mbedtls_ecdsa_context ctx;
343 res = ecdsa_init_str(&ctx, curveid, NULL, key_x, key_y);
344 if (res)
345 return res;
347 res = mbedtls_ecdsa_read_signature(
348 &ctx,
349 hash ? shahash : input,
350 hash ? sizeof(shahash) : length,
351 signature,
352 signaturelen
355 mbedtls_ecdsa_free(&ctx);
356 return res;
359 int ecdsa_signature_verify(mbedtls_ecp_group_id curveid, uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t signaturelen, bool hash) {
360 int res;
361 uint8_t shahash[32] = {0};
362 if (hash) {
363 res = sha256hash(input, length, shahash);
364 if (res)
365 return res;
368 mbedtls_ecdsa_context ctx;
369 res = ecdsa_init(&ctx, curveid, NULL, key_xy);
370 if (res)
371 return res;
373 res = mbedtls_ecdsa_read_signature(
374 &ctx,
375 hash ? shahash : input,
376 hash ? sizeof(shahash) : length,
377 signature,
378 signaturelen
381 mbedtls_ecdsa_free(&ctx);
382 return res;
385 // take signature bytes, converts to ASN1 signature and tries to verify
386 int ecdsa_signature_r_s_verify(mbedtls_ecp_group_id curveid, uint8_t *key_xy, uint8_t *input, int length, uint8_t *r_s, size_t r_s_len, bool hash) {
387 uint8_t signature[MBEDTLS_ECDSA_MAX_LEN] = {0};
388 size_t signature_len = 0;
390 // convert r & s to ASN.1 signature
391 mbedtls_mpi r, s;
392 mbedtls_mpi_init(&r);
393 mbedtls_mpi_init(&s);
394 mbedtls_mpi_read_binary(&r, r_s, r_s_len / 2);
395 mbedtls_mpi_read_binary(&s, r_s + r_s_len / 2, r_s_len / 2);
397 int res = ecdsa_signature_to_asn1(&r, &s, signature, &signature_len);
398 if (res < 0) {
399 return res;
402 res = ecdsa_signature_verify(curveid, key_xy, input, length, signature, signature_len, hash);
403 mbedtls_mpi_free(&r);
404 mbedtls_mpi_free(&s);
405 return res;
409 #define T_PRIVATE_KEY "C477F9F65C22CCE20657FAA5B2D1D8122336F851A508A1ED04E479C34985BF96"
410 #define T_Q_X "B7E08AFDFE94BAD3F1DC8C734798BA1C62B3A0AD1E9EA2A38201CD0889BC7A19"
411 #define T_Q_Y "3603F747959DBF7A4BB226E41928729063ADC7AE43529E61B563BBC606CC5E09"
412 #define T_K "7A1A7E52797FC8CAAA435D2A4DACE39158504BF204FBE19F14DBB427FAEE50AE"
413 #define T_R "2B42F576D07F4165FF65D1F3B1500F81E44C316F1F0B3EF57325B69ACA46104F"
414 #define T_S "DC42C2122D6392CD3E3A993A89502A8198C1886FE69D262C4B329BDB6B63FAF1"
416 int ecdsa_nist_test(bool verbose) {
417 int res;
418 uint8_t input[] = "Example of ECDSA with P-256";
419 mbedtls_ecp_group_id curveid = MBEDTLS_ECP_DP_SECP256R1;
420 int length = strlen((char *)input);
421 uint8_t signature[300] = {0};
422 size_t siglen = 0;
424 // NIST ecdsa test
425 if (verbose)
426 PrintAndLogEx(INFO, " ECDSA NIST test: " NOLF);
427 // make signature
428 res = ecdsa_signature_create_test(curveid, T_PRIVATE_KEY, T_Q_X, T_Q_Y, T_K, input, length, signature, &siglen);
429 // PrintAndLogEx(INFO, "res: %x signature[%x]: %s", (res < 0)? -res : res, siglen, sprint_hex(signature, siglen));
430 if (res != PM3_SUCCESS)
431 goto exit;
433 // check vectors
434 uint8_t rval[300] = {0};
435 uint8_t sval[300] = {0};
436 res = ecdsa_asn1_get_signature(signature, siglen, rval, sval);
437 if (res)
438 goto exit;
440 int slen = 0;
441 uint8_t rval_s[33] = {0};
442 param_gethex_to_eol(T_R, 0, rval_s, sizeof(rval_s), &slen);
443 uint8_t sval_s[33] = {0};
444 param_gethex_to_eol(T_S, 0, sval_s, sizeof(sval_s), &slen);
445 if (strncmp((char *)rval, (char *)rval_s, 32) || strncmp((char *)sval, (char *)sval_s, 32)) {
446 PrintAndLogEx(INFO, "R or S check error");
447 res = 100;
448 goto exit;
451 // verify signature
452 res = ecdsa_signature_verify_keystr(curveid, T_Q_X, T_Q_Y, input, length, signature, siglen, true);
453 if (res)
454 goto exit;
456 // verify wrong signature
457 input[0] ^= 0xFF;
458 res = ecdsa_signature_verify_keystr(curveid, T_Q_X, T_Q_Y, input, length, signature, siglen, true);
459 if (res == false) {
460 res = 1;
461 goto exit;
464 if (verbose) {
465 PrintAndLogEx(NORMAL, _GREEN_("passed"));
466 PrintAndLogEx(INFO, " ECDSA binary signature create/check test: " NOLF);
469 // random ecdsa test
470 uint8_t key_d[32] = {0};
471 uint8_t key_xy[32 * 2 + 2] = {0};
472 memset(signature, 0x00, sizeof(signature));
473 siglen = 0;
475 res = ecdsa_key_create(curveid, key_d, key_xy);
476 if (res)
477 goto exit;
479 res = ecdsa_signature_create(curveid, key_d, key_xy, input, length, signature, &siglen, true);
480 if (res)
481 goto exit;
483 res = ecdsa_signature_verify(curveid, key_xy, input, length, signature, siglen, true);
484 if (res)
485 goto exit;
487 input[0] ^= 0xFF;
488 res = ecdsa_signature_verify(curveid, key_xy, input, length, signature, siglen, true);
489 if (!res)
490 goto exit;
492 if (verbose)
493 PrintAndLogEx(NORMAL, _GREEN_("passed\n"));
495 return PM3_SUCCESS;
496 exit:
497 if (verbose)
498 PrintAndLogEx(NORMAL, _RED_("failed\n"));
499 return res;