/* * Check a private RSA key */ int shrsa_check_privkey( const shrsa_context *ctx ) { int ret; shmpi PQ, DE, P1, Q1, H, I, G, G2, L1, L2, DP, DQ, QP; if( ( ret = shrsa_check_pubkey( ctx ) ) != 0 ) return( ret ); if( !ctx->P.p || !ctx->Q.p || !ctx->D.p ) return( RSA_ERR_RSA_KEY_CHECK_FAILED ); shmpi_init( &PQ ); shmpi_init( &DE ); shmpi_init( &P1 ); shmpi_init( &Q1 ); shmpi_init( &H ); shmpi_init( &I ); shmpi_init( &G ); shmpi_init( &G2 ); shmpi_init( &L1 ); shmpi_init( &L2 ); shmpi_init( &DP ); shmpi_init( &DQ ); shmpi_init( &QP ); MPI_CHK( shmpi_mul_shmpi( &PQ, &ctx->P, &ctx->Q ) ); MPI_CHK( shmpi_mul_shmpi( &DE, &ctx->D, &ctx->E ) ); MPI_CHK( shmpi_sub_int( &P1, &ctx->P, 1 ) ); MPI_CHK( shmpi_sub_int( &Q1, &ctx->Q, 1 ) ); MPI_CHK( shmpi_mul_shmpi( &H, &P1, &Q1 ) ); MPI_CHK( shmpi_gcd( &G, &ctx->E, &H ) ); MPI_CHK( shmpi_gcd( &G2, &P1, &Q1 ) ); MPI_CHK( shmpi_div_shmpi( &L1, &L2, &H, &G2 ) ); MPI_CHK( shmpi_mod_shmpi( &I, &DE, &L1 ) ); MPI_CHK( shmpi_mod_shmpi( &DP, &ctx->D, &P1 ) ); MPI_CHK( shmpi_mod_shmpi( &DQ, &ctx->D, &Q1 ) ); MPI_CHK( shmpi_inv_mod( &QP, &ctx->Q, &ctx->P ) ); /* * Check for a valid PKCS1v2 private key */ if( shmpi_cmp_shmpi( &PQ, &ctx->N ) != 0 || shmpi_cmp_shmpi( &DP, &ctx->DP ) != 0 || shmpi_cmp_shmpi( &DQ, &ctx->DQ ) != 0 || shmpi_cmp_shmpi( &QP, &ctx->QP ) != 0 || shmpi_cmp_int( &L2, 0 ) != 0 || shmpi_cmp_int( &I, 1 ) != 0 || shmpi_cmp_int( &G, 1 ) != 0 ) { ret = RSA_ERR_RSA_KEY_CHECK_FAILED; } cleanup: shmpi_free( &PQ ); shmpi_free( &DE ); shmpi_free( &P1 ); shmpi_free( &Q1 ); shmpi_free( &H ); shmpi_free( &I ); shmpi_free( &G ); shmpi_free( &G2 ); shmpi_free( &L1 ); shmpi_free( &L2 ); shmpi_free( &DP ); shmpi_free( &DQ ); shmpi_free( &QP ); if( ret == RSA_ERR_RSA_KEY_CHECK_FAILED ) return( ret ); if( ret != 0 ) return( RSA_ERR_RSA_KEY_CHECK_FAILED + ret ); return( 0 ); }
/* * Check if contexts holding a public and private key match */ int shrsa_check_pub_priv( const shrsa_context *pub, const shrsa_context *prv ) { if( shrsa_check_pubkey( pub ) != 0 || shrsa_check_privkey( prv ) != 0 ) { return( RSA_ERR_RSA_KEY_CHECK_FAILED ); } if( shmpi_cmp_shmpi( &pub->N, &prv->N ) != 0 || shmpi_cmp_shmpi( &pub->E, &prv->E ) != 0 ) { return( RSA_ERR_RSA_KEY_CHECK_FAILED ); } return( 0 ); }
/* * Check a public RSA key */ int shrsa_check_pubkey( const shrsa_context *ctx ) { if( !ctx->N.p || !ctx->E.p ) return( RSA_ERR_RSA_KEY_CHECK_FAILED ); if( ( ctx->N.p[0] & 1 ) == 0 || ( ctx->E.p[0] & 1 ) == 0 ) return( RSA_ERR_RSA_KEY_CHECK_FAILED ); if( shmpi_msb( &ctx->N ) < 128 || shmpi_msb( &ctx->N ) > MPI_MPI_MAX_BITS ) return( RSA_ERR_RSA_KEY_CHECK_FAILED ); if( shmpi_msb( &ctx->E ) < 2 || shmpi_cmp_shmpi( &ctx->E, &ctx->N ) >= 0 ) return( RSA_ERR_RSA_KEY_CHECK_FAILED ); return( 0 ); }
/* * Do an RSA public key operation */ int shrsa_public( shrsa_context *ctx, const unsigned char *input, unsigned char *output ) { int ret; size_t olen; shmpi T; shmpi_init( &T ); MPI_CHK( shmpi_read_binary( &T, input, ctx->len ) ); if( shmpi_cmp_shmpi( &T, &ctx->N ) >= 0 ) { shmpi_free( &T ); return( RSA_ERR_RSA_BAD_INPUT_DATA ); } #if defined(RSA_THREADING_C) polarssl_mutex_lock( &ctx->mutex ); #endif olen = ctx->len; MPI_CHK( shmpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) ); MPI_CHK( shmpi_write_binary( &T, output, olen ) ); cleanup: #if defined(RSA_THREADING_C) polarssl_mutex_unlock( &ctx->mutex ); #endif shmpi_free( &T ); if( ret != 0 ) return( RSA_ERR_RSA_PUBLIC_FAILED + ret ); return( 0 ); }
/* * 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 ecp_group *grp, ecp_group_id *grp_id ) { int ret = 0; ecp_group ref; const ecp_group_id *id; ecp_group_init( &ref ); for( id = ecp_grp_id_list(); *id != POLARSSL_ECP_DP_NONE; id++ ) { /* Load the group associated to that id */ ecp_group_free( &ref ); MPI_CHK( ecp_use_known_dp( &ref, *id ) ); /* Compare to the group we were given, starting with easy tests */ if( grp->pbits == ref.pbits && grp->nbits == ref.nbits && shmpi_cmp_shmpi( &grp->P, &ref.P ) == 0 && shmpi_cmp_shmpi( &grp->A, &ref.A ) == 0 && shmpi_cmp_shmpi( &grp->B, &ref.B ) == 0 && shmpi_cmp_shmpi( &grp->N, &ref.N ) == 0 && shmpi_cmp_shmpi( &grp->G.X, &ref.G.X ) == 0 && shmpi_cmp_shmpi( &grp->G.Z, &ref.G.Z ) == 0 && /* For Y we may only know the parity bit, so compare only that */ shmpi_get_bit( &grp->G.Y, 0 ) == shmpi_get_bit( &ref.G.Y, 0 ) ) { break; } } cleanup: ecp_group_free( &ref ); *grp_id = *id; if( ret == 0 && *id == POLARSSL_ECP_DP_NONE ) ret = POLARSSL_ERR_ECP_FEATURE_UNAVAILABLE; return( ret ); }
/* * Generate an RSA keypair */ int shrsa_gen_key( shrsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, unsigned int nbits, int exponent ) { int ret; shmpi P1, Q1, H, G; if( f_rng == NULL || nbits < 128 || exponent < 3 ) return( RSA_ERR_RSA_BAD_INPUT_DATA ); shmpi_init( &P1 ); shmpi_init( &Q1 ); shmpi_init( &H ); shmpi_init( &G ); /* * find primes P and Q with Q < P so that: * GCD( E, (P-1)*(Q-1) ) == 1 */ MPI_CHK( shmpi_lset( &ctx->E, exponent ) ); do { MPI_CHK( shmpi_gen_prime( &ctx->P, ( nbits + 1 ) >> 1, 0, f_rng, p_rng ) ); MPI_CHK( shmpi_gen_prime( &ctx->Q, ( nbits + 1 ) >> 1, 0, f_rng, p_rng ) ); if( shmpi_cmp_shmpi( &ctx->P, &ctx->Q ) < 0 ) shmpi_swap( &ctx->P, &ctx->Q ); if( shmpi_cmp_shmpi( &ctx->P, &ctx->Q ) == 0 ) continue; MPI_CHK( shmpi_mul_shmpi( &ctx->N, &ctx->P, &ctx->Q ) ); if( shmpi_msb( &ctx->N ) != nbits ) continue; MPI_CHK( shmpi_sub_int( &P1, &ctx->P, 1 ) ); MPI_CHK( shmpi_sub_int( &Q1, &ctx->Q, 1 ) ); MPI_CHK( shmpi_mul_shmpi( &H, &P1, &Q1 ) ); MPI_CHK( shmpi_gcd( &G, &ctx->E, &H ) ); } while( shmpi_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 */ MPI_CHK( shmpi_inv_mod( &ctx->D , &ctx->E, &H ) ); MPI_CHK( shmpi_mod_shmpi( &ctx->DP, &ctx->D, &P1 ) ); MPI_CHK( shmpi_mod_shmpi( &ctx->DQ, &ctx->D, &Q1 ) ); MPI_CHK( shmpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) ); ctx->len = ( shmpi_msb( &ctx->N ) + 7 ) >> 3; cleanup: shmpi_free( &P1 ); shmpi_free( &Q1 ); shmpi_free( &H ); shmpi_free( &G ); if( ret != 0 ) { shrsa_free( ctx ); return( RSA_ERR_RSA_KEY_GEN_FAILED + ret ); } return( 0 ); }
/* * Do an RSA private key operation */ int shrsa_private( shrsa_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; shmpi T, T1, T2; shmpi *Vi, *Vf; /* * When using the Chinese Remainder Theorem, we use blinding values. * Without threading, we just read them directly from the context, * otherwise we make a local copy in order to reduce locking contention. */ #if defined(RSA_THREADING_C) shmpi Vi_copy, Vf_copy; shmpi_init( &Vi_copy ); shmpi_init( &Vf_copy ); Vi = &Vi_copy; Vf = &Vf_copy; #else Vi = &ctx->Vi; Vf = &ctx->Vf; #endif shmpi_init( &T ); shmpi_init( &T1 ); shmpi_init( &T2 ); MPI_CHK( shmpi_read_binary( &T, input, ctx->len ) ); if( shmpi_cmp_shmpi( &T, &ctx->N ) >= 0 ) { shmpi_free( &T ); return( RSA_ERR_RSA_BAD_INPUT_DATA ); } if( f_rng != NULL ) { /* * Blinding * T = T * Vi mod N */ MPI_CHK( shrsa_prepare_blinding( ctx, Vi, Vf, f_rng, p_rng ) ); MPI_CHK( shmpi_mul_shmpi( &T, &T, Vi ) ); MPI_CHK( shmpi_mod_shmpi( &T, &T, &ctx->N ) ); } #if defined(RSA_THREADING_C) polarssl_mutex_lock( &ctx->mutex ); #endif #if defined(RSA_RSA_NO_CRT) MPI_CHK( shmpi_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 */ MPI_CHK( shmpi_exp_mod( &T1, &T, &ctx->DP, &ctx->P, &ctx->RP ) ); MPI_CHK( shmpi_exp_mod( &T2, &T, &ctx->DQ, &ctx->Q, &ctx->RQ ) ); /* * T = (T1 - T2) * (Q^-1 mod P) mod P */ MPI_CHK( shmpi_sub_shmpi( &T, &T1, &T2 ) ); MPI_CHK( shmpi_mul_shmpi( &T1, &T, &ctx->QP ) ); MPI_CHK( shmpi_mod_shmpi( &T, &T1, &ctx->P ) ); /* * T = T2 + T * Q */ MPI_CHK( shmpi_mul_shmpi( &T1, &T, &ctx->Q ) ); MPI_CHK( shmpi_add_shmpi( &T, &T2, &T1 ) ); #endif /* RSA_RSA_NO_CRT */ if( f_rng != NULL ) { /* * Unblind * T = T * Vf mod N */ MPI_CHK( shmpi_mul_shmpi( &T, &T, Vf ) ); MPI_CHK( shmpi_mod_shmpi( &T, &T, &ctx->N ) ); } olen = ctx->len; MPI_CHK( shmpi_write_binary( &T, output, olen ) ); cleanup: #if defined(RSA_THREADING_C) polarssl_mutex_unlock( &ctx->mutex ); shmpi_free( &Vi_copy ); shmpi_free( &Vf_copy ); #endif shmpi_free( &T ); shmpi_free( &T1 ); shmpi_free( &T2 ); if( ret != 0 ) return( RSA_ERR_RSA_PRIVATE_FAILED + ret ); return( 0 ); }