/* * 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 ); }
/* * 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 ); }
/* * This function calculates: * d = a^b mod c * * @a: base * @b: exponent * @c: modulus * @d: destination */ static int exptmod(void *a, void *b, void *c, void *d) { int res; if (d == a || d == b || d == c) { mbedtls_mpi dest; mbedtls_mpi_init_mempool(&dest); res = mbedtls_mpi_exp_mod(&dest, a, b, c, NULL); if (!res) res = mbedtls_mpi_copy(d, &dest); mbedtls_mpi_free(&dest); } else { res = mbedtls_mpi_exp_mod(d, a, b, c, NULL); } if (res) return CRYPT_MEM; else return CRYPT_OK; }
/* * 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 ); }
/* * 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 ); }
/* * 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 ); }
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 ); }
/* * 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 ); }
/* * 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 ); }