Ejemplo n.º 1
0
char *ssh_gcry_bn2dec(bignum bn) {
  bignum bndup, num, ten;
  char *ret;
  int count, count2;
  int size, rsize;
  char decnum;

  size = gcry_mpi_get_nbits(bn) * 3;
  rsize = size / 10 + size / 1000 + 2;

  ret = malloc(rsize + 1);
  if (ret == NULL) {
    return NULL;
  }

  if (!gcry_mpi_cmp_ui(bn, 0)) {
    strcpy(ret, "0");
  } else {
    ten = bignum_new();
    if (ten == NULL) {
      SAFE_FREE(ret);
      return NULL;
    }

    num = bignum_new();
    if (num == NULL) {
      SAFE_FREE(ret);
      bignum_safe_free(ten);
      return NULL;
    }

    for (bndup = gcry_mpi_copy(bn), bignum_set_word(ten, 10), count = rsize;
        count; count--) {
      gcry_mpi_div(bndup, num, bndup, ten, 0);
      for (decnum = 0, count2 = gcry_mpi_get_nbits(num); count2;
          decnum *= 2, decnum += (gcry_mpi_test_bit(num, count2 - 1) ? 1 : 0),
          count2--)
        ;
      ret[count - 1] = decnum + '0';
    }
    for (count = 0; count < rsize && ret[count] == '0'; count++)
      ;
    for (count2 = 0; count2 < rsize - count; ++count2) {
      ret[count2] = ret[count2 + count];
    }
    ret[count2] = 0;
    bignum_safe_free(num);
    bignum_safe_free(bndup);
    bignum_safe_free(ten);
  }

  return ret;
}
Ejemplo n.º 2
0
Archivo: kex.c Proyecto: gpg/gsti
static gcry_mpi_t
calc_dh_key (gcry_mpi_t gex_p, gcry_mpi_t f, gcry_mpi_t x)
{
  gcry_mpi_t k, prime;
  size_t n = sizeof diffie_hellman_group1_prime;

  if (gex_p)
      prime = gcry_mpi_copy (gex_p);
  else if (gcry_mpi_scan (&prime, GCRYMPI_FMT_STD,
                          diffie_hellman_group1_prime, n, NULL))
    abort ();

  n = gcry_mpi_get_nbits (prime);
  k = gcry_mpi_snew (n+1);
  gcry_mpi_powm (k, f, x, prime);
  gcry_mpi_release (prime);
  return k;
}
Ejemplo n.º 3
0
Archivo: kex.c Proyecto: gpg/gsti
static gsti_error_t
check_dh_mpi_range (gcry_mpi_t gex_p, gcry_mpi_t chk)
{
  gsti_error_t err = 0;
  gcry_mpi_t p;

  /* A value which is not in the range [1, p-1] is considered as a
     protocol violation.  */
  if (gex_p)
      p = gcry_mpi_copy (gex_p);
  else if (gcry_mpi_scan (&p, GCRYMPI_FMT_STD, diffie_hellman_group1_prime,
                          sizeof diffie_hellman_group1_prime, NULL))
#warning why abort?
    abort ();
  if (gcry_mpi_cmp (chk, p) > 0 || gcry_mpi_get_nbits (chk) < 2)
    err = gsti_error (GPG_ERR_PROTOCOL_VIOLATION);
  gcry_mpi_release (p);
  
  return err;
}
Ejemplo n.º 4
0
void serialize_mpi(char *outbuf, int outlen, enum disp_format df, 
		   const gcry_mpi_t x)
{
  switch(df) {
  case DF_BIN: do {
      int len = (gcry_mpi_get_nbits(x) + 7) / 8;
      assert(len <= outlen);
      memset(outbuf, 0, outlen - len);
      gcry_mpi_print(GCRYMPI_FMT_USG, (unsigned char*)outbuf + (outlen - len), 
		     len, NULL, x);
    } while (0);
    break;
    
  case DF_COMPACT:
  case DF_BASE36: do {
    const char *digits = get_digits(df);
    unsigned int digit_count = get_digit_count(df);
    gcry_mpi_t base, Q, R;
    int i;
    base = gcry_mpi_set_ui(NULL, digit_count);
    Q = gcry_mpi_copy(x);
    R = gcry_mpi_snew(0);
    for(i = outlen - 1; i >= 0; i--) {
        unsigned char digit = 0;
        gcry_mpi_div(Q, R, Q, base, 0);        
        gcry_mpi_print(GCRYMPI_FMT_USG, &digit, 1, NULL, R);
        assert(digit < digit_count);
        outbuf[i] = digits[digit];
    }    
    assert(! gcry_mpi_cmp_ui(Q, 0));
    gcry_mpi_release(base);
    gcry_mpi_release(Q);
    gcry_mpi_release(R);
    } while(0);
    break;
  default: 
    assert(0);
  }
}
Ejemplo n.º 5
0
/* Rotate in a new DH public key for our correspondent.  Be sure to keep
 * the sesskeys array in sync. */
static gcry_error_t rotate_y_keys(ConnContext *context, gcry_mpi_t new_y)
{
    gcry_error_t err;

    /* Rotate the public key */
    gcry_mpi_release(context->context_priv->their_old_y);
    context->context_priv->their_old_y = context->context_priv->their_y;

    /* Rotate the session keys */
    err = reveal_macs(context, &(context->context_priv->sesskeys[0][1]),
	    &(context->context_priv->sesskeys[1][1]));
    if (err) return err;
    otrl_dh_session_free(&(context->context_priv->sesskeys[0][1]));
    otrl_dh_session_free(&(context->context_priv->sesskeys[1][1]));
    memmove(&(context->context_priv->sesskeys[0][1]),
	    &(context->context_priv->sesskeys[0][0]),
	    sizeof(DH_sesskeys));
    memmove(&(context->context_priv->sesskeys[1][1]),
	    &(context->context_priv->sesskeys[1][0]),
	    sizeof(DH_sesskeys));

    /* Copy in the new public key */
    context->context_priv->their_y = gcry_mpi_copy(new_y);
    context->context_priv->their_keyid++;

    /* Make the session keys */
    err = otrl_dh_session(&(context->context_priv->sesskeys[0][0]),
	    &(context->context_priv->our_dh_key),
	    context->context_priv->their_y);
    if (err) return err;
    err = otrl_dh_session(&(context->context_priv->sesskeys[1][0]),
	    &(context->context_priv->our_old_dh_key),
	    context->context_priv->their_y);
    if (err) return err;

    return gcry_error(GPG_ERR_NO_ERROR);
}
Ejemplo n.º 6
0
cdk_error_t
_cdk_copy_pubkey (cdk_pkt_pubkey_t* dst, cdk_pkt_pubkey_t src)
{
  cdk_pkt_pubkey_t k;
  int i;
  
  if (!dst || !src)
    return CDK_Inv_Value;
  
  *dst = NULL;
  k = cdk_calloc (1, sizeof *k);
  if (!k)
    return CDK_Out_Of_Core;
  memcpy (k, src, sizeof *k);
  if (src->uid)
    _cdk_copy_userid (&k->uid, src->uid);
  if (src->prefs)
    k->prefs = _cdk_copy_prefs (src->prefs);
  for (i = 0; i < cdk_pk_get_npkey (src->pubkey_algo); i++)
    k->mpi[i] = gcry_mpi_copy (src->mpi[i]);
  *dst = k;
  
  return 0;
}
Ejemplo n.º 7
0
int get_serialization_len(const gcry_mpi_t x, enum disp_format df)
{
  int res;
  switch(df) {
  case DF_BIN:
    res = (gcry_mpi_get_nbits(x) + 7) / 8;
    break;
  case DF_BASE36:
  case DF_COMPACT:  
    do {
      gcry_mpi_t base, Q;
      base = gcry_mpi_set_ui(NULL, get_digit_count(df));
      Q = gcry_mpi_copy(x);
      for(res = 0; gcry_mpi_cmp_ui(Q, 0); res++)
	gcry_mpi_div(Q, NULL, Q, base, 0);
      gcry_mpi_release(base);
      gcry_mpi_release(Q);
    } while (0);
    break;
  default:
    assert(0);
  }
  return res;
}
Ejemplo n.º 8
0
/* Generate a key pair with a key of size NBITS not using a random
   value for the secret key but the one given as X.  This is useful to
   implement a passphrase based decryption for a public key based
   encryption.  It has appliactions in backup systems.
 
   Returns: A structure filled with all needed values and an array
 	    with n-1 factors of (p-1).  */
static gcry_err_code_t
generate_using_x (ELG_secret_key *sk, unsigned int nbits, gcry_mpi_t x,
                  gcry_mpi_t **ret_factors )
{
  gcry_mpi_t p;      /* The prime.  */
  gcry_mpi_t p_min1; /* The prime minus 1.  */
  gcry_mpi_t g;      /* The generator.  */
  gcry_mpi_t y;      /* g^x mod p.  */
  unsigned int qbits;
  unsigned int xbits;

  sk->p = NULL;
  sk->g = NULL;
  sk->y = NULL;
  sk->x = NULL;

  /* Do a quick check to see whether X is suitable.  */
  xbits = mpi_get_nbits (x);
  if ( xbits < 64 || xbits >= nbits )
    return GPG_ERR_INV_VALUE;

  p_min1 = gcry_mpi_new ( nbits );
  qbits  = wiener_map ( nbits );
  if ( (qbits & 1) ) /* Better have an even one.  */
    qbits++;
  g = mpi_alloc (1);
  p = _gcry_generate_elg_prime ( 0, nbits, qbits, g, ret_factors );
  mpi_sub_ui (p_min1, p, 1);

  if (DBG_CIPHER)
    log_debug ("using a supplied x of size %u", xbits );
  if ( !(mpi_cmp_ui ( x, 0 ) > 0 && mpi_cmp ( x, p_min1 ) <0 ) )
    {
      gcry_mpi_release ( p_min1 );
      gcry_mpi_release ( p );
      gcry_mpi_release ( g );
      return GPG_ERR_INV_VALUE;
    }

  y = gcry_mpi_new (nbits);
  gcry_mpi_powm ( y, g, x, p );

  if ( DBG_CIPHER ) 
    {
      progress ('\n');
      log_mpidump ("elg  p= ", p );
      log_mpidump ("elg  g= ", g );
      log_mpidump ("elg  y= ", y );
      log_mpidump ("elg  x= ", x );
    }

  /* Copy the stuff to the key structures */
  sk->p = p;
  sk->g = g;
  sk->y = y;
  sk->x = gcry_mpi_copy (x);

  gcry_mpi_release ( p_min1 );

  /* Now we can test our keys. */
  if ( test_keys ( sk, nbits - 64, 1 ) )
    {
      gcry_mpi_release ( sk->p ); sk->p = NULL;
      gcry_mpi_release ( sk->g ); sk->g = NULL;
      gcry_mpi_release ( sk->y ); sk->y = NULL;
      gcry_mpi_release ( sk->x ); sk->x = NULL;
      return GPG_ERR_BAD_SECKEY;
    }

  return 0;
}
Ejemplo n.º 9
0
/* Find a generator for PRIME where the factorization of (prime-1) is
   in the NULL terminated array FACTORS. Return the generator as a
   newly allocated MPI in R_G.  If START_G is not NULL, use this as s
   atart for the search. Returns 0 on success.*/
gcry_error_t
gcry_prime_group_generator (gcry_mpi_t *r_g,
                            gcry_mpi_t prime, gcry_mpi_t *factors,
                            gcry_mpi_t start_g)
{
  gcry_mpi_t tmp = gcry_mpi_new (0);
  gcry_mpi_t b = gcry_mpi_new (0);
  gcry_mpi_t pmin1 = gcry_mpi_new (0);
  gcry_mpi_t g = start_g? gcry_mpi_copy (start_g) : gcry_mpi_set_ui (NULL, 3);
  int first = 1;
  int i, n;

  if (!factors || !r_g || !prime)
    return gpg_error (GPG_ERR_INV_ARG);
  *r_g = NULL; 

  for (n=0; factors[n]; n++)
    ;
  if (n < 2)
    return gpg_error (GPG_ERR_INV_ARG);

  /* Extra sanity check - usually disabled. */  
/*   mpi_set (tmp, factors[0]); */
/*   for(i = 1; i < n; i++) */
/*     mpi_mul (tmp, tmp, factors[i]); */
/*   mpi_add_ui (tmp, tmp, 1); */
/*   if (mpi_cmp (prime, tmp)) */
/*     return gpg_error (GPG_ERR_INV_ARG); */
  
  gcry_mpi_sub_ui (pmin1, prime, 1);      
  do         
    {
      if (first)
        first = 0;
      else
        gcry_mpi_add_ui (g, g, 1);
      
      if (DBG_CIPHER)
        {
          log_debug ("checking g:");
          gcry_mpi_dump (g);
          log_debug ("\n");
        }
      else
        progress('^');
      
      for (i = 0; i < n; i++)
        {
          mpi_fdiv_q (tmp, pmin1, factors[i]);
          gcry_mpi_powm (b, g, tmp, prime);
          if (! mpi_cmp_ui (b, 1))
            break;
        }
      if (DBG_CIPHER)
        progress('\n');
    }
  while (i < n);
  
  gcry_mpi_release (tmp);
  gcry_mpi_release (b); 
  gcry_mpi_release (pmin1); 
  *r_g = g; 

  return 0; 
}
Ejemplo n.º 10
0
/* Check that left shifting works correctly.  */
static void
test_lshift (int pass)
{
  static int size_list[] = {1, 31, 32, 63, 64, 65, 70, 0};
  int size_idx;
  gcry_mpi_t a, b;
  char *tmpstr, *result, *result2;
  int i;

  wherestr = "test_lshift";
  show ("checking that lshift works as expected (pass %d)\n", pass);

  for (size_idx=0; size_list[size_idx]; size_idx++)
    {
      a = gcry_mpi_new (0);
      b = gcry_mpi_new (0);

      /* gcry_mpi_randomize rounds up to full bytes, thus we need to
         use gcry_mpi_clear_highbit to fix that.  */
      gcry_mpi_randomize (a, size_list[size_idx], GCRY_WEAK_RANDOM);
      gcry_mpi_clear_highbit (a, size_list[size_idx]);

      for (i=0; i < 75; i++)
        {
          gcry_mpi_lshift (b, a, i);
          
          result = mpi2bitstr_nlz (b);
          tmpstr = mpi2bitstr_nlz (a);
          result2 = lshiftbitstring (tmpstr, i);
          xfree (tmpstr);
          if (strcmp (result, result2))
            {
              show ("got =%s\n", result);
              show ("want=%s\n", result2);
              fail ("lshift by %d failed\n", i);
            }
          xfree (result);
          xfree (result2);
        }
      
      /* Again. This time using in-place operation. */
      gcry_mpi_randomize (a, size_list[size_idx], GCRY_WEAK_RANDOM);
      gcry_mpi_clear_highbit (a, size_list[size_idx]);
      
      for (i=0; i < 75; i++)
        {
          gcry_mpi_release (b);
          b = gcry_mpi_copy (a);
          gcry_mpi_lshift (b, b, i);

          result = mpi2bitstr_nlz (b);
          tmpstr = mpi2bitstr_nlz (a);
          result2 = lshiftbitstring (tmpstr, i);
          xfree (tmpstr);
          if (strcmp (result, result2))
            {
              show ("got =%s\n", result);
              show ("want=%s\n", result2);
              fail ("in-place lshift by %d failed\n", i);
            }
          xfree (result2);
          xfree (result);
        }

      gcry_mpi_release (b);
      gcry_mpi_release (a);
    }
}
Ejemplo n.º 11
0
static int
test_const_and_immutable (void)
{
  gcry_mpi_t one, second_one;

  one = gcry_mpi_set_ui (NULL, 1);
  if (gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE)
      || gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST))
    die ("immutable or const flag initially set\n");

  second_one = gcry_mpi_copy (one);
  if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_IMMUTABLE))
    die ("immutable flag set after copy\n");
  if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_CONST))
    die ("const flag set after copy\n");
  gcry_mpi_release (second_one);

  gcry_mpi_set_flag (one, GCRYMPI_FLAG_IMMUTABLE);
  if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE))
    die ("failed to set immutable flag\n");
  if (gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST))
    die ("const flag unexpectly set\n");

  second_one = gcry_mpi_copy (one);
  if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_IMMUTABLE))
    die ("immutable flag not cleared after copy\n");
  if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_CONST))
    die ("const flag unexpectly set after copy\n");
  gcry_mpi_release (second_one);

  gcry_mpi_clear_flag (one, GCRYMPI_FLAG_IMMUTABLE);
  if (gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE))
    die ("failed to clear immutable flag\n");
  if (gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST))
    die ("const flag unexpectly set\n");

  gcry_mpi_set_flag (one, GCRYMPI_FLAG_CONST);
  if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST))
    die ("failed to set const flag\n");
  if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE))
    die ("failed to set immutable flag with const flag\n");

  second_one = gcry_mpi_copy (one);
  if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_IMMUTABLE))
    die ("immutable flag not cleared after copy\n");
  if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_CONST))
    die ("const flag not cleared after copy\n");
  gcry_mpi_release (second_one);

  gcry_mpi_clear_flag (one, GCRYMPI_FLAG_IMMUTABLE);
  if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE))
    die ("clearing immutable flag not ignored for a constant MPI\n");
  if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST))
    die ("const flag unexpectly cleared\n");


  second_one = gcry_mpi_set (NULL, GCRYMPI_CONST_ONE);
  if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_IMMUTABLE))
    die ("immutable flag not cleared by mpi_set (NULL,x)\n");
  if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_CONST))
    die ("const flag not cleared by mpi_set (NULL,x)\n");
  gcry_mpi_release (second_one);

  second_one = gcry_mpi_set_ui (NULL, 42);
  gcry_mpi_set (second_one, GCRYMPI_CONST_ONE);
  if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_IMMUTABLE))
    die ("immutable flag not cleared after mpi_set (a,x)\n");
  if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_CONST))
    die ("const flag not cleared mpi_set (a,x)\n");
  gcry_mpi_release (second_one);


  /* Due to the the constant flag the release below should be a NOP
     and will leak memory.  */
  gcry_mpi_release (one);
  return 1;
}
Ejemplo n.º 12
0
/* Check that the RSA secret key SKEY is valid.  Swap parameters to
   the libgcrypt standard.  */
static gpg_error_t
rsa_key_check (struct rsa_secret_key_s *skey)
{
  int err = 0;
  gcry_mpi_t t = gcry_mpi_snew (0);
  gcry_mpi_t t1 = gcry_mpi_snew (0);
  gcry_mpi_t t2 = gcry_mpi_snew (0);
  gcry_mpi_t phi = gcry_mpi_snew (0);

  /* Check that n == p * q.  */
  gcry_mpi_mul (t, skey->p, skey->q);
  if (gcry_mpi_cmp( t, skey->n) )
    {
      log_error ("RSA oops: n != p * q\n");
      err++;
    }

  /* Check that p is less than q.  */
  if (gcry_mpi_cmp (skey->p, skey->q) > 0)
    {
      gcry_mpi_t tmp;

      log_info ("swapping secret primes\n");
      tmp = gcry_mpi_copy (skey->p);
      gcry_mpi_set (skey->p, skey->q);
      gcry_mpi_set (skey->q, tmp);
      gcry_mpi_release (tmp);
      /* Recompute u.  */
      gcry_mpi_invm (skey->u, skey->p, skey->q);
    }

  /* Check that e divides neither p-1 nor q-1.  */
  gcry_mpi_sub_ui (t, skey->p, 1 );
  gcry_mpi_div (NULL, t, t, skey->e, 0);
  if (!gcry_mpi_cmp_ui( t, 0) )
    {
      log_error ("RSA oops: e divides p-1\n");
      err++;
    }
  gcry_mpi_sub_ui (t, skey->q, 1);
  gcry_mpi_div (NULL, t, t, skey->e, 0);
  if (!gcry_mpi_cmp_ui( t, 0))
    {
      log_info ("RSA oops: e divides q-1\n" );
      err++;
    }

  /* Check that d is correct.  */
  gcry_mpi_sub_ui (t1, skey->p, 1);
  gcry_mpi_sub_ui (t2, skey->q, 1);
  gcry_mpi_mul (phi, t1, t2);
  gcry_mpi_invm (t, skey->e, phi);
  if (gcry_mpi_cmp (t, skey->d))
    {
      /* No: try universal exponent. */
      gcry_mpi_gcd (t, t1, t2);
      gcry_mpi_div (t, NULL, phi, t, 0);
      gcry_mpi_invm (t, skey->e, t);
      if (gcry_mpi_cmp (t, skey->d))
        {
          log_error ("RSA oops: bad secret exponent\n");
          err++;
        }
    }

  /* Check for correctness of u.  */
  gcry_mpi_invm (t, skey->p, skey->q);
  if (gcry_mpi_cmp (t, skey->u))
    {
      log_info ("RSA oops: bad u parameter\n");
      err++;
    }

  if (err)
    log_info ("RSA secret key check failed\n");

  gcry_mpi_release (t);
  gcry_mpi_release (t1);
  gcry_mpi_release (t2);
  gcry_mpi_release (phi);

  return err? gpg_error (GPG_ERR_BAD_SECKEY):0;
}
Ejemplo n.º 13
0
/*
 * Test iterative X25519 computation through lower layer MPI routines.
 *
 * Input: K (as hex string), ITER, R (as hex string)
 *
 * where R is expected result of iterating X25519 by ITER times.
 *
 */
static void
test_it (int testno, const char *k_str, int iter, const char *result_str)
{
  gcry_ctx_t ctx;
  gpg_error_t err;
  void *buffer = NULL;
  size_t buflen;
  gcry_mpi_t mpi_k = NULL;
  gcry_mpi_t mpi_x = NULL;
  gcry_mpi_point_t P = NULL;
  gcry_mpi_point_t Q;
  int i;
  gcry_mpi_t mpi_kk = NULL;

  if (verbose > 1)
    info ("Running test %d: iteration=%d\n", testno, iter);

  gcry_mpi_ec_new (&ctx, NULL, "Curve25519");
  Q = gcry_mpi_point_new (0);

  if (!(buffer = hex2buffer (k_str, &buflen)) || buflen != 32)
    {
      fail ("error scanning MPI for test %d, %s: %s",
            testno, "k", "invalid hex string");
      goto leave;
    }
  reverse_buffer (buffer, buflen);
  if ((err = gcry_mpi_scan (&mpi_x, GCRYMPI_FMT_USG, buffer, buflen, NULL)))
    {
      fail ("error scanning MPI for test %d, %s: %s",
            testno, "x", gpg_strerror (err));
      goto leave;
    }

  xfree (buffer);
  buffer = NULL;

  P = gcry_mpi_point_set (NULL, mpi_x, NULL, GCRYMPI_CONST_ONE);

  mpi_k = gcry_mpi_copy (mpi_x);
  if (debug)
    print_mpi ("k", mpi_k);

  for (i = 0; i < iter; i++)
    {
      /*
       * Another variant of decodeScalar25519 thing.
       */
      mpi_kk = gcry_mpi_set (mpi_kk, mpi_k);
      gcry_mpi_set_bit (mpi_kk, 254);
      gcry_mpi_clear_bit (mpi_kk, 255);
      gcry_mpi_clear_bit (mpi_kk, 0);
      gcry_mpi_clear_bit (mpi_kk, 1);
      gcry_mpi_clear_bit (mpi_kk, 2);

      gcry_mpi_ec_mul (Q, mpi_kk, P, ctx);

      P = gcry_mpi_point_set (P, mpi_k, NULL, GCRYMPI_CONST_ONE);
      gcry_mpi_ec_get_affine (mpi_k, NULL, Q, ctx);

      if (debug)
        print_mpi ("k", mpi_k);
    }

  {
    unsigned char res[32];
    char *r, *r0;

    gcry_mpi_print (GCRYMPI_FMT_USG, res, 32, NULL, mpi_k);
    reverse_buffer (res, 32);

    r0 = r = xmalloc (65);
    if (!r0)
      {
        fail ("memory allocation for test %d", testno);
        goto leave;
      }

    for (i=0; i < 32; i++, r += 2)
      snprintf (r, 3, "%02x", res[i]);

    if (strcmp (result_str, r0))
      {
        fail ("curv25519 failed for test %d: %s",
              testno, "wrong value returned");
        info ("  expected: '%s'", result_str);
        info ("       got: '%s'", r0);
      }
    xfree (r0);
  }

 leave:
  gcry_mpi_release (mpi_kk);
  gcry_mpi_release (mpi_k);
  gcry_mpi_point_release (P);
  gcry_mpi_release (mpi_x);
  xfree (buffer);
  gcry_mpi_point_release (Q);
  gcry_ctx_release (ctx);
}