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