Ejemplo n.º 1
0
/* Compute the A value as used by EdDSA.  The caller needs to provide
   the context EC and the actual secret D as an MPI.  The function
   returns a newly allocated 64 byte buffer at r_digest; the first 32
   bytes represent the A value.  NULL is returned on error and NULL
   stored at R_DIGEST.  */
gpg_err_code_t
_gcry_ecc_eddsa_compute_h_d (unsigned char **r_digest,
                             gcry_mpi_t d, mpi_ec_t ec)
{
  gpg_err_code_t rc;
  unsigned char *rawmpi = NULL;
  unsigned int rawmpilen;
  unsigned char *digest;
  gcry_buffer_t hvec[2];
  int hashalgo, b;

  *r_digest = NULL;

  hashalgo = GCRY_MD_SHA512;
  if (hashalgo != GCRY_MD_SHA512)
    return GPG_ERR_DIGEST_ALGO;

  b = (ec->nbits+7)/8;
  if (b != 256/8)
    return GPG_ERR_INTERNAL; /* We only support 256 bit. */

  /* Note that we clear DIGEST so we can use it as input to left pad
     the key with zeroes for hashing.  */
  digest = xtrycalloc_secure (2, b);
  if (!digest)
    return gpg_err_code_from_syserror ();

  memset (hvec, 0, sizeof hvec);

  rawmpi = _gcry_mpi_get_buffer (d, 0, &rawmpilen, NULL);
  if (!rawmpi)
    {
      xfree (digest);
      return gpg_err_code_from_syserror ();
    }

  hvec[0].data = digest;
  hvec[0].off = 0;
  hvec[0].len = b > rawmpilen? b - rawmpilen : 0;
  hvec[1].data = rawmpi;
  hvec[1].off = 0;
  hvec[1].len = rawmpilen;
  rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 2);
  xfree (rawmpi);
  if (rc)
    {
      xfree (digest);
      return rc;
    }

  /* Compute the A value.  */
  reverse_buffer (digest, 32);  /* Only the first half of the hash.  */
  digest[0]   = (digest[0] & 0x7f) | 0x40;
  digest[31] &= 0xf8;

  *r_digest = digest;
  return 0;
}
Ejemplo n.º 2
0
/* Encode MPI using the EdDSA scheme.  MINLEN specifies the required
   length of the buffer in bytes.  On success 0 is returned an a
   malloced buffer with the encoded point is stored at R_BUFFER; the
   length of this buffer is stored at R_BUFLEN.  */
static gpg_err_code_t
eddsa_encodempi (gcry_mpi_t mpi, unsigned int minlen,
                 unsigned char **r_buffer, unsigned int *r_buflen)
{
  unsigned char *rawmpi;
  unsigned int rawmpilen;

  rawmpi = _gcry_mpi_get_buffer (mpi, minlen, &rawmpilen, NULL);
  if (!rawmpi)
    return gpg_err_code_from_syserror ();

  *r_buffer = rawmpi;
  *r_buflen = rawmpilen;
  return 0;
}
Ejemplo n.º 3
0
/* Convert the big integer A into the external representation
   described by FORMAT and store it in the provided BUFFER which has
   been allocated by the user with a size of BUFLEN bytes.  NWRITTEN
   receives the actual length of the external representation unless it
   has been passed as NULL.  BUFFER may be NULL to query the required
   length.  */
gcry_error_t
gcry_mpi_print (enum gcry_mpi_format format,
                unsigned char *buffer, size_t buflen,
                size_t *nwritten, struct gcry_mpi *a)
{
  unsigned int nbits = mpi_get_nbits (a);
  size_t len;
  size_t dummy_nwritten;

  if (!nwritten)
    nwritten = &dummy_nwritten;

  len = buflen;
  *nwritten = 0;
  if (format == GCRYMPI_FMT_STD)
    {
      unsigned char *tmp;
      int extra = 0;
      unsigned int n;

      if (a->sign)
        return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */

      tmp = _gcry_mpi_get_buffer (a, &n, NULL);
      if (!tmp)
        return gpg_error_from_syserror ();
      if (n && (*tmp & 0x80))
        {
          n++;
          extra=1;
	}

      if (buffer && n > len)
        {
          /* The provided buffer is too short. */
          gcry_free (tmp);
          return gcry_error (GPG_ERR_TOO_SHORT);
	}
      if (buffer)
        {
          unsigned char *s = buffer;

          if (extra)
            *s++ = 0;
          memcpy (s, tmp, n-extra);
	}
      gcry_free(tmp);
      *nwritten = n;
      return 0;
    }
  else if (format == GCRYMPI_FMT_USG)
    {
      unsigned int n = (nbits + 7)/8;

      /* Note:  We ignore the sign for this format.  */
      /* FIXME: for performance reasons we should put this into
	 mpi_aprint because we can then use the buffer directly.  */
      if (buffer && n > len)
        return gcry_error (GPG_ERR_TOO_SHORT);
      if (buffer)
        {
          unsigned char *tmp;

          tmp = _gcry_mpi_get_buffer (a, &n, NULL);
          if (!tmp)
            return gpg_error_from_syserror ();
          memcpy (buffer, tmp, n);
          gcry_free (tmp);
	}
      *nwritten = n;
      return 0;
    }
  else if (format == GCRYMPI_FMT_PGP)
    {
      unsigned int n = (nbits + 7)/8;

      /* The PGP format can only handle unsigned integers.  */
      if( a->sign )
        return gcry_error (GPG_ERR_INV_ARG);

      if (buffer && n+2 > len)
        return gcry_error (GPG_ERR_TOO_SHORT);

      if (buffer)
        {
          unsigned char *tmp;
          unsigned char *s = buffer;

          s[0] = nbits >> 8;
          s[1] = nbits;

          tmp = _gcry_mpi_get_buffer (a, &n, NULL);
          if (!tmp)
            return gpg_error_from_syserror ();
          memcpy (s+2, tmp, n);
          gcry_free (tmp);
	}
      *nwritten = n+2;
      return 0;
    }
Ejemplo n.º 4
0
/* Decode the EdDSA style encoded PK and set it into RESULT.  CTX is
   the usual curve context.  If R_ENCPK is not NULL, the encoded PK is
   stored at that address; this is a new copy to be released by the
   caller.  In contrast to the supplied PK, this is not an MPI and
   thus guaranteed to be properly padded.  R_ENCPKLEN receives the
   length of that encoded key.  */
gpg_err_code_t
_gcry_ecc_eddsa_decodepoint (gcry_mpi_t pk, mpi_ec_t ctx, mpi_point_t result,
                             unsigned char **r_encpk, unsigned int *r_encpklen)
{
  gpg_err_code_t rc;
  unsigned char *rawmpi;
  unsigned int rawmpilen;
  int sign;

  if (mpi_is_opaque (pk))
    {
      const unsigned char *buf;

      buf = mpi_get_opaque (pk, &rawmpilen);
      if (!buf)
        return GPG_ERR_INV_OBJ;
      rawmpilen = (rawmpilen + 7)/8;

      /* Handle compression prefixes.  The size of the buffer will be
         odd in this case.  */
      if (rawmpilen > 1 && (rawmpilen%2))
        {
          /* First check whether the public key has been given in
             standard uncompressed format (SEC1).  No need to recover
             x in this case.  */
          if (buf[0] == 0x04)
            {
              gcry_mpi_t x, y;

              rc = _gcry_mpi_scan (&x, GCRYMPI_FMT_STD,
                                   buf+1, (rawmpilen-1)/2, NULL);
              if (rc)
                return rc;
              rc = _gcry_mpi_scan (&y, GCRYMPI_FMT_STD,
                                   buf+1+(rawmpilen-1)/2, (rawmpilen-1)/2,NULL);
              if (rc)
                {
                  mpi_free (x);
                  return rc;
                }

              if (r_encpk)
                {
                  rc = eddsa_encode_x_y (x, y, ctx->nbits/8, 0,
                                         r_encpk, r_encpklen);
                  if (rc)
                    {
                      mpi_free (x);
                      mpi_free (y);
                      return rc;
                    }
                }
              mpi_snatch (result->x, x);
              mpi_snatch (result->y, y);
              mpi_set_ui (result->z, 1);
              return 0;
            }

          /* Check whether the public key has been prefixed with a 0x40
             byte to explicitly indicate compressed format using a SEC1
             alike prefix byte.  This is a Libgcrypt extension.  */
          if (buf[0] == 0x40)
            {
              rawmpilen--;
              buf++;
            }
        }

      /* EdDSA compressed point.  */
      rawmpi = xtrymalloc (rawmpilen? rawmpilen:1);
      if (!rawmpi)
        return gpg_err_code_from_syserror ();
      memcpy (rawmpi, buf, rawmpilen);
      reverse_buffer (rawmpi, rawmpilen);
    }
  else
    {
      /* Note: Without using an opaque MPI it is not reliable possible
         to find out whether the public key has been given in
         uncompressed format.  Thus we expect native EdDSA format.  */
      rawmpi = _gcry_mpi_get_buffer (pk, ctx->nbits/8, &rawmpilen, NULL);
      if (!rawmpi)
        return gpg_err_code_from_syserror ();
    }

  if (rawmpilen)
    {
      sign = !!(rawmpi[0] & 0x80);
      rawmpi[0] &= 0x7f;
    }
  else
    sign = 0;
  _gcry_mpi_set_buffer (result->y, rawmpi, rawmpilen, 0);
  if (r_encpk)
    {
      /* Revert to little endian.  */
      if (sign && rawmpilen)
        rawmpi[0] |= 0x80;
      reverse_buffer (rawmpi, rawmpilen);
      *r_encpk = rawmpi;
      if (r_encpklen)
        *r_encpklen = rawmpilen;
    }
  else
    xfree (rawmpi);

  rc = _gcry_ecc_eddsa_recover_x (result->x, result->y, sign, ctx);
  mpi_set_ui (result->z, 1);

  return rc;
}