What is the c method for the following open ssl command that only extracts the modulus
Short answer... Given an RSA
structure:
RSA* rsa = ...;
BIGNUM* n = rsa->n;
Then, use BN_print_fp
:
BN_print_fp(stdout, n);
Or, use BN_bn2dec
:
fprintf(stdout, "%s", BN_bn2dec(n));
Or, use ASN1_bn_print
:
int ASN1_bn_print(BIO *bp, const char *number, const BIGNUM *num,
unsigned char *buf, int off)
ASN1_bn_print
is from the long answer below, and it gives you the formatting you showed in your example.
Long answer... I believe the key is printed with RSA_print_fp
, and it ultimately ends with calls to ASN1_bn_print
for the various RSA parameters. Here's part of the trail:
$ grep -R RSA_print_fp *
crypto/rsa/rsa.h:int RSA_print_fp(FILE *fp, const RSA *r,int offset);
crypto/rsa/rsa_err.c:{ERR_FUNC(RSA_F_RSA_PRINT_FP), "RSA_print_fp"},
crypto/rsa/rsa_prn.c:int RSA_print_fp(FILE *fp, const RSA *x, int off)
...
Following RSA_print_fp
:
int RSA_print_fp(FILE *fp, const RSA *x, int off)
{
BIO *b;
int ret;
if ((b=BIO_new(BIO_s_file())) == NULL)
{
RSAerr(RSA_F_RSA_PRINT_FP,ERR_R_BUF_LIB);
return(0);
}
BIO_set_fp(b,fp,BIO_NOCLOSE);
ret=RSA_print(b,x,off);
BIO_free(b);
return(ret);
}
And RSA_print
:
int RSA_print(BIO *bp, const RSA *x, int off)
{
EVP_PKEY *pk;
int ret;
pk = EVP_PKEY_new();
if (!pk || !EVP_PKEY_set1_RSA(pk, (RSA *)x))
return 0;
ret = EVP_PKEY_print_private(bp, pk, off, NULL);
EVP_PKEY_free(pk);
return ret;
}
EVP_PKEY_print_private
is in crypto/evp/p_lib.c
:
int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey,
int indent, ASN1_PCTX *pctx)
{
if (pkey->ameth && pkey->ameth->priv_print)
return pkey->ameth->priv_print(out, pkey, indent, pctx);
return unsup_alg(out, pkey, indent, "Private Key");
}
Once in the "methods", don't follow RSA_get_default_method
. Rather, find priv_print
:
$ grep -R priv_print * | grep -i RSA
crypto/rsa/rsa_ameth.c:static int rsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
crypto/rsa/rsa_ameth.c: rsa_priv_print,
And rsa_priv_print
:
static int rsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
ASN1_PCTX *ctx)
{
return do_rsa_print(bp, pkey->pkey.rsa, indent, 1);
}
Next, do_rsa_print
:
static int do_rsa_print(BIO *bp, const RSA *x, int off, int priv)
{
...
str = "Modulus:";
s = "Exponent:";
if (!ASN1_bn_print(bp,str,x->n,m,off)) goto err;
if (!ASN1_bn_print(bp,s,x->e,m,off)) goto err;
if (priv)
{
if (!ASN1_bn_print(bp,"privateExponent:",x->d,m,off))
goto err;
if (!ASN1_bn_print(bp,"prime1:",x->p,m,off))
goto err;
if (!ASN1_bn_print(bp,"prime2:",x->q,m,off))
goto err;
if (!ASN1_bn_print(bp,"exponent1:",x->dmp1,m,off))
goto err;
if (!ASN1_bn_print(bp,"exponent2:",x->dmq1,m,off))
goto err;
if (!ASN1_bn_print(bp,"coefficient:",x->iqmp,m,off))
goto err;
}
...
}
I'll leave the final ASN1_bn_print
trace to the reader. It adds the colons (:
) and line breaks (\n
). You can find it in crypto/asn1/t_pkey.c
.
Here's how you would use ASN1_bn_print
:
RSA* rsa = RSA_new();
...
BIO* bio = BIO_new_fp(stdout, BIO_NOCLOSE);
...
int req = BN_num_bytes(rsa->n) + 4;
ptr = OPENSSL_malloc(req);
rc = ASN1_bn_print(bio, "Modulus:", rsa->n, ptr, 0);
ASSERT(rc == 1);
...
Running a program like above will produce:
$ ./test-openssl.exe
Modulus:
00:bb:bb:cf:ac:58:a9:25:2c:08:37:4d:4d:1d:0c:
5b:7d:a7:ba:de:7b:31:9a:5e:40:61:1f:6d:de:f9:
b4:48:15:a3:8c:2a:12:a9:10:fb:66:12:a4:3f:9c:
0d:7f:80:94:b1:63:91:05:96:f0:48:e5:7d:76:8a:
d0:26:dc:54:43