/* * 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 ); }
/* * 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); }
/* * 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 ); }
static int addi(void *a, unsigned long b, void *c) { uint32_t b32 = b; if (b32 != b) return CRYPT_INVALID_ARG; mbedtls_mpi_uint p = b32; mbedtls_mpi bn = { .s = 1, .n = 1, .p = &p }; return add(a, &bn, c); } /* sub */ static int sub(void *a, void *b, void *c) { if (mbedtls_mpi_sub_mpi(c, a, b)) return CRYPT_MEM; return CRYPT_OK; } static int subi(void *a, unsigned long b, void *c) { uint32_t b32 = b; if (b32 != b) return CRYPT_INVALID_ARG; mbedtls_mpi_uint p = b32; mbedtls_mpi bn = { .s = 1, .n = 1, .p = &p }; return sub(a, &bn, c); } /* mul */ static int mul(void *a, void *b, void *c) { if (mbedtls_mpi_mul_mpi(c, a, b)) return CRYPT_MEM; return CRYPT_OK; } static int muli(void *a, unsigned long b, void *c) { if (b > (unsigned long) UINT32_MAX) return CRYPT_INVALID_ARG; if (mbedtls_mpi_mul_int(c, a, b)) return CRYPT_MEM; return CRYPT_OK; } /* sqr */ static int sqr(void *a, void *b) { return mul(a, a, b); } /* div */ static int divide(void *a, void *b, void *c, void *d) { int res = mbedtls_mpi_div_mpi(c, d, a, b); if (res == MBEDTLS_ERR_MPI_ALLOC_FAILED) return CRYPT_MEM; if (res) return CRYPT_ERROR; return CRYPT_OK; }