Merge pull request #969 from pwpiwi/gcc10_fixes
[legacy-proxmark3.git] / client / crypto / libpcrypto.c
blobb20961d814f4561d46e0c853c01825a01b59d7a0
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 <stdlib.h>
14 #include <unistd.h>
15 #include <string.h>
16 #include <mbedtls/asn1.h>
17 #include <mbedtls/aes.h>
18 #include <mbedtls/cmac.h>
19 #include <mbedtls/pk.h>
20 #include <mbedtls/ecdsa.h>
21 #include <mbedtls/sha256.h>
22 #include <mbedtls/sha512.h>
23 #include <mbedtls/ctr_drbg.h>
24 #include <mbedtls/entropy.h>
25 #include <mbedtls/error.h>
26 #include <crypto/asn1utils.h>
27 #include <util.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;
48 int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length){
49 uint8_t iiv[16] = {0};
50 if (iv)
51 memcpy(iiv, iv, 16);
53 mbedtls_aes_context aes;
54 mbedtls_aes_init(&aes);
55 if (mbedtls_aes_setkey_dec(&aes, key, 128))
56 return 1;
57 if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, length, iiv, input, output))
58 return 2;
59 mbedtls_aes_free(&aes);
61 return 0;
65 // NIST Special Publication 800-38B — Recommendation for block cipher modes of operation: The CMAC mode for authentication.
66 // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CMAC.pdf
67 int aes_cmac(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length) {
68 memset(mac, 0x00, 16);
70 // NIST 800-38B
71 return mbedtls_aes_cmac_prf_128(key, MBEDTLS_AES_BLOCK_SIZE, input, length, mac);
75 int aes_cmac8(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length) {
76 uint8_t cmac[16] = {0};
77 memset(mac, 0x00, 8);
79 int res = aes_cmac(iv, key, input, cmac, length);
80 if (res)
81 return res;
83 for(int i = 0; i < 8; i++)
84 mac[i] = cmac[i * 2 + 1];
86 return 0;
90 static uint8_t fixed_rand_value[250] = {0};
92 static int fixed_rand(void *rng_state, unsigned char *output, size_t len) {
93 if (len <= 250) {
94 memcpy(output, fixed_rand_value, len);
95 } else {
96 memset(output, 0x00, len);
99 return 0;
103 int sha256hash(uint8_t *input, int length, uint8_t *hash) {
104 if (!hash || !input)
105 return 1;
107 mbedtls_sha256_context sctx;
108 mbedtls_sha256_init(&sctx);
109 mbedtls_sha256_starts(&sctx, 0); // SHA-256, not 224
110 mbedtls_sha256_update(&sctx, input, length);
111 mbedtls_sha256_finish(&sctx, hash);
112 mbedtls_sha256_free(&sctx);
114 return 0;
118 int sha512hash(uint8_t *input, int length, uint8_t *hash) {
119 if (!hash || !input)
120 return 1;
122 mbedtls_sha512_context sctx;
123 mbedtls_sha512_init(&sctx);
124 mbedtls_sha512_starts(&sctx, 0); //SHA-512, not 384
125 mbedtls_sha512_update(&sctx, input, length);
126 mbedtls_sha512_finish(&sctx, hash);
127 mbedtls_sha512_free(&sctx);
129 return 0;
133 int ecdsa_init_str(mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id curveID, char *key_d, char *key_x, char *key_y) {
134 if (!ctx)
135 return 1;
137 int res;
139 mbedtls_ecdsa_init(ctx);
140 res = mbedtls_ecp_group_load(&ctx->grp, curveID);
141 if (res)
142 return res;
144 if (key_d) {
145 res = mbedtls_mpi_read_string(&ctx->d, 16, key_d);
146 if (res)
147 return res;
150 if (key_x && key_y) {
151 res = mbedtls_ecp_point_read_string(&ctx->Q, 16, key_x, key_y);
152 if (res)
153 return res;
156 return 0;
160 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;
188 int ecdsa_key_create(mbedtls_ecp_group_id curveID, uint8_t *key_d, uint8_t *key_xy) {
189 int res;
190 mbedtls_ecdsa_context ctx;
191 ecdsa_init(&ctx, curveID, NULL, NULL);
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;
234 char *ecdsa_get_error(int ret) {
235 static char retstr[300];
236 memset(retstr, 0x00, sizeof(retstr));
237 mbedtls_strerror(ret, retstr, sizeof(retstr));
238 return retstr;
242 int ecdsa_public_key_from_pk(mbedtls_pk_context *pk, mbedtls_ecp_group_id curveID, uint8_t *key, size_t keylen) {
243 int res = 0;
244 size_t realkeylen = 0;
246 mbedtls_ecdsa_context ctx;
247 mbedtls_ecdsa_init(&ctx);
249 res = mbedtls_ecp_group_load(&ctx.grp, curveID);
250 if (res)
251 goto exit;
253 size_t private_keylen = (ctx.grp.nbits + 7) / 8;
254 if (keylen < 1 + 2 * private_keylen) {
255 res = 1;
256 goto exit;
259 res = mbedtls_ecdsa_from_keypair(&ctx, mbedtls_pk_ec(*pk) );
260 if (res)
261 goto exit;
263 res = mbedtls_ecp_point_write_binary(&ctx.grp, &ctx.Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &realkeylen, key, keylen);
264 if (realkeylen != 1 + 2 * private_keylen)
265 res = 2;
266 exit:
267 mbedtls_ecdsa_free(&ctx);
268 return res;
272 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) {
273 int res;
274 *signaturelen = 0;
276 uint8_t shahash[32] = {0};
277 res = sha256hash(input, length, shahash);
278 if (res)
279 return res;
281 mbedtls_entropy_context entropy;
282 mbedtls_ctr_drbg_context ctr_drbg;
283 const char *pers = "ecdsaproxmark";
285 mbedtls_entropy_init(&entropy);
286 mbedtls_ctr_drbg_init(&ctr_drbg);
288 res = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers));
289 if (res)
290 goto exit;
292 mbedtls_ecdsa_context ctx;
293 ecdsa_init(&ctx, curveID, key_d, key_xy);
294 res = mbedtls_ecdsa_write_signature(&ctx, MBEDTLS_MD_SHA256, hash?shahash:input, hash?sizeof(shahash):length, signature, signaturelen, mbedtls_ctr_drbg_random, &ctr_drbg);
296 exit:
297 mbedtls_ctr_drbg_free(&ctr_drbg);
298 mbedtls_ecdsa_free(&ctx);
299 return res;
303 int ecdsa_signature_create_test(mbedtls_ecp_group_id curveID, char *key_d, char *key_x, char *key_y, char *random, uint8_t *input, int length, uint8_t *signature, size_t *signaturelen) {
304 int res;
305 *signaturelen = 0;
307 uint8_t shahash[32] = {0};
308 res = sha256hash(input, length, shahash);
309 if (res)
310 return res;
312 int rndlen = 0;
313 param_gethex_to_eol(random, 0, fixed_rand_value, sizeof(fixed_rand_value), &rndlen);
315 mbedtls_ecdsa_context ctx;
316 ecdsa_init_str(&ctx, curveID, key_d, key_x, key_y);
317 res = mbedtls_ecdsa_write_signature(&ctx, MBEDTLS_MD_SHA256, shahash, sizeof(shahash), signature, signaturelen, fixed_rand, NULL);
319 mbedtls_ecdsa_free(&ctx);
320 return res;
324 int ecdsa_signature_verify_keystr(mbedtls_ecp_group_id curveID, char *key_x, char *key_y, uint8_t *input, int length, uint8_t *signature, size_t signaturelen, bool hash) {
325 int res;
326 uint8_t shahash[32] = {0};
327 res = sha256hash(input, length, shahash);
328 if (res)
329 return res;
331 mbedtls_ecdsa_context ctx;
332 ecdsa_init_str(&ctx, curveID, NULL, key_x, key_y);
333 res = mbedtls_ecdsa_read_signature(&ctx, hash?shahash:input, hash?sizeof(shahash):length, signature, signaturelen);
335 mbedtls_ecdsa_free(&ctx);
336 return res;
340 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) {
341 int res;
342 uint8_t shahash[32] = {0};
343 if (hash) {
344 res = sha256hash(input, length, shahash);
345 if (res)
346 return res;
349 mbedtls_ecdsa_context ctx;
350 res = ecdsa_init(&ctx, curveID, NULL, key_xy);
351 res = mbedtls_ecdsa_read_signature(&ctx, hash?shahash:input, hash?sizeof(shahash):length, signature, signaturelen);
353 mbedtls_ecdsa_free(&ctx);
354 return res;
358 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) {
359 int res;
360 uint8_t signature[MBEDTLS_ECDSA_MAX_LEN];
361 size_t signature_len;
363 // convert r & s to ASN.1 signature
364 mbedtls_mpi r, s;
365 mbedtls_mpi_init(&r);
366 mbedtls_mpi_init(&s);
367 mbedtls_mpi_read_binary(&r, r_s, r_s_len/2);
368 mbedtls_mpi_read_binary(&s, r_s + r_s_len/2, r_s_len/2);
370 res = ecdsa_signature_to_asn1(&r, &s, signature, &signature_len);
371 if (res < 0) {
372 return res;
375 res = ecdsa_signature_verify(curveID, key_xy, input, length, signature, signature_len, hash);
377 mbedtls_mpi_free(&r);
378 mbedtls_mpi_free(&s);
380 return res;
384 #define T_PRIVATE_KEY "C477F9F65C22CCE20657FAA5B2D1D8122336F851A508A1ED04E479C34985BF96"
385 #define T_Q_X "B7E08AFDFE94BAD3F1DC8C734798BA1C62B3A0AD1E9EA2A38201CD0889BC7A19"
386 #define T_Q_Y "3603F747959DBF7A4BB226E41928729063ADC7AE43529E61B563BBC606CC5E09"
387 #define T_K "7A1A7E52797FC8CAAA435D2A4DACE39158504BF204FBE19F14DBB427FAEE50AE"
388 #define T_R "2B42F576D07F4165FF65D1F3B1500F81E44C316F1F0B3EF57325B69ACA46104F"
389 #define T_S "DC42C2122D6392CD3E3A993A89502A8198C1886FE69D262C4B329BDB6B63FAF1"
391 int ecdsa_nist_test(bool verbose) {
392 int res;
393 uint8_t input[] = "Example of ECDSA with P-256";
394 mbedtls_ecp_group_id curveID = MBEDTLS_ECP_DP_SECP256R1;
395 int length = strlen((char *)input);
396 uint8_t signature[300] = {0};
397 size_t siglen = 0;
399 // NIST ecdsa test
400 if (verbose)
401 printf(" ECDSA NIST test: ");
402 // make signature
403 res = ecdsa_signature_create_test(curveID, T_PRIVATE_KEY, T_Q_X, T_Q_Y, T_K, input, length, signature, &siglen);
404 // printf("res: %x signature[%x]: %s\n", (res<0)?-res:res, siglen, sprint_hex(signature, siglen));
405 if (res)
406 goto exit;
408 // check vectors
409 uint8_t rval[300] = {0};
410 uint8_t sval[300] = {0};
411 res = ecdsa_asn1_get_signature(signature, siglen, rval, sval);
412 if (res)
413 goto exit;
415 int slen = 0;
416 uint8_t rval_s[33] = {0};
417 param_gethex_to_eol(T_R, 0, rval_s, sizeof(rval_s), &slen);
418 uint8_t sval_s[33] = {0};
419 param_gethex_to_eol(T_S, 0, sval_s, sizeof(sval_s), &slen);
420 if (strncmp((char *)rval, (char *)rval_s, 32) || strncmp((char *)sval, (char *)sval_s, 32)) {
421 printf("R or S check error\n");
422 res = 100;
423 goto exit;
426 // verify signature
427 res = ecdsa_signature_verify_keystr(curveID, T_Q_X, T_Q_Y, input, length, signature, siglen, true);
428 if (res)
429 goto exit;
431 // verify wrong signature
432 input[0] ^= 0xFF;
433 res = ecdsa_signature_verify_keystr(curveID, T_Q_X, T_Q_Y, input, length, signature, siglen, true);
434 if (!res) {
435 res = 1;
436 goto exit;
438 if (verbose)
439 printf("passed\n");
441 // random ecdsa test
442 if (verbose)
443 printf(" ECDSA binary signature create/check test: ");
445 uint8_t key_d[32] = {0};
446 uint8_t key_xy[32 * 2 + 2] = {0};
447 memset(signature, 0x00, sizeof(signature));
448 siglen = 0;
450 res = ecdsa_key_create(curveID, key_d, key_xy);
451 if (res)
452 goto exit;
454 res = ecdsa_signature_create(curveID, key_d, key_xy, input, length, signature, &siglen, true);
455 if (res)
456 goto exit;
458 res = ecdsa_signature_verify(curveID, key_xy, input, length, signature, siglen, true);
459 if (res)
460 goto exit;
462 input[0] ^= 0xFF;
463 res = ecdsa_signature_verify(curveID, key_xy, input, length, signature, siglen, true);
464 if (!res)
465 goto exit;
467 if (verbose)
468 printf("passed\n\n");
470 return 0;
471 exit:
472 if (verbose)
473 printf("failed\n\n");
474 return res;