/*
  File: t-dh.c

  Authors:
        Tero T Mononen <tmo@ssh.fi>

  Description:


  Copyright:
        Copyright (c) 2000 SSH Communications Security, Finland
        All rights reserved
*/

#include "sshincludes.h"
#include "sshcrypt.h"
#include "sshtimemeasure.h"

typedef struct SshDHGrpRec
{
  char *type;
  char *name;
  int str;
} *SshDHGrp;

static struct SshDHGrpRec group_descr[5] =
{
  { "dl-modp", "ietf-ike-grp-modp-768", 0x42 },
  { "dl-modp", "ietf-ike-grp-modp-1024", 0x4d},
  { "dl-modp", "ietf-ike-grp-modp-1536", 0x5b },
  { "ec-gf2n", "ietf-ike-grp-ec2n-155", 0x4c },
  { "ec-gf2n", "ietf-ike-grp-ec2n-185", 0x5b }
};

int main (int ac, char **av)
{
  int i, j;
  SshDHGrp group;
  SshPkGroup g;

  for (j = 0; j < 5; j++)
    {
      SshPkGroupDHSecret secret;
      unsigned char *agreed, *exchange;
      size_t alen, elen, rlen;
      struct SshTimeMeasureRec tmit = SSH_TIME_MEASURE_INITIALIZER;
      SshUInt32 usecs;
      SshCryptoStatus cret;

      group = &group_descr[j];

      if (!strcmp(group->type, "dl-modp"))
        cret =
          ssh_pk_group_generate(&g,
                                group->type,
                                SSH_PKF_PREDEFINED_GROUP, group->name,
                                SSH_PKF_DH, "plain",
                                SSH_PKF_RANDOMIZER_ENTROPY, group->str * 3,
                                SSH_PKF_END);
      else
        cret =
          ssh_pk_group_generate(&g,
                                group->type,
                                SSH_PKF_PREDEFINED_GROUP, group->name,
                                SSH_PKF_DH, "plain",
                                SSH_PKF_END);

      if (cret != SSH_CRYPTO_OK)
        ssh_fatal("setting up group %s", group->name);

      elen = ssh_pk_group_diffie_hellman_setup_max_output_length(g);
      if (elen == 0)
        ssh_fatal("group can not do diffie hellman", group->name);
      else
        exchange = ssh_xmalloc(elen);

      alen = ssh_pk_group_diffie_hellman_agree_max_output_length(g);
      if (alen == 0)
        ssh_fatal("group can not do diffie hellman", group->name);
      else
        agreed = ssh_xmalloc(alen);

      ssh_time_measure_reset(&tmit);
      ssh_time_measure_start(&tmit);
      for (i = 0; i < 25; i++)
        {

          if (ssh_pk_group_diffie_hellman_setup(g, &secret,
                                                exchange, elen, &rlen)
              != SSH_CRYPTO_OK)
            ssh_fatal("diffie hellman setup failed for %s", group->name);

          if (ssh_pk_group_diffie_hellman_agree(g,
                                                secret,
                                                exchange, elen, agreed, alen,
                                                &rlen) != SSH_CRYPTO_OK)
            ssh_fatal("diffie hellman agree failed for %s", group->name);

          if (rlen != alen)
            ssh_fatal("agreed length differs");
        }

      ssh_time_measure_stop(&tmit);
      usecs = ssh_time_measure_get(&tmit, SSH_TIME_GRANULARITY_MICROSECOND);

      printf("group %s %d agreements in %ld usecs -> %2.4g/second\n",
             group->name,
             i, usecs,
             (double)(1.0 / ((1.0 / 1000000.0) * ((double)usecs / i))));

      ssh_xfree(agreed);
      ssh_xfree(exchange);

      ssh_pk_group_free(g);
    }
  return 0;
}
/* eof */
