/* * Compute and write signature */ int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hlen, unsigned char *sig, size_t *slen, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret; mbedtls_mpi r, s; mbedtls_mpi_init( &r ); mbedtls_mpi_init( &s ); #if defined(MBEDTLS_ECDSA_DETERMINISTIC) (void) f_rng; (void) p_rng; MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign_det( &ctx->grp, &r, &s, &ctx->d, hash, hlen, md_alg ) ); #else (void) md_alg; MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d, hash, hlen, f_rng, p_rng ) ); #endif MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen ) ); cleanup: mbedtls_mpi_free( &r ); mbedtls_mpi_free( &s ); return( ret ); }
/* Z = (X * Y) mod M Not an mbedTLS function */ int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M) { int ret; size_t num_words = hardware_words_needed(M); mbedtls_mpi Rinv; mbedtls_mpi_uint Mprime; /* Calculate and load the first stage montgomery multiplication */ mbedtls_mpi_init(&Rinv); MBEDTLS_MPI_CHK(calculate_rinv(&Rinv, M, num_words)); Mprime = modular_inverse(M); esp_mpi_acquire_hardware(); /* Load M, X, Rinv, Mprime (Mprime is mod 2^32) */ mpi_to_mem_block(RSA_MEM_M_BLOCK_BASE, M, num_words); mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, num_words); mpi_to_mem_block(RSA_MEM_RB_BLOCK_BASE, &Rinv, num_words); REG_WRITE(RSA_M_DASH_REG, (uint32_t)Mprime); /* "mode" register loaded with number of 512-bit blocks, minus 1 */ REG_WRITE(RSA_MULT_MODE_REG, (num_words / 16) - 1); /* Execute first stage montgomery multiplication */ execute_op(RSA_MULT_START_REG); /* execute second stage */ MBEDTLS_MPI_CHK( modular_multiply_finish(Z, X, Y, num_words) ); esp_mpi_release_hardware(); cleanup: mbedtls_mpi_free(&Rinv); return ret; }
/* * Compute shared secret (SEC1 3.3.1) */ int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, const mbedtls_ecp_point *Q, const mbedtls_mpi *d, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret; mbedtls_ecp_point P; mbedtls_ecp_point_init( &P ); /* * Make sure Q is a valid pubkey before using it */ MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) ); MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, &P, d, Q, f_rng, p_rng ) ); if( mbedtls_ecp_is_zero( &P ) ) { ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; goto cleanup; } MBEDTLS_MPI_CHK( mbedtls_mpi_copy( z, &P.X ) ); cleanup: mbedtls_ecp_point_free( &P ); return( ret ); }
/* * Deterministic signature wrapper */ int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, const mbedtls_mpi *d, const unsigned char *buf, size_t blen, mbedtls_md_type_t md_alg ) { int ret; mbedtls_hmac_drbg_context rng_ctx; unsigned char data[2 * MBEDTLS_ECP_MAX_BYTES]; size_t grp_len = ( grp->nbits + 7 ) / 8; const mbedtls_md_info_t *md_info; mbedtls_mpi h; if( ( md_info = mbedtls_md_info_from_type( md_alg ) ) == NULL ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); mbedtls_mpi_init( &h ); mbedtls_hmac_drbg_init( &rng_ctx ); /* Use private key and message hash (reduced) to initialize HMAC_DRBG */ MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, data, grp_len ) ); MBEDTLS_MPI_CHK( derive_mpi( grp, &h, buf, blen ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, data + grp_len, grp_len ) ); mbedtls_hmac_drbg_seed_buf( &rng_ctx, md_info, data, 2 * grp_len ); ret = mbedtls_ecdsa_sign( grp, r, s, d, buf, blen, mbedtls_hmac_drbg_random, &rng_ctx ); cleanup: mbedtls_hmac_drbg_free( &rng_ctx ); mbedtls_mpi_free( &h ); return( ret ); }
/* * Use the blinding method and optimisation suggested in section 10 of: * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA, * DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer * Berlin Heidelberg, 1996. p. 104-113. */ static int dhm_update_blinding( mbedtls_dhm_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret, count; /* * Don't use any blinding the first time a particular X is used, * but remember it to use blinding next time. */ if( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->pX ) != 0 ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &ctx->pX, &ctx->X ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vi, 1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vf, 1 ) ); return( 0 ); } /* * Ok, we need blinding. Can we re-use existing values? * If yes, just update them by squaring them. */ if( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 ) { MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->P ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) ); return( 0 ); } /* * We need to generate blinding values from scratch */ /* Vi = random( 2, P-1 ) */ count = 0; do { mbedtls_mpi_fill_random( &ctx->Vi, mbedtls_mpi_size( &ctx->P ), f_rng, p_rng ); while( mbedtls_mpi_cmp_mpi( &ctx->Vi, &ctx->P ) >= 0 ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->Vi, 1 ) ); if( count++ > 10 ) return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); } while( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) <= 0 ); /* Vf = Vi^-X mod P */ MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vf, &ctx->Vi, &ctx->P ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP ) ); cleanup: return( ret ); }
/* Calculate Rinv = RR^2 mod M, where: * * R = b^n where b = 2^32, n=num_words, * R = 2^N (where N=num_bits) * RR = R^2 = 2^(2*N) (where N=num_bits=num_words*32) * * This calculation is computationally expensive (mbedtls_mpi_mod_mpi) * so caller should cache the result where possible. * * DO NOT call this function while holding esp_mpi_acquire_hardware(). * */ static int calculate_rinv(mbedtls_mpi *Rinv, const mbedtls_mpi *M, int num_words) { int ret; size_t num_bits = num_words * 32; mbedtls_mpi RR; mbedtls_mpi_init(&RR); MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&RR, num_bits * 2, 1)); MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(Rinv, &RR, M)); cleanup: mbedtls_mpi_free(&RR); return ret; }
/* * Generate or update blinding values, see section 10 of: * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA, * DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer * Berlin Heidelberg, 1996. p. 104-113. */ static int rsa_prepare_blinding( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret, count = 0; if( ctx->Vf.p != NULL ) { /* We already have blinding values, just update them by squaring */ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->N ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->N ) ); goto cleanup; } /* Unblinding value: Vf = random number, invertible mod N */ do { if( count++ > 10 ) return( MBEDTLS_ERR_RSA_RNG_FAILED ); MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->Vf, ctx->len - 1, f_rng, p_rng ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &ctx->Vi, &ctx->Vf, &ctx->N ) ); } while( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 ); /* Blinding value: Vi = Vf^(-e) mod N */ MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vi, &ctx->Vf, &ctx->N ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vi, &ctx->Vi, &ctx->E, &ctx->N, &ctx->RN ) ); cleanup: return( ret ); }
int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start, const mbedtls_mpi *X ) { int ret; size_t len = 0; // Write the MPI // len = mbedtls_mpi_size( X ); if( *p < start || (size_t)( *p - start ) < len ) return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); (*p) -= len; MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, *p, len ) ); // DER format assumes 2s complement for numbers, so the leftmost bit // should be 0 for positive numbers and 1 for negative numbers. // if( X->s ==1 && **p & 0x80 ) { if( *p - start < 1 ) return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); *--(*p) = 0x00; len += 1; } MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_INTEGER ) ); ret = (int) len; cleanup: return( ret ); }
/* * Derive a suitable integer for group grp from a buffer of length len * SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3 */ static int derive_mpi( const mbedtls_ecp_group *grp, mbedtls_mpi *x, const unsigned char *buf, size_t blen ) { int ret; size_t n_size = ( grp->nbits + 7 ) / 8; size_t use_size = blen > n_size ? n_size : blen; MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( x, buf, use_size ) ); if( use_size * 8 > grp->nbits ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( x, use_size * 8 - grp->nbits ) ); /* While at it, reduce modulo N */ if( mbedtls_mpi_cmp_mpi( x, &grp->N ) >= 0 ) MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( x, x, &grp->N ) ); cleanup: return( ret ); }
/* * Create own private value X and export G^X */ int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size, unsigned char *output, size_t olen, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret, count = 0; if( ctx == NULL || olen < 1 || olen > ctx->len ) return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 ) return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); /* * generate X and calculate GX = G^X mod P */ do { mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ); while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) ); if( count++ > 10 ) return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED ); } while( dhm_check_range( &ctx->X, &ctx->P ) != 0 ); MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X, &ctx->P , &ctx->RP ) ); if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 ) return( ret ); MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->GX, output, olen ) ); cleanup: if( ret != 0 ) return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED + ret ); return( 0 ); }
/* * Verify sanity of parameter with regards to P * * Parameter should be: 2 <= public_param <= P - 2 * * For more information on the attack, see: * http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf * http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643 */ static int dhm_check_range( const mbedtls_mpi *param, const mbedtls_mpi *P ) { mbedtls_mpi L, U; int ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA; mbedtls_mpi_init( &L ); mbedtls_mpi_init( &U ); MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &L, 2 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &U, P, 2 ) ); if( mbedtls_mpi_cmp_mpi( param, &L ) >= 0 && mbedtls_mpi_cmp_mpi( param, &U ) <= 0 ) { ret = 0; } cleanup: mbedtls_mpi_free( &L ); mbedtls_mpi_free( &U ); return( ret ); }
/* Deal with the case when X & Y are too long for the hardware unit, by splitting one operand into two halves. Y must be the longer operand Slice Y into Yp, Ypp such that: Yp = lower 'b' bits of Y Ypp = upper 'b' bits of Y (right shifted) Such that Z = X * Y Z = X * (Yp + Ypp<<b) Z = (X * Yp) + (X * Ypp<<b) Note that this function may recurse multiple times, if both X & Y are too long for the hardware multiplication unit. */ static int mpi_mult_mpi_overlong(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t bits_y, size_t words_result) { int ret; mbedtls_mpi Ztemp; const size_t limbs_y = (bits_y + biL - 1) / biL; /* Rather than slicing in two on bits we slice on limbs (32 bit words) */ const size_t limbs_slice = limbs_y / 2; /* Yp holds lower bits of Y (declared to reuse Y's array contents to save on copying) */ const mbedtls_mpi Yp = { .p = Y->p, .n = limbs_slice, .s = Y->s }; /* Ypp holds upper bits of Y, right shifted (also reuses Y's array contents) */ const mbedtls_mpi Ypp = { .p = Y->p + limbs_slice, .n = limbs_y - limbs_slice, .s = Y->s }; mbedtls_mpi_init(&Ztemp); /* Grow Z to result size early, avoid interim allocations */ mbedtls_mpi_grow(Z, words_result); /* Get result Ztemp = Yp * X (need temporary variable Ztemp) */ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi(&Ztemp, X, &Yp) ); /* Z = Ypp * Y */ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi(Z, X, &Ypp) ); /* Z = Z << b */ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l(Z, limbs_slice * biL) ); /* Z += Ztemp */ MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi(Z, Z, &Ztemp) ); cleanup: mbedtls_mpi_free(&Ztemp); return ret; }
/* * Do an RSA public key operation */ int mbedtls_rsa_public( mbedtls_rsa_context *ctx, const unsigned char *input, unsigned char *output ) { int ret; size_t olen; mbedtls_mpi T; mbedtls_mpi_init( &T ); #if defined(MBEDTLS_THREADING_C) if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) return( ret ); #endif MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &T, input, ctx->len ) ); if( mbedtls_mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) { ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; goto cleanup; } olen = ctx->len; MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &T, output, olen ) ); cleanup: #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); #endif mbedtls_mpi_free( &T ); if( ret != 0 ) return( MBEDTLS_ERR_RSA_PUBLIC_FAILED + ret ); return( 0 ); }
/* * Derive and export the shared secret (G^Y)^X mod P */ int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx, unsigned char *output, size_t output_size, size_t *olen, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret; mbedtls_mpi GYb; if( ctx == NULL || output_size < ctx->len ) return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 ) return( ret ); mbedtls_mpi_init( &GYb ); /* Blind peer's value */ if( f_rng != NULL ) { MBEDTLS_MPI_CHK( dhm_update_blinding( ctx, f_rng, p_rng ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &GYb, &ctx->GY, &ctx->Vi ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &GYb, &GYb, &ctx->P ) ); } else MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &GYb, &ctx->GY ) ); /* Do modular exponentiation */ MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->K, &GYb, &ctx->X, &ctx->P, &ctx->RP ) ); /* Unblind secret value */ if( f_rng != NULL ) { MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->K, &ctx->K, &ctx->Vf ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->K, &ctx->K, &ctx->P ) ); } *olen = mbedtls_mpi_size( &ctx->K ); MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->K, output, *olen ) ); cleanup: mbedtls_mpi_free( &GYb ); if( ret != 0 ) return( MBEDTLS_ERR_DHM_CALC_SECRET_FAILED + ret ); return( 0 ); }
static int eckey_verify_rs_wrap( void *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, const unsigned char *sig, size_t sig_len, void *rs_ctx ) { int ret; eckey_restart_ctx *rs = rs_ctx; /* Should never happen */ if( rs == NULL ) return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); /* set up our own sub-context if needed (that is, on first run) */ if( rs->ecdsa_ctx.grp.pbits == 0 ) MBEDTLS_MPI_CHK( mbedtls_ecdsa_from_keypair( &rs->ecdsa_ctx, ctx ) ); MBEDTLS_MPI_CHK( ecdsa_verify_rs_wrap( &rs->ecdsa_ctx, md_alg, hash, hash_len, sig, sig_len, &rs->ecdsa_rs ) ); cleanup: return( ret ); }
/* Read mbedTLS MPI bignum back from hardware memory block. Reads num_words words from block. Can return a failure result if fails to grow the MPI result. */ static inline int mem_block_to_mpi(mbedtls_mpi *x, uint32_t mem_base, int num_words) { int ret = 0; MBEDTLS_MPI_CHK( mbedtls_mpi_grow(x, num_words) ); /* Copy data from memory block registers */ memcpy(x->p, (uint32_t *)mem_base, num_words * 4); /* Zero any remaining limbs in the bignum, if the buffer is bigger than num_words */ for(size_t i = num_words; i < x->n; i++) { x->p[i] = 0; } asm volatile ("memw"); cleanup: return ret; }
/* * Find the group id associated with an (almost filled) group as generated by * pk_group_from_specified(), or return an error if unknown. */ static int pk_group_id_from_group( const mbedtls_ecp_group *grp, mbedtls_ecp_group_id *grp_id ) { int ret = 0; mbedtls_ecp_group ref; const mbedtls_ecp_group_id *id; mbedtls_ecp_group_init( &ref ); for( id = mbedtls_ecp_grp_id_list(); *id != MBEDTLS_ECP_DP_NONE; id++ ) { /* Load the group associated to that id */ mbedtls_ecp_group_free( &ref ); MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ref, *id ) ); /* Compare to the group we were given, starting with easy tests */ if( grp->pbits == ref.pbits && grp->nbits == ref.nbits && mbedtls_mpi_cmp_mpi( &grp->P, &ref.P ) == 0 && mbedtls_mpi_cmp_mpi( &grp->A, &ref.A ) == 0 && mbedtls_mpi_cmp_mpi( &grp->B, &ref.B ) == 0 && mbedtls_mpi_cmp_mpi( &grp->N, &ref.N ) == 0 && mbedtls_mpi_cmp_mpi( &grp->G.X, &ref.G.X ) == 0 && mbedtls_mpi_cmp_mpi( &grp->G.Z, &ref.G.Z ) == 0 && /* For Y we may only know the parity bit, so compare only that */ mbedtls_mpi_get_bit( &grp->G.Y, 0 ) == mbedtls_mpi_get_bit( &ref.G.Y, 0 ) ) { break; } } cleanup: mbedtls_ecp_group_free( &ref ); *grp_id = *id; if( ret == 0 && *id == MBEDTLS_ECP_DP_NONE ) ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; return( ret ); }
/* Special-case of mbedtls_mpi_mult_mpi(), where we use hardware montgomery mod multiplication to calculate an mbedtls_mpi_mult_mpi result where either A or B are >2048 bits so can't use the standard multiplication method. Result (A bits + B bits) must still be less than 4096 bits. This case is simpler than the general case modulo multiply of esp_mpi_mul_mpi_mod() because we can control the other arguments: * Modulus is chosen with M=(2^num_bits - 1) (ie M=R-1), so output isn't actually modulo anything. * Mprime and Rinv are therefore predictable as follows: Mprime = 1 Rinv = 1 (See RSA Accelerator section in Technical Reference for more about Mprime, Rinv) */ static int mpi_mult_mpi_failover_mod_mult(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words) { int ret = 0; /* Load coefficients to hardware */ esp_mpi_acquire_hardware(); /* M = 2^num_words - 1, so block is entirely FF */ for(int i = 0; i < num_words; i++) { REG_WRITE(RSA_MEM_M_BLOCK_BASE + i * 4, UINT32_MAX); } /* Mprime = 1 */ REG_WRITE(RSA_M_DASH_REG, 1); /* "mode" register loaded with number of 512-bit blocks, minus 1 */ REG_WRITE(RSA_MULT_MODE_REG, (num_words / 16) - 1); /* Load X */ mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, num_words); /* Rinv = 1 */ REG_WRITE(RSA_MEM_RB_BLOCK_BASE, 1); for(int i = 1; i < num_words; i++) { REG_WRITE(RSA_MEM_RB_BLOCK_BASE + i * 4, 0); } execute_op(RSA_MULT_START_REG); /* finish the modular multiplication */ MBEDTLS_MPI_CHK( modular_multiply_finish(Z, X, Y, num_words) ); esp_mpi_release_hardware(); cleanup: return ret; }
int main( void ) { int ret; mbedtls_mpi E, P, Q, N, H, D, X, Y, Z; mbedtls_mpi_init( &E ); mbedtls_mpi_init( &P ); mbedtls_mpi_init( &Q ); mbedtls_mpi_init( &N ); mbedtls_mpi_init( &H ); mbedtls_mpi_init( &D ); mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &Z ); MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &P, 10, "2789" ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &Q, 10, "3203" ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &E, 10, "257" ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &N, &P, &Q ) ); mbedtls_printf( "\n Public key:\n\n" ); MBEDTLS_MPI_CHK( mbedtls_mpi_write_file( " N = ", &N, 10, NULL ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_write_file( " E = ", &E, 10, NULL ) ); mbedtls_printf( "\n Private key:\n\n" ); MBEDTLS_MPI_CHK( mbedtls_mpi_write_file( " P = ", &P, 10, NULL ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_write_file( " Q = ", &Q, 10, NULL ) ); #if defined(MBEDTLS_GENPRIME) MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &P, &P, 1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &Q, &Q, 1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &H, &P, &Q ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &D, &E, &H ) ); mbedtls_mpi_write_file( " D = E^-1 mod (P-1)*(Q-1) = ", &D, 10, NULL ); #else mbedtls_printf("\nTest skipped (MBEDTLS_GENPRIME not defined).\n\n"); #endif MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &X, 10, "55555" ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &Y, &X, &E, &N, NULL ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &Z, &Y, &D, &N, NULL ) ); mbedtls_printf( "\n RSA operation:\n\n" ); MBEDTLS_MPI_CHK( mbedtls_mpi_write_file( " X (plaintext) = ", &X, 10, NULL ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_write_file( " Y (ciphertext) = X^E mod N = ", &Y, 10, NULL ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_write_file( " Z (decrypted) = Y^D mod N = ", &Z, 10, NULL ) ); mbedtls_printf( "\n" ); cleanup: mbedtls_mpi_free( &E ); mbedtls_mpi_free( &P ); mbedtls_mpi_free( &Q ); mbedtls_mpi_free( &N ); mbedtls_mpi_free( &H ); mbedtls_mpi_free( &D ); mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z ); if( ret != 0 ) { mbedtls_printf( "\nAn error occurred.\n" ); ret = 1; } #if defined(_WIN32) mbedtls_printf( " Press Enter to exit this program.\n" ); fflush( stdout ); getchar(); #endif return( ret ); }
/* * Check a private RSA key */ int mbedtls_rsa_check_privkey( const mbedtls_rsa_context *ctx ) { int ret; mbedtls_mpi PQ, DE, P1, Q1, H, I, G, G2, L1, L2, DP, DQ, QP; if( ( ret = mbedtls_rsa_check_pubkey( ctx ) ) != 0 ) return( ret ); if( !ctx->P.p || !ctx->Q.p || !ctx->D.p ) return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); mbedtls_mpi_init( &PQ ); mbedtls_mpi_init( &DE ); mbedtls_mpi_init( &P1 ); mbedtls_mpi_init( &Q1 ); mbedtls_mpi_init( &H ); mbedtls_mpi_init( &I ); mbedtls_mpi_init( &G ); mbedtls_mpi_init( &G2 ); mbedtls_mpi_init( &L1 ); mbedtls_mpi_init( &L2 ); mbedtls_mpi_init( &DP ); mbedtls_mpi_init( &DQ ); mbedtls_mpi_init( &QP ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &PQ, &ctx->P, &ctx->Q ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &DE, &ctx->D, &ctx->E ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &P1, &ctx->P, 1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &Q1, &ctx->Q, 1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &H, &P1, &Q1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, &ctx->E, &H ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G2, &P1, &Q1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &L1, &L2, &H, &G2 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &I, &DE, &L1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &DP, &ctx->D, &P1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &DQ, &ctx->D, &Q1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &QP, &ctx->Q, &ctx->P ) ); /* * Check for a valid PKCS1v2 private key */ if( mbedtls_mpi_cmp_mpi( &PQ, &ctx->N ) != 0 || mbedtls_mpi_cmp_mpi( &DP, &ctx->DP ) != 0 || mbedtls_mpi_cmp_mpi( &DQ, &ctx->DQ ) != 0 || mbedtls_mpi_cmp_mpi( &QP, &ctx->QP ) != 0 || mbedtls_mpi_cmp_int( &L2, 0 ) != 0 || mbedtls_mpi_cmp_int( &I, 1 ) != 0 || mbedtls_mpi_cmp_int( &G, 1 ) != 0 ) { ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; } cleanup: mbedtls_mpi_free( &PQ ); mbedtls_mpi_free( &DE ); mbedtls_mpi_free( &P1 ); mbedtls_mpi_free( &Q1 ); mbedtls_mpi_free( &H ); mbedtls_mpi_free( &I ); mbedtls_mpi_free( &G ); mbedtls_mpi_free( &G2 ); mbedtls_mpi_free( &L1 ); mbedtls_mpi_free( &L2 ); mbedtls_mpi_free( &DP ); mbedtls_mpi_free( &DQ ); mbedtls_mpi_free( &QP ); if( ret == MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ) return( ret ); if( ret != 0 ) return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED + ret ); return( 0 ); }
/* * Do an RSA private key operation */ int mbedtls_rsa_private( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, const unsigned char *input, unsigned char *output ) { int ret; size_t olen; mbedtls_mpi T, T1, T2; /* Make sure we have private key info, prevent possible misuse */ if( ctx->P.p == NULL || ctx->Q.p == NULL || ctx->D.p == NULL ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 ); #if defined(MBEDTLS_THREADING_C) if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) return( ret ); #endif MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &T, input, ctx->len ) ); if( mbedtls_mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) { ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; goto cleanup; } if( f_rng != NULL ) { /* * Blinding * T = T * Vi mod N */ MBEDTLS_MPI_CHK( rsa_prepare_blinding( ctx, f_rng, p_rng ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &T, &ctx->Vi ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T, &ctx->N ) ); } #if defined(MBEDTLS_RSA_NO_CRT) MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T, &T, &ctx->D, &ctx->N, &ctx->RN ) ); #else /* * faster decryption using the CRT * * T1 = input ^ dP mod P * T2 = input ^ dQ mod Q */ MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T1, &T, &ctx->DP, &ctx->P, &ctx->RP ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T2, &T, &ctx->DQ, &ctx->Q, &ctx->RQ ) ); /* * T = (T1 - T2) * (Q^-1 mod P) mod P */ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T, &T1, &T2 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &T, &ctx->QP ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T1, &ctx->P ) ); /* * T = T2 + T * Q */ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &T, &ctx->Q ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &T, &T2, &T1 ) ); #endif /* MBEDTLS_RSA_NO_CRT */ if( f_rng != NULL ) { /* * Unblind * T = T * Vf mod N */ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &T, &ctx->Vf ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T, &ctx->N ) ); } olen = ctx->len; MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &T, output, olen ) ); cleanup: #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); #endif mbedtls_mpi_free( &T ); mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 ); if( ret != 0 ) return( MBEDTLS_ERR_RSA_PRIVATE_FAILED + ret ); return( 0 ); }
/* * Generate an RSA keypair */ int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, unsigned int nbits, int exponent ) { int ret; mbedtls_mpi P1, Q1, H, G; if( f_rng == NULL || nbits < 128 || exponent < 3 ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); mbedtls_mpi_init( &P1 ); mbedtls_mpi_init( &Q1 ); mbedtls_mpi_init( &H ); mbedtls_mpi_init( &G ); /* * find primes P and Q with Q < P so that: * GCD( E, (P-1)*(Q-1) ) == 1 */ MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->E, exponent ) ); do { MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->P, ( nbits + 1 ) >> 1, 0, f_rng, p_rng ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->Q, ( nbits + 1 ) >> 1, 0, f_rng, p_rng ) ); if( mbedtls_mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 ) mbedtls_mpi_swap( &ctx->P, &ctx->Q ); if( mbedtls_mpi_cmp_mpi( &ctx->P, &ctx->Q ) == 0 ) continue; MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) ); if( mbedtls_mpi_bitlen( &ctx->N ) != nbits ) continue; MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &P1, &ctx->P, 1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &Q1, &ctx->Q, 1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &H, &P1, &Q1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, &ctx->E, &H ) ); } while( mbedtls_mpi_cmp_int( &G, 1 ) != 0 ); /* * D = E^-1 mod ((P-1)*(Q-1)) * DP = D mod (P - 1) * DQ = D mod (Q - 1) * QP = Q^-1 mod P */ MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->D , &ctx->E, &H ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) ); ctx->len = ( mbedtls_mpi_bitlen( &ctx->N ) + 7 ) >> 3; cleanup: mbedtls_mpi_free( &P1 ); mbedtls_mpi_free( &Q1 ); mbedtls_mpi_free( &H ); mbedtls_mpi_free( &G ); if( ret != 0 ) { mbedtls_rsa_free( ctx ); return( MBEDTLS_ERR_RSA_KEY_GEN_FAILED + ret ); } return( 0 ); }
/* * Setup and write the ServerKeyExchange parameters */ int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size, unsigned char *output, size_t *olen, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret, count = 0; size_t n1, n2, n3; unsigned char *p; if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 ) return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); /* * Generate X as large as possible ( < P ) */ do { mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ); while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) ); if( count++ > 10 ) return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED ); } while( dhm_check_range( &ctx->X, &ctx->P ) != 0 ); /* * Calculate GX = G^X mod P */ MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X, &ctx->P , &ctx->RP ) ); if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 ) return( ret ); /* * export P, G, GX */ #define DHM_MPI_EXPORT(X,n) \ MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, p + 2, n ) ); \ *p++ = (unsigned char)( n >> 8 ); \ *p++ = (unsigned char)( n ); p += n; n1 = mbedtls_mpi_size( &ctx->P ); n2 = mbedtls_mpi_size( &ctx->G ); n3 = mbedtls_mpi_size( &ctx->GX ); p = output; DHM_MPI_EXPORT( &ctx->P , n1 ); DHM_MPI_EXPORT( &ctx->G , n2 ); DHM_MPI_EXPORT( &ctx->GX, n3 ); *olen = p - output; ctx->len = n1; cleanup: if( ret != 0 ) return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED + ret ); return( 0 ); }
//need to normalize the coordinates int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, const unsigned char *buf, size_t blen, const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s) { int ret = 0; CRYSError_t CrysRet = CRYS_OK; void* pHeap = NULL; size_t heapSize = 0; uint8_t * pSignature = NULL; CRYS_ECPKI_HASH_OpMode_t hash_mode = message_size_to_hash_mode( blen ); size_t temp_size = 0; uint32_t signature_size = ( ( grp->nbits + 7 ) / 8 ) * 2; const CRYS_ECPKI_Domain_t* pDomain = CRYS_ECPKI_GetEcDomain ( convert_mbedtls_grp_id_to_crys_domain_id( grp->id ) ); #if SIZE_MAX > UINT_MAX if( blen > 0xFFFFFFFF ) { return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); } #endif if ( pDomain ) { uint8_t temp_buf[ 2*MAX_KEY_SIZE_IN_BYTES + 1 ] = {0}; cc_ecc_ws_verify_params_t* verifyParams = mbedtls_calloc( 1, sizeof(cc_ecc_ws_verify_params_t) ); if ( verifyParams == NULL) return ( MBEDTLS_ERR_ECP_ALLOC_FAILED ); pHeap = verifyParams; heapSize = sizeof(cc_ecc_ws_verify_params_t); pSignature = mbedtls_calloc( 1, signature_size ); if ( pSignature == NULL) { ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; goto cleanup; } MBEDTLS_MPI_CHK( mbedtls_ecp_point_write_binary( grp, Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &temp_size, temp_buf, sizeof(temp_buf) ) ); CrysRet = CRYS_ECPKI_BuildPublKey(pDomain, temp_buf, temp_size, &verifyParams->pubKey); if( CrysRet != CRYS_OK ) { ret = convert_CrysError_to_mbedtls_err( CrysRet ); goto cleanup; } MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( r, pSignature, ( ( grp->nbits + 7 ) / 8 ) ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( s, pSignature + ( ( grp->nbits + 7 ) / 8 ), ( ( grp->nbits + 7 ) / 8 ) ) ); CrysRet = CRYS_ECDSA_Verify ( &verifyParams->verifyContext, &verifyParams->pubKey, hash_mode, pSignature, signature_size, (uint8_t*)buf, blen ); if( CrysRet != CRYS_OK ) { ret = convert_CrysError_to_mbedtls_err( CrysRet ); goto cleanup; } } else ret = MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED; cleanup: if( pHeap ) { mbedtls_zeroize( pHeap, heapSize ); mbedtls_free( pHeap ); } if( pSignature ) { mbedtls_zeroize( pSignature, signature_size ); mbedtls_free( pSignature ); } return ret; }
int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret = 0; CRYSError_t CrysRet = CRYS_OK; void* pHeap = NULL; size_t heapSize = 0; uint32_t key_size = 2*MAX_KEY_SIZE_IN_BYTES + 1; const CRYS_ECPKI_Domain_t* pDomain = CRYS_ECPKI_GetEcDomain ( convert_mbedtls_grp_id_to_crys_domain_id( gid ) ); mbedtls_rand_func_container cc_rand = { f_rng, p_rng }; if ( pDomain ) { uint8_t temp_buf[ 2 * MAX_KEY_SIZE_IN_BYTES + 1 ] = {0}; cc_ecc_ws_keygen_params_t* kgParams = mbedtls_calloc( 1, sizeof(cc_ecc_ws_keygen_params_t) ); if ( kgParams == NULL ) return ( MBEDTLS_ERR_ECP_ALLOC_FAILED ); pHeap = kgParams; heapSize = sizeof(cc_ecc_ws_keygen_params_t); CrysRet = CRYS_ECPKI_GenKeyPair( &cc_rand, convert_mbedtls_to_cc_rand, pDomain, &kgParams->privKey, &kgParams->pubKey, &kgParams->kgTempData, NULL ); if ( CrysRet != CRYS_OK ) { ret = convert_CrysError_to_mbedtls_err( CrysRet ); goto cleanup; } MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ctx->grp, gid ) ); CrysRet = CRYS_ECPKI_ExportPublKey( &kgParams->pubKey, CRYS_EC_PointUncompressed, temp_buf, &key_size ); if ( CrysRet != CRYS_OK ) { ret = convert_CrysError_to_mbedtls_err( CrysRet ); goto cleanup; } ret = mbedtls_ecp_point_read_binary( &ctx->grp, &ctx->Q, temp_buf, key_size ); if ( ret != 0 ) goto cleanup; memset ( temp_buf, 0 , sizeof(temp_buf) ); CrysRet = CRYS_COMMON_ConvertLswMswWordsToMsbLsbBytes( temp_buf, (ctx->grp.nbits+7)/8, kgParams->privKey.PrivKeyDbBuff, 4*((((ctx->grp.nbits+7)/8)+3)/4) ); if ( CrysRet != CRYS_OK ) { ret = convert_CrysError_to_mbedtls_err( CrysRet ); mbedtls_zeroize( temp_buf, sizeof(temp_buf) ); goto cleanup; } ret = mbedtls_mpi_read_binary( &ctx->d, temp_buf, (ctx->grp.nbits+7)/8 ); mbedtls_zeroize( temp_buf, sizeof(temp_buf) ); if ( ret != 0 ) { goto cleanup; } } else ret = MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED; cleanup: if ( pHeap ) { mbedtls_zeroize( pHeap, heapSize ); mbedtls_free ( pHeap ); } return ( ret ); }
int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, const mbedtls_mpi *d, const unsigned char *buf, size_t blen, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret = 0; CRYSError_t CrysRet = CRYS_OK; void* pHeap = NULL; size_t heapSize = 0; uint8_t* pSignature = NULL; CRYS_ECPKI_HASH_OpMode_t hash_mode = message_size_to_hash_mode( blen ); uint32_t signature_size = ( ( grp->nbits + 7 ) / 8 ) *2; const uint32_t signature_size_for_heap = signature_size; mbedtls_rand_func_container cc_rand = { f_rng, p_rng }; const CRYS_ECPKI_Domain_t* pDomain = CRYS_ECPKI_GetEcDomain ( convert_mbedtls_grp_id_to_crys_domain_id( grp->id ) ); #if SIZE_MAX > UINT_MAX if( blen > 0xFFFFFFFF ) { return ( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); } #endif if ( pDomain != NULL ) { uint8_t temp_buf[ MAX_KEY_SIZE_IN_BYTES ] = {0}; cc_ecc_ws_sign_params_t* signParams = mbedtls_calloc( 1, sizeof(cc_ecc_ws_sign_params_t) ); if ( signParams == NULL) return ( MBEDTLS_ERR_ECP_ALLOC_FAILED ); pHeap = signParams; heapSize = sizeof(cc_ecc_ws_sign_params_t); pSignature = mbedtls_calloc( 1, signature_size_for_heap ); if ( pSignature == NULL) { ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; goto cleanup; } MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, temp_buf, mbedtls_mpi_size( d ) ) ); CrysRet = CRYS_ECPKI_BuildPrivKey( pDomain, temp_buf, mbedtls_mpi_size( d ), &signParams->privKey); if( CrysRet != CRYS_OK ) { ret = convert_CrysError_to_mbedtls_err( CrysRet ); mbedtls_zeroize( temp_buf, sizeof(temp_buf) ); goto cleanup; } CrysRet = CRYS_ECDSA_Sign( &cc_rand, convert_mbedtls_to_cc_rand, &signParams->signContext, &signParams->privKey, hash_mode, (uint8_t*)buf, blen, pSignature, &signature_size ); mbedtls_zeroize( temp_buf, sizeof(temp_buf) ); if( CrysRet != CRYS_OK ) { ret = convert_CrysError_to_mbedtls_err( CrysRet ); goto cleanup; } } else { ret = MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED; goto cleanup; } MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( r, pSignature, ( ( grp->nbits + 7 ) / 8 ) ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( s, pSignature + ( ( grp->nbits + 7 ) / 8 ), ( ( grp->nbits + 7 ) / 8 ) ) ); cleanup: if ( pHeap ) { mbedtls_zeroize( pHeap, heapSize ); mbedtls_free( pHeap ); } if( pSignature ) { mbedtls_zeroize( pSignature, signature_size_for_heap ); mbedtls_free( pSignature ); } return ( ret ) ; }
/* * Compute ECDSA signature of a hashed message (SEC1 4.1.3) * Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message) */ static int ecdsa_sign_restartable( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, const mbedtls_mpi *d, const unsigned char *buf, size_t blen, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, mbedtls_ecdsa_restart_ctx *rs_ctx ) { int ret, key_tries, sign_tries; int *p_sign_tries = &sign_tries, *p_key_tries = &key_tries; mbedtls_ecp_point R; mbedtls_mpi k, e, t; mbedtls_mpi *pk = &k, *pr = r; /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ if( grp->N.p == NULL ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); /* Make sure d is in range 1..n-1 */ if( mbedtls_mpi_cmp_int( d, 1 ) < 0 || mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 ) return( MBEDTLS_ERR_ECP_INVALID_KEY ); mbedtls_ecp_point_init( &R ); mbedtls_mpi_init( &k ); mbedtls_mpi_init( &e ); mbedtls_mpi_init( &t ); ECDSA_RS_ENTER( sig ); #if defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && rs_ctx->sig != NULL ) { /* redirect to our context */ p_sign_tries = &rs_ctx->sig->sign_tries; p_key_tries = &rs_ctx->sig->key_tries; pk = &rs_ctx->sig->k; pr = &rs_ctx->sig->r; /* jump to current step */ if( rs_ctx->sig->state == ecdsa_sig_mul ) goto mul; if( rs_ctx->sig->state == ecdsa_sig_modn ) goto modn; } #endif /* MBEDTLS_ECP_RESTARTABLE */ *p_sign_tries = 0; do { if( *p_sign_tries++ > 10 ) { ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; goto cleanup; } /* * Steps 1-3: generate a suitable ephemeral keypair * and set r = xR mod n */ *p_key_tries = 0; do { if( *p_key_tries++ > 10 ) { ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; goto cleanup; } MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, pk, f_rng, p_rng ) ); #if defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && rs_ctx->sig != NULL ) rs_ctx->sig->state = ecdsa_sig_mul; mul: #endif MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &R, pk, &grp->G, f_rng, p_rng, ECDSA_RS_ECP ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pr, &R.X, &grp->N ) ); } while( mbedtls_mpi_cmp_int( pr, 0 ) == 0 ); #if defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && rs_ctx->sig != NULL ) rs_ctx->sig->state = ecdsa_sig_modn; modn: #endif /* * Accounting for everything up to the end of the loop * (step 6, but checking now avoids saving e and t) */ ECDSA_BUDGET( MBEDTLS_ECP_OPS_INV + 4 ); /* * Step 5: derive MPI from hashed message */ MBEDTLS_MPI_CHK( derive_mpi( grp, &e, buf, blen ) ); /* * Generate a random value to blind inv_mod in next step, * avoiding a potential timing leak. */ MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, &t, f_rng, p_rng ) ); /* * Step 6: compute s = (e + r * d) / k = t (e + rd) / (kt) mod n */ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, pr, d ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &e, &e, s ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &e, &e, &t ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pk, pk, &t ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( s, pk, &grp->N ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, s, &e ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( s, s, &grp->N ) ); } while( mbedtls_mpi_cmp_int( s, 0 ) == 0 ); #if defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && rs_ctx->sig != NULL ) mbedtls_mpi_copy( r, pr ); #endif cleanup: mbedtls_ecp_point_free( &R ); mbedtls_mpi_free( &k ); mbedtls_mpi_free( &e ); mbedtls_mpi_free( &t ); ECDSA_RS_LEAVE( sig ); return( ret ); }
/* * Sliding-window exponentiation: Z = X^Y mod M (HAC 14.85) * * _Rinv is optional pre-calculated version of Rinv (via calculate_rinv()). * * (See RSA Accelerator section in Technical Reference for more about Mprime, Rinv) * */ int mbedtls_mpi_exp_mod( mbedtls_mpi* Z, const mbedtls_mpi* X, const mbedtls_mpi* Y, const mbedtls_mpi* M, mbedtls_mpi* _Rinv ) { int ret = 0; size_t z_words = hardware_words_needed(Z); size_t x_words = hardware_words_needed(X); size_t y_words = hardware_words_needed(Y); size_t m_words = hardware_words_needed(M); size_t num_words; mbedtls_mpi Rinv_new; /* used if _Rinv == NULL */ mbedtls_mpi *Rinv; /* points to _Rinv (if not NULL) othwerwise &RR_new */ mbedtls_mpi_uint Mprime; /* "all numbers must be the same length", so choose longest number as cardinal length of operation... */ num_words = z_words; if (x_words > num_words) { num_words = x_words; } if (y_words > num_words) { num_words = y_words; } if (m_words > num_words) { num_words = m_words; } if (num_words * 32 > 4096) { return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; } /* Determine RR pointer, either _RR for cached value or local RR_new */ if (_Rinv == NULL) { mbedtls_mpi_init(&Rinv_new); Rinv = &Rinv_new; } else { Rinv = _Rinv; } if (Rinv->p == NULL) { MBEDTLS_MPI_CHK(calculate_rinv(Rinv, M, num_words)); } Mprime = modular_inverse(M); esp_mpi_acquire_hardware(); /* "mode" register loaded with number of 512-bit blocks, minus 1 */ REG_WRITE(RSA_MODEXP_MODE_REG, (num_words / 16) - 1); /* Load M, X, Rinv, M-prime (M-prime is mod 2^32) */ mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, num_words); mpi_to_mem_block(RSA_MEM_Y_BLOCK_BASE, Y, num_words); mpi_to_mem_block(RSA_MEM_M_BLOCK_BASE, M, num_words); mpi_to_mem_block(RSA_MEM_RB_BLOCK_BASE, Rinv, num_words); REG_WRITE(RSA_M_DASH_REG, Mprime); execute_op(RSA_START_MODEXP_REG); ret = mem_block_to_mpi(Z, RSA_MEM_Z_BLOCK_BASE, num_words); esp_mpi_release_hardware(); cleanup: if (_Rinv == NULL) { mbedtls_mpi_free(&Rinv_new); } return ret; }
/* * Deterministic signature wrapper */ static int ecdsa_sign_det_restartable( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, const mbedtls_mpi *d, const unsigned char *buf, size_t blen, mbedtls_md_type_t md_alg, mbedtls_ecdsa_restart_ctx *rs_ctx ) { int ret; mbedtls_hmac_drbg_context rng_ctx; mbedtls_hmac_drbg_context *p_rng = &rng_ctx; unsigned char data[2 * MBEDTLS_ECP_MAX_BYTES]; size_t grp_len = ( grp->nbits + 7 ) / 8; const mbedtls_md_info_t *md_info; mbedtls_mpi h; if( ( md_info = mbedtls_md_info_from_type( md_alg ) ) == NULL ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); mbedtls_mpi_init( &h ); mbedtls_hmac_drbg_init( &rng_ctx ); ECDSA_RS_ENTER( det ); #if defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && rs_ctx->det != NULL ) { /* redirect to our context */ p_rng = &rs_ctx->det->rng_ctx; /* jump to current step */ if( rs_ctx->det->state == ecdsa_det_sign ) goto sign; } #endif /* MBEDTLS_ECP_RESTARTABLE */ /* Use private key and message hash (reduced) to initialize HMAC_DRBG */ MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, data, grp_len ) ); MBEDTLS_MPI_CHK( derive_mpi( grp, &h, buf, blen ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, data + grp_len, grp_len ) ); mbedtls_hmac_drbg_seed_buf( p_rng, md_info, data, 2 * grp_len ); #if defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && rs_ctx->det != NULL ) rs_ctx->det->state = ecdsa_det_sign; sign: #endif #if defined(MBEDTLS_ECDSA_SIGN_ALT) ret = mbedtls_ecdsa_sign( grp, r, s, d, buf, blen, mbedtls_hmac_drbg_random, p_rng ); #else ret = ecdsa_sign_restartable( grp, r, s, d, buf, blen, mbedtls_hmac_drbg_random, p_rng, rs_ctx ); #endif /* MBEDTLS_ECDSA_SIGN_ALT */ cleanup: mbedtls_hmac_drbg_free( &rng_ctx ); mbedtls_mpi_free( &h ); ECDSA_RS_LEAVE( det ); return( ret ); }
/* * Verify ECDSA signature of hashed message (SEC1 4.1.4) * Obviously, compared to SEC1 4.1.3, we skip step 2 (hash message) */ static int ecdsa_verify_restartable( mbedtls_ecp_group *grp, const unsigned char *buf, size_t blen, const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s, mbedtls_ecdsa_restart_ctx *rs_ctx ) { int ret; mbedtls_mpi e, s_inv, u1, u2; mbedtls_ecp_point R; mbedtls_mpi *pu1 = &u1, *pu2 = &u2; mbedtls_ecp_point_init( &R ); mbedtls_mpi_init( &e ); mbedtls_mpi_init( &s_inv ); mbedtls_mpi_init( &u1 ); mbedtls_mpi_init( &u2 ); /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ if( grp->N.p == NULL ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); ECDSA_RS_ENTER( ver ); #if defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && rs_ctx->ver != NULL ) { /* redirect to our context */ pu1 = &rs_ctx->ver->u1; pu2 = &rs_ctx->ver->u2; /* jump to current step */ if( rs_ctx->ver->state == ecdsa_ver_muladd ) goto muladd; } #endif /* MBEDTLS_ECP_RESTARTABLE */ /* * Step 1: make sure r and s are in range 1..n-1 */ if( mbedtls_mpi_cmp_int( r, 1 ) < 0 || mbedtls_mpi_cmp_mpi( r, &grp->N ) >= 0 || mbedtls_mpi_cmp_int( s, 1 ) < 0 || mbedtls_mpi_cmp_mpi( s, &grp->N ) >= 0 ) { ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; goto cleanup; } /* * Step 3: derive MPI from hashed message */ MBEDTLS_MPI_CHK( derive_mpi( grp, &e, buf, blen ) ); /* * Step 4: u1 = e / s mod n, u2 = r / s mod n */ ECDSA_BUDGET( MBEDTLS_ECP_OPS_CHK + MBEDTLS_ECP_OPS_INV + 2 ); MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &s_inv, s, &grp->N ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pu1, &e, &s_inv ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pu1, pu1, &grp->N ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pu2, r, &s_inv ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pu2, pu2, &grp->N ) ); #if defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && rs_ctx->ver != NULL ) rs_ctx->ver->state = ecdsa_ver_muladd; muladd: #endif /* * Step 5: R = u1 G + u2 Q */ MBEDTLS_MPI_CHK( mbedtls_ecp_muladd_restartable( grp, &R, pu1, &grp->G, pu2, Q, ECDSA_RS_ECP ) ); if( mbedtls_ecp_is_zero( &R ) ) { ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; goto cleanup; } /* * Step 6: convert xR to an integer (no-op) * Step 7: reduce xR mod n (gives v) */ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &R.X, &R.X, &grp->N ) ); /* * Step 8: check if v (that is, R.X) is equal to r */ if( mbedtls_mpi_cmp_mpi( &R.X, r ) != 0 ) { ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; goto cleanup; } cleanup: mbedtls_ecp_point_free( &R ); mbedtls_mpi_free( &e ); mbedtls_mpi_free( &s_inv ); mbedtls_mpi_free( &u1 ); mbedtls_mpi_free( &u2 ); ECDSA_RS_LEAVE( ver ); return( ret ); }