/* * 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 ); }
static int div_2(void *a, void *b) { if (mbedtls_mpi_copy(b, a)) return CRYPT_MEM; if (mbedtls_mpi_shift_r(b, 1)) return CRYPT_MEM; return CRYPT_OK; }
void TEE_BigIntShiftRight(TEE_BigInt *dest, const TEE_BigInt *op, size_t bits) { mbedtls_mpi mpi_dest; mbedtls_mpi mpi_op; get_mpi(&mpi_dest, dest); if (dest == op) { MPI_CHECK(mbedtls_mpi_shift_r(&mpi_dest, bits)); goto out; } get_mpi(&mpi_op, op); if (mbedtls_mpi_size(&mpi_dest) >= mbedtls_mpi_size(&mpi_op)) { MPI_CHECK(mbedtls_mpi_copy(&mpi_dest, &mpi_op)); MPI_CHECK(mbedtls_mpi_shift_r(&mpi_dest, bits)); } else { mbedtls_mpi mpi_t; get_mpi(&mpi_t, NULL); /* * We're using a temporary buffer to avoid the corner case * where destination is unexpectedly overflowed by up to * @bits number of bits. */ MPI_CHECK(mbedtls_mpi_copy(&mpi_t, &mpi_op)); MPI_CHECK(mbedtls_mpi_shift_r(&mpi_t, bits)); MPI_CHECK(mbedtls_mpi_copy(&mpi_dest, &mpi_t)); mbedtls_mpi_free(&mpi_t); } mbedtls_mpi_free(&mpi_op); out: MPI_CHECK(copy_mpi_to_bigint(&mpi_dest, dest)); mbedtls_mpi_free(&mpi_dest); }
/* * 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 ); }
/* * 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 ); }
/* * Compute ECDSA signature of a hashed message (SEC1 4.1.3) * Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message) */ 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, key_tries, sign_tries, blind_tries; mbedtls_ecp_point R; mbedtls_mpi k, e, t; /* 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 ); mbedtls_ecp_point_init( &R ); mbedtls_mpi_init( &k ); mbedtls_mpi_init( &e ); mbedtls_mpi_init( &t ); sign_tries = 0; do { /* * Steps 1-3: generate a suitable ephemeral keypair * and set r = xR mod n */ key_tries = 0; do { MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair( grp, &k, &R, f_rng, p_rng ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( r, &R.X, &grp->N ) ); if( key_tries++ > 10 ) { ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; goto cleanup; } } while( mbedtls_mpi_cmp_int( r, 0 ) == 0 ); /* * 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. */ blind_tries = 0; do { size_t n_size = ( grp->nbits + 7 ) / 8; MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &t, n_size, f_rng, p_rng ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &t, 8 * n_size - grp->nbits ) ); /* See mbedtls_ecp_gen_keypair() */ if( ++blind_tries > 30 ) return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); } while( mbedtls_mpi_cmp_int( &t, 1 ) < 0 || mbedtls_mpi_cmp_mpi( &t, &grp->N ) >= 0 ); /* * Step 6: compute s = (e + r * d) / k = t (e + rd) / (kt) mod n */ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, r, 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( &k, &k, &t ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( s, &k, &grp->N ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, s, &e ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( s, s, &grp->N ) ); if( sign_tries++ > 10 ) { ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; goto cleanup; } } while( mbedtls_mpi_cmp_int( s, 0 ) == 0 ); cleanup: mbedtls_ecp_point_free( &R ); mbedtls_mpi_free( &k ); mbedtls_mpi_free( &e ); mbedtls_mpi_free( &t ); return( ret ); }
/* * Based on libmpa implementation __mpa_egcd(), modified to work with MPI * instead. */ static void mpi_egcd(mbedtls_mpi *gcd, mbedtls_mpi *a, mbedtls_mpi *b, mbedtls_mpi *x_in, mbedtls_mpi *y_in) { mbedtls_mpi_uint k; mbedtls_mpi A; mbedtls_mpi B; mbedtls_mpi C; mbedtls_mpi D; mbedtls_mpi x; mbedtls_mpi y; mbedtls_mpi u; get_mpi(&A, NULL); get_mpi(&B, NULL); get_mpi(&C, NULL); get_mpi(&D, NULL); get_mpi(&x, NULL); get_mpi(&y, NULL); get_mpi(&u, NULL); /* have y < x from assumption */ if (!mbedtls_mpi_cmp_int(y_in, 0)) { MPI_CHECK(mbedtls_mpi_lset(a, 1)); MPI_CHECK(mbedtls_mpi_lset(b, 0)); MPI_CHECK(mbedtls_mpi_copy(gcd, x_in)); goto out; } MPI_CHECK(mbedtls_mpi_copy(&x, x_in)); MPI_CHECK(mbedtls_mpi_copy(&y, y_in)); k = 0; while (mpi_is_even(&x) && mpi_is_even(&y)) { k++; MPI_CHECK(mbedtls_mpi_shift_r(&x, 1)); MPI_CHECK(mbedtls_mpi_shift_r(&y, 1)); } MPI_CHECK(mbedtls_mpi_copy(&u, &x)); MPI_CHECK(mbedtls_mpi_copy(gcd, &y)); MPI_CHECK(mbedtls_mpi_lset(&A, 1)); MPI_CHECK(mbedtls_mpi_lset(&B, 0)); MPI_CHECK(mbedtls_mpi_lset(&C, 0)); MPI_CHECK(mbedtls_mpi_lset(&D, 1)); while (mbedtls_mpi_cmp_int(&u, 0)) { while (mpi_is_even(&u)) { MPI_CHECK(mbedtls_mpi_shift_r(&u, 1)); if (mpi_is_odd(&A) || mpi_is_odd(&B)) { MPI_CHECK(mbedtls_mpi_add_mpi(&A, &A, &y)); MPI_CHECK(mbedtls_mpi_sub_mpi(&B, &B, &x)); } MPI_CHECK(mbedtls_mpi_shift_r(&A, 1)); MPI_CHECK(mbedtls_mpi_shift_r(&B, 1)); } while (mpi_is_even(gcd)) { MPI_CHECK(mbedtls_mpi_shift_r(gcd, 1)); if (mpi_is_odd(&C) || mpi_is_odd(&D)) { MPI_CHECK(mbedtls_mpi_add_mpi(&C, &C, &y)); MPI_CHECK(mbedtls_mpi_sub_mpi(&D, &D, &x)); } MPI_CHECK(mbedtls_mpi_shift_r(&C, 1)); MPI_CHECK(mbedtls_mpi_shift_r(&D, 1)); } if (mbedtls_mpi_cmp_mpi(&u, gcd) >= 0) { MPI_CHECK(mbedtls_mpi_sub_mpi(&u, &u, gcd)); MPI_CHECK(mbedtls_mpi_sub_mpi(&A, &A, &C)); MPI_CHECK(mbedtls_mpi_sub_mpi(&B, &B, &D)); } else { MPI_CHECK(mbedtls_mpi_sub_mpi(gcd, gcd, &u)); MPI_CHECK(mbedtls_mpi_sub_mpi(&C, &C, &A)); MPI_CHECK(mbedtls_mpi_sub_mpi(&D, &D, &B)); } } MPI_CHECK(mbedtls_mpi_copy(a, &C)); MPI_CHECK(mbedtls_mpi_copy(b, &D)); MPI_CHECK(mbedtls_mpi_shift_l(gcd, k)); out: mbedtls_mpi_free(&A); mbedtls_mpi_free(&B); mbedtls_mpi_free(&C); mbedtls_mpi_free(&D); mbedtls_mpi_free(&x); mbedtls_mpi_free(&y); mbedtls_mpi_free(&u); }