BN_BLINDING *BN_BLINDING_create_param(BN_BLINDING *b,
	const BIGNUM *e, BIGNUM *m, BN_CTX *ctx,
	int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
			  const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx),
	BN_MONT_CTX *m_ctx)
{
	int    retry_counter = 32;
	BN_BLINDING *ret = NULL;

	if (b == NULL)
		ret = BN_BLINDING_new(NULL, NULL, m);
	else
		ret = b;

	if (ret == NULL)
		goto err;

	if (ret->A  == NULL && (ret->A  = BN_new()) == NULL)
		goto err;
	if (ret->Ai == NULL && (ret->Ai	= BN_new()) == NULL)
		goto err;

	if (e != NULL)
		{
		if (ret->e != NULL)
			BN_free(ret->e);
		ret->e = BN_dup(e);
		}
	if (ret->e == NULL)
		goto err;

	if (bn_mod_exp != NULL)
		ret->bn_mod_exp = bn_mod_exp;
	if (m_ctx != NULL)
		ret->m_ctx = m_ctx;

	do {
		int rv;
		if (!BN_rand_range(ret->A, ret->mod)) goto err;
		if (!int_bn_mod_inverse(ret->Ai, ret->A, ret->mod, ctx, &rv))
			{
			/* this should almost never happen for good RSA keys */
			if (rv)
				{
				if (retry_counter-- == 0)
				{
					BNerr(BN_F_BN_BLINDING_CREATE_PARAM,
						BN_R_TOO_MANY_ITERATIONS);
					goto err;
				}
				}
			else
				goto err;
			}
		else
			break;
	} while (1);

	if (ret->bn_mod_exp != NULL && ret->m_ctx != NULL)
		{
		if (!ret->bn_mod_exp(ret->A, ret->A, ret->e, ret->mod, ctx, ret->m_ctx))
			goto err;
		}
	else
		{
		if (!BN_mod_exp(ret->A, ret->A, ret->e, ret->mod, ctx))
			goto err;
		}

	return ret;
err:
	if (b == NULL && ret != NULL)
		{
		BN_BLINDING_free(ret);
		ret = NULL;
		}

	return ret;
}