How to use the function mpi_fromstr?
Werner Koch
wk at gnupg.org
Thu Oct 14 15:20:01 CEST 2004
On Thu, 14 Oct 2004 13:19:24 +0000, Michel Thrysøe said:
> Can the function mpi_fromstr found in mpicoder.c can somehow be used
> to generate an mpi from a public in clear text produced by the --armor
No. This is just string to binary MPI and not generally useful.
To parse the key you need to take the code from
parse-packet.c:parse_key. You may also want to look at the code below
(from gnupg 1.9) which parses a key in memory to compute the
fingerprint.
Werner
/* Parse a key packet and store the information in KI. */
static gpg_error_t
parse_key (const unsigned char *data, size_t datalen,
struct _keybox_openpgp_key_info *ki)
{
gpg_error_t err;
const unsigned char *data_start = data;
int i, version, algorithm;
size_t n;
unsigned long timestamp, expiredate;
int npkey;
unsigned char hashbuffer[768];
const unsigned char *mpi_n = NULL;
size_t mpi_n_len = 0, mpi_e_len = 0;
gcry_md_hd_t md;
if (datalen < 5)
return gpg_error (GPG_ERR_INV_PACKET);
version = *data++; datalen--;
if (version < 2 || version > 4 )
return gpg_error (GPG_ERR_INV_PACKET); /* Invalid version. */
timestamp = ((data[0]<<24)|(data[1]<<16)|(data[2]<<8)|(data[3]));
data +=4; datalen -=4;
if (version < 4)
{
unsigned short ndays;
if (datalen < 2)
return gpg_error (GPG_ERR_INV_PACKET);
ndays = ((data[0]<<8)|(data[1]));
data +=2; datalen -= 2;
if (ndays)
expiredate = ndays? (timestamp + ndays * 86400L) : 0;
}
else
expiredate = 0; /* This is stored in the self-signature. */
if (!datalen)
return gpg_error (GPG_ERR_INV_PACKET);
algorithm = *data++; datalen--;
switch (algorithm)
{
case 1:
case 2:
case 3: /* RSA */
npkey = 2;
break;
case 16:
case 20: /* Elgamal */
npkey = 3;
break;
case 17: /* DSA */
npkey = 4;
break;
default: /* Unknown algorithm. */
return gpg_error (GPG_ERR_UNKNOWN_ALGORITHM);
}
for (i=0; i < npkey; i++ )
{
unsigned int nbits, nbytes;
if (datalen < 2)
return gpg_error (GPG_ERR_INV_PACKET);
nbits = ((data[0]<<8)|(data[1]));
data += 2; datalen -=2;
nbytes = (nbits+7) / 8;
if (datalen < nbytes)
return gpg_error (GPG_ERR_INV_PACKET);
/* For use by v3 fingerprint calculation we need to know the RSA
modulus and exponent. */
if (i==0)
{
mpi_n = data;
mpi_n_len = nbytes;
}
else if (i==1)
mpi_e_len = nbytes;
data += nbytes; datalen -= nbytes;
}
n = data - data_start;
if (version < 4)
{
/* We do not support any other algorithm than RSA in v3
packets. */
if (algorithm < 1 || algorithm > 3)
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
err = gcry_md_open (&md, GCRY_MD_MD5, 0);
if (err)
return err; /* Oops */
gcry_md_write (md, mpi_n, mpi_n_len);
gcry_md_write (md, mpi_n+mpi_n_len+2, mpi_e_len);
memcpy (ki->fpr, gcry_md_read (md, 0), 16);
gcry_md_close (md);
ki->fprlen = 16;
if (mpi_n_len < 8)
{
/* Moduli less than 64 bit are out of the specs scope. Zero
them out becuase this is what gpg does too. */
memset (ki->keyid, 0, 8);
}
else
memcpy (ki->keyid, mpi_n + mpi_n_len - 8, 8);
}
else
{
/* Its a pitty that we need to prefix the buffer with the tag
and a length header: We can't simply pass it to the fast
hashing function for that reason. It might be a good idea to
have a scatter-gather enabled hash function. What we do here
is to use a static buffer if this one is large enough and
only use the regular hash fucntions if this buffer is not
large enough. */
if ( 3 + n < sizeof hashbuffer )
{
hashbuffer[0] = 0x99; /* CTB */
hashbuffer[1] = (n >> 8); /* 2 byte length header. */
hashbuffer[2] = n;
memcpy (hashbuffer + 3, data_start, n);
gcry_md_hash_buffer (GCRY_MD_SHA1, ki->fpr, hashbuffer, 3 + n);
}
else
{
err = gcry_md_open (&md, GCRY_MD_SHA1, 0);
if (err)
return err; /* Oops */
gcry_md_putc (md, 0x99 ); /* CTB */
gcry_md_putc (md, (n >> 8) ); /* 2 byte length header. */
gcry_md_putc (md, n );
gcry_md_write (md, data_start, n);
memcpy (ki->fpr, gcry_md_read (md, 0), 20);
gcry_md_close (md);
}
ki->fprlen = 20;
memcpy (ki->keyid, ki->fpr+12, 8);
}
return 0;
}
More information about the Gnupg-devel
mailing list