Reputation: 1049
Is there a public API to create a RSA structure by specifying the values of p, q and e?
I found Crypt-OpenSSL-RSA/RSA.xs doing what I want to do.
new_key_from_parametersGiven Crypt::OpenSSL::Bignum objects for n, e, and optionally d, p, and q, where p and q are the prime factors of n, e is the public exponent and d is the private exponent, create a new Crypt::OpenSSL::RSA object using these values.
But on the other hand the rsa section in the OpenSSL manual says:
applications should generally avoid using RSA structure elements directly and instead use API functions to query or modify keys
Upvotes: 0
Views: 3995
Reputation: 2012
Openssl does not offer API to gen key via p, q, yet one can create one based on math...
static int rsa_keygen_self(RSA *rsa, int bits)
{
BIGNUM *r0=NULL,*r1=NULL,*r2=NULL,*r3=NULL,*tmp;
BIGNUM local_r0,local_d,local_p;
BIGNUM *pr0,*d,*p;
int bitsp,bitsq,ok= -1,n=0;
BN_CTX *ctx=NULL;
ctx=BN_CTX_new();
if (ctx == NULL) goto err;
BN_CTX_start(ctx);
r0 = BN_CTX_get(ctx);
r1 = BN_CTX_get(ctx);
r2 = BN_CTX_get(ctx);
r3 = BN_CTX_get(ctx);
if (r3 == NULL) goto err;
bitsp=(bits+1)/2;
bitsq=bits-bitsp;
/* We need the RSA components non-NULL */
if(!rsa->n && ((rsa->n=BN_new()) == NULL)) goto err;
if(!rsa->d && ((rsa->d=BN_new()) == NULL)) goto err;
if(!rsa->e && ((rsa->e=BN_new()) == NULL)) goto err;
if(!rsa->p && ((rsa->p=BN_new()) == NULL)) goto err;
if(!rsa->q && ((rsa->q=BN_new()) == NULL)) goto err;
if(!rsa->dmp1 && ((rsa->dmp1=BN_new()) == NULL)) goto err;
if(!rsa->dmq1 && ((rsa->dmq1=BN_new()) == NULL)) goto err;
if(!rsa->iqmp && ((rsa->iqmp=BN_new()) == NULL)) goto err;
//p,q,e all from out side when creating RSA structure.
/* calculate n */
if (!BN_mul(rsa->n,rsa->p,rsa->q,ctx)) goto err;
/* calculate d */
if (!BN_sub(r1,rsa->p,BN_value_one())) goto err; /* p-1 */
if (!BN_sub(r2,rsa->q,BN_value_one())) goto err; /* q-1 */
if (!BN_mul(r0,r1,r2,ctx)) goto err; /* (p-1)(q-1) */
if (!(rsa->flags & RSA_FLAG_NO_CONSTTIME))
{
pr0 = &local_r0;
BN_with_flags(pr0, r0, BN_FLG_CONSTTIME);
}
else
pr0 = r0;
if (!BN_mod_inverse(rsa->d,rsa->e,pr0,ctx)) goto err; /* d */
/* set up d for correct BN_FLG_CONSTTIME flag */
if (!(rsa->flags & RSA_FLAG_NO_CONSTTIME))
{
d = &local_d;
BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME);
}
else
d = rsa->d;
/* calculate d mod (p-1) */
if (!BN_mod(rsa->dmp1,d,r1,ctx)) goto err;
/* calculate d mod (q-1) */
if (!BN_mod(rsa->dmq1,d,r2,ctx)) goto err;
/* calculate inverse of q mod p */
if (!(rsa->flags & RSA_FLAG_NO_CONSTTIME))
{
p = &local_p;
BN_with_flags(p, rsa->p, BN_FLG_CONSTTIME);
}
else
p = rsa->p;
if (!BN_mod_inverse(rsa->iqmp,rsa->q,p,ctx)) goto err;
ok=1;
err:
if (ok == -1)
{
//RSAerr(RSA_F_RSA_BUILTIN_KEYGEN,ERR_LIB_BN);
ok=0;
}
if (ctx != NULL)
{
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
return ok;
}
Upvotes: 2
Reputation: 38821
The statement about "use API" is aspirational at this time. The RSA module is one of the oldest in OpenSSL and dates to the time it was SSLeay and Eric cared about other things more than information hiding. Newer modules like ECC SHA AES EVP, and even somewhat reworked ones like BN BIO SSL, have APIs that almost always remain opaque, but RSA doesn't. Now that the project actually has developers plural, some of this old stuff may get cleaned up.
Semantically your combination is inconsistent. An RSA
structure used as a public key must have n and e, and should not have p q or any other private info;
one used as a private key must have n d p q dp dq qinv and probably e. (e isn't used for privatekey operations,
but it is required to check a keypair or write it out or read it back.) If you really have p q e you must compute n,
and if you want a private key you must also compute d (then) dp dq qinv. See PKCS#1 aka https://www.rfc-editor.org/rfc/rfc3447 and once you have the correct BN
values for now just stuff them in rsa->whatever
.
Upvotes: 2