Example #1
0
static void
run_selftest (int algo)
{
  gpg_error_t err;
  size_t n;

  n = 1;
  err = gcry_md_algo_info (algo, GCRYCTL_SELFTEST, NULL, &n);
  if (err && gpg_err_code (err) != GPG_ERR_NOT_IMPLEMENTED)
    fail ("extended selftest for %s (%d) failed: %s",
          gcry_md_algo_name (algo), algo, gpg_strerror (err));
  else if (err && verbose)
    show ("extended selftest for %s (%d) not implemented",
          gcry_md_algo_name (algo), algo);
  else if (verbose)
    show ("extended selftest for %s (%d) passed",
          gcry_md_algo_name (algo), algo);
}
Example #2
0
/* Compare DIGEST of length DIGESTLEN generated using ALGO and GIGS
   plus BYTES with the test vector and print an error message if the
   don't match.  Return 0 on match.  */
static int
cmp_digest (const unsigned char *digest, size_t digestlen,
            int algo, int gigs, int bytes)
{
  int idx;
  unsigned char *tv_digest;
  size_t tv_digestlen = 0;

  for (idx=0; testvectors[idx].algo; idx++)
    {
      if (testvectors[idx].algo == algo
          && testvectors[idx].gigs == gigs
          && testvectors[idx].bytes == bytes)
        break;
    }
  if (!testvectors[idx].algo)
    {
      show ("%d GiB %+3d %-10s warning: %s",
            gigs, bytes, gcry_md_algo_name (algo), "no test vector");
      missing_test_vectors++;
      return 1;
    }

  tv_digest = hex2buffer (testvectors[idx].hex, &tv_digestlen);
  if (tv_digestlen != digestlen) /* Ooops.  */
    {
      fail ("%d GiB %+3d %-10s error: %s",
            gigs, bytes, gcry_md_algo_name (algo), "digest length mismatch");
      xfree (tv_digest);
      return 1;
    }
  if (memcmp (tv_digest, digest, tv_digestlen))
    {
      fail ("%d GiB %+3d %-10s error: %s",
            gigs, bytes, gcry_md_algo_name (algo), "mismatch");
      xfree (tv_digest);
      return 1;
    }
  xfree (tv_digest);

  return 0;
}
Example #3
0
static void
hash_bench_one (int algo, struct bench_hash_mode *pmode)
{
  struct bench_hash_mode mode = *pmode;
  struct bench_obj obj = { 0 };
  double result;

  mode.algo = algo;

  if (mode.name[0] == '\0')
    bench_print_algo (-14, gcry_md_algo_name (algo));
  else
    bench_print_algo (14, mode.name);

  obj.ops = mode.ops;
  obj.priv = &mode;

  result = do_slope_benchmark (&obj);

  bench_print_result (result);
}
Example #4
0
void
kdf_bench (char **argv, int argc)
{
  char algo_name[32];
  int i, j;

  bench_print_section ("kdf", "KDF");

  if (!csv_mode)
    {
      printf (" %-*s | ", 24, "");
      printf ("%14s %13s\n", "nanosecs/iter", "cycles/iter");
    }

  if (argv && argc)
    {
      for (i = 0; i < argc; i++)
	{
	  for (j = 1; j < 400; j++)
	    {
	      if (gcry_md_test_algo (j))
		continue;

	      snprintf (algo_name, sizeof(algo_name), "PBKDF2-HMAC-%s",
			gcry_md_algo_name (j));

	      if (!strcmp(argv[i], algo_name))
		kdf_bench_one (GCRY_KDF_PBKDF2, j);
	    }
	}
    }
  else
    {
      for (i = 1; i < 400; i++)
	if (!gcry_md_test_algo (i))
	  kdf_bench_one (GCRY_KDF_PBKDF2, i);
    }

  bench_print_footer (24);
}
Example #5
0
static int
bench_hash_init (struct bench_obj *obj)
{
  struct bench_hash_mode *mode = obj->priv;
  gcry_md_hd_t hd;
  int err;

  obj->min_bufsize = BUF_START_SIZE;
  obj->max_bufsize = BUF_END_SIZE;
  obj->step_size = BUF_STEP_SIZE;
  obj->num_measure_repetitions = num_measurement_repetitions;

  err = gcry_md_open (&hd, mode->algo, 0);
  if (err)
    {
      fprintf (stderr, PGM ": error opening hash `%s'\n",
	       gcry_md_algo_name (mode->algo));
      exit (1);
    }

  obj->priv = hd;

  return 0;
}
static gboolean
generate_pkcs12 (int hash_algo, int type, const gchar *utf8_password, 
                 gssize n_password, const guchar *salt, gsize n_salt, 
                 int iterations, guchar *output, gsize n_output)
{
	gcry_mpi_t num_b1, num_ij;
	guchar *hash, *buf_i, *buf_b;
	const gchar *end_password;
	gcry_md_hd_t mdh;
	const gchar *p2;
	guchar *p;
	gsize n_hash, i;
	gunichar unich;
	gcry_error_t gcry;
	
	num_b1 = num_ij = NULL;
	
	n_hash = gcry_md_get_algo_dlen (hash_algo);
	g_return_val_if_fail (n_hash > 0, FALSE);
	
	if (!utf8_password)
		n_password = 0;
	if (n_password == -1) 
		end_password = utf8_password + strlen (utf8_password);
	else
		end_password = utf8_password + n_password;
	
	gcry = gcry_md_open (&mdh, hash_algo, 0);
	if (gcry) {
		g_warning ("couldn't create '%s' hash context: %s", 
		           gcry_md_algo_name (hash_algo), gcry_strerror (gcry));
		return FALSE;
	}

	/* Reqisition me a buffer */
	hash = egg_secure_alloc (n_hash);
	buf_i = egg_secure_alloc (128);
	buf_b = egg_secure_alloc (64);
	g_return_val_if_fail (hash && buf_i && buf_b, FALSE);
		
	/* Bring in the salt */
	p = buf_i;
	if (salt) {
		for (i = 0; i < 64; ++i)
			*(p++) = salt[i % n_salt];
	} else {
		memset (p, 0, 64);
		p += 64;
	}
	
	/* Bring in the password, as 16bits per character BMP string, ie: UCS2 */
	if (utf8_password) {
		p2 = utf8_password;
		for (i = 0; i < 64; i += 2) {
			
			/* Get a character from the string */
			if (p2 < end_password) {
				unich = g_utf8_get_char (p2);
				p2 = g_utf8_next_char (p2);

			/* Get zero null terminator, and loop back to beginning */
			} else {
				unich = 0;
				p2 = utf8_password;
			}

			/* Encode the bytes received */
			*(p++) = (unich & 0xFF00) >> 8;
			*(p++) = (unich & 0xFF);
		}
	} else {
gboolean
egg_symkey_generate_pbe (int cipher_algo, int hash_algo, const gchar *password, 
                         gssize n_password, const guchar *salt, gsize n_salt, int iterations, 
                         guchar **key, guchar **iv)
{
	gcry_md_hd_t mdh;
	gcry_error_t gcry;
	guchar *digest;
	guchar *digested;
	guint i, n_digest;
	gint needed_iv, needed_key;

	g_assert (cipher_algo);
	g_assert (hash_algo);

	g_return_val_if_fail (iterations >= 1, FALSE);
	
	if (!password)
		n_password = 0;
	if (n_password == -1)
		n_password = strlen (password);
	
	/* 
	 * We only do one pass here.
	 * 
	 * The key ends up as the first needed_key bytes of the hash buffer.
	 * The iv ends up as the last needed_iv bytes of the hash buffer. 
	 * 
	 * The IV may overlap the key (which is stupid) if the wrong pair of 
	 * hash/cipher algorithms are chosen.
	 */ 

	n_digest = gcry_md_get_algo_dlen (hash_algo);
	g_return_val_if_fail (n_digest > 0, FALSE);
	
	needed_key = gcry_cipher_get_algo_keylen (cipher_algo);
	needed_iv = gcry_cipher_get_algo_blklen (cipher_algo);
	if (needed_iv + needed_key > 16 || needed_iv + needed_key > n_digest) {
		g_warning ("using PBE symkey generation with %s using an algorithm that needs " 
		           "too many bytes of key and/or IV: %s",
		           gcry_cipher_algo_name (hash_algo), 
		           gcry_cipher_algo_name (cipher_algo));
		return FALSE;
	}
	
	gcry = gcry_md_open (&mdh, hash_algo, 0);
	if (gcry) {
		g_warning ("couldn't create '%s' hash context: %s", 
			   gcry_md_algo_name (hash_algo), gcry_strerror (gcry));
		return FALSE;
	}

	digest = egg_secure_alloc (n_digest);
	g_return_val_if_fail (digest, FALSE);
	if (key) {
		*key = egg_secure_alloc (needed_key);
		g_return_val_if_fail (*key, FALSE);
	}
	if (iv) 
		*iv = g_new0 (guchar, needed_iv);

	if (password)
		gcry_md_write (mdh, password, n_password);
	if (salt && n_salt)
		gcry_md_write (mdh, salt, n_salt);
	gcry_md_final (mdh);
	digested = gcry_md_read (mdh, 0);
	g_return_val_if_fail (digested, FALSE);
	memcpy (digest, digested, n_digest);
		
	for (i = 1; i < iterations; ++i)
		gcry_md_hash_buffer (hash_algo, digest, digest, n_digest);
	
	/* The first x bytes are the key */
	if (key) {
		g_assert (needed_key <= n_digest);
		memcpy (*key, digest, needed_key);
	}
	
	/* The last 16 - x bytes are the iv */
	if (iv) {
		g_assert (needed_iv <= n_digest && n_digest >= 16);
		memcpy (*iv, digest + (16 - needed_iv), needed_iv);
	}
		
	egg_secure_free (digest);
	gcry_md_close (mdh);
	
	return TRUE;	
}
Example #8
0
/* Check the signature on CERT using the ISSUER_CERT.  This function
   does only test the cryptographic signature and nothing else.  It is
   assumed that the ISSUER_CERT is valid. */
static gpg_error_t
check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert)
{
  gpg_error_t err;
  const char *algoid;
  gcry_md_hd_t md;
  int i, algo;
  ksba_sexp_t p;
  size_t n;
  gcry_sexp_t s_sig, s_hash, s_pkey;
  const char *s;
  char algo_name[16+1]; /* hash algorithm name converted to lower case. */
  int digestlen;
  unsigned char *digest;

  /* Hash the target certificate using the algorithm from that certificate.  */
  algoid = ksba_cert_get_digest_algo (cert);
  algo = gcry_md_map_name (algoid);
  if (!algo)
    {
      log_error (_("unknown hash algorithm '%s'\n"), algoid? algoid:"?");
      return gpg_error (GPG_ERR_GENERAL);
    }
  s = gcry_md_algo_name (algo);
  for (i=0; *s && i < sizeof algo_name - 1; s++, i++)
    algo_name[i] = tolower (*s);
  algo_name[i] = 0;

  err = gcry_md_open (&md, algo, 0);
  if (err)
    {
      log_error ("md_open failed: %s\n", gpg_strerror (err));
      return err;
    }
  if (DBG_HASHING)
    gcry_md_debug (md, "hash.cert");

  err = ksba_cert_hash (cert, 1, HASH_FNC, md);
  if (err)
    {
      log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (err));
      gcry_md_close (md);
      return err;
    }
  gcry_md_final (md);

  /* Get the signature value out of the target certificate.  */
  p = ksba_cert_get_sig_val (cert);
  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
  if (!n)
    {
      log_error ("libksba did not return a proper S-Exp\n");
      gcry_md_close (md);
      ksba_free (p);
      return gpg_error (GPG_ERR_BUG);
    }
  if (DBG_CRYPTO)
    {
      int j;
      log_debug ("signature value:");
      for (j=0; j < n; j++)
        log_printf (" %02X", p[j]);
      log_printf ("\n");
    }

  err = gcry_sexp_sscan ( &s_sig, NULL, p, n);
  ksba_free (p);
  if (err)
    {
      log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (err));
      gcry_md_close (md);
      return err;
    }

  /* Get the public key from the issuer certificate.  */
  p = ksba_cert_get_public_key (issuer_cert);
  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
  if (!n)
    {
      log_error ("libksba did not return a proper S-Exp\n");
      gcry_md_close (md);
      ksba_free (p);
      gcry_sexp_release (s_sig);
      return gpg_error (GPG_ERR_BUG);
    }
  err = gcry_sexp_sscan ( &s_pkey, NULL, p, n);
  ksba_free (p);
  if (err)
    {
      log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (err));
      gcry_md_close (md);
      gcry_sexp_release (s_sig);
      return err;
    }


  /* Prepare the values for signature verification. At this point we
     have these values:

     S_PKEY    - S-expression with the issuer's public key.
     S_SIG     - Signature value as given in the certrificate.
     MD        - Finalized hash context with hash of the certificate.
     ALGO_NAME - Lowercase hash algorithm name
   */
  digestlen = gcry_md_get_algo_dlen (algo);
  digest = gcry_md_read (md, algo);
  if (pk_algo_from_sexp (s_pkey) == GCRY_PK_DSA)
    {
      if (digestlen != 20)
        {
          log_error (_("DSA requires the use of a 160 bit hash algorithm\n"));
          gcry_md_close (md);
          gcry_sexp_release (s_sig);
          gcry_sexp_release (s_pkey);
          return gpg_error (GPG_ERR_INTERNAL);
        }
      if ( gcry_sexp_build (&s_hash, NULL, "(data(flags raw)(value %b))",
                            (int)digestlen, digest) )
        BUG ();
    }
  else /* Not DSA.  */
    {
      if ( gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash %s %b))",
                            algo_name, (int)digestlen, digest) )
        BUG ();

    }

  err = gcry_pk_verify (s_sig, s_hash, s_pkey);
  if (DBG_X509)
    log_debug ("gcry_pk_verify: %s\n", gpg_strerror (err));
  gcry_md_close (md);
  gcry_sexp_release (s_sig);
  gcry_sexp_release (s_hash);
  gcry_sexp_release (s_pkey);
  return err;
}
Example #9
0
static void
md_bench ( const char *algoname )
{
  int algo;
  gcry_md_hd_t hd;
  int i, j, repcount;
  char buf_base[1000+15];
  size_t bufsize = 1000;
  char *buf;
  char *largebuf_base;
  char *largebuf;
  char digest[512/8];
  gcry_error_t err = GPG_ERR_NO_ERROR;

  if (!algoname)
    {
      for (i=1; i < 400; i++)
        if (in_fips_mode && i == GCRY_MD_MD5)
          ; /* Don't use MD5 in fips mode.  */
        else if ( !gcry_md_test_algo (i) )
          md_bench (gcry_md_algo_name (i));
      return;
    }

  buf = buf_base + ((16 - ((size_t)buf_base & 0x0f)) % buffer_alignment);

  algo = gcry_md_map_name (algoname);
  if (!algo)
    {
      fprintf (stderr, PGM ": invalid hash algorithm `%s'\n", algoname);
      exit (1);
    }

  err = gcry_md_open (&hd, algo, 0);
  if (err)
    {
      fprintf (stderr, PGM ": error opening hash algorithm `%s'\n", algoname);
      exit (1);
    }

  for (i=0; i < bufsize; i++)
    buf[i] = i;

  printf ("%-12s", gcry_md_algo_name (algo));

  start_timer ();
  for (repcount=0; repcount < hash_repetitions; repcount++)
    for (i=0; i < 1000; i++)
      gcry_md_write (hd, buf, bufsize);
  gcry_md_final (hd);
  stop_timer ();
  printf (" %s", elapsed_time ());
  fflush (stdout);

  gcry_md_reset (hd);
  start_timer ();
  for (repcount=0; repcount < hash_repetitions; repcount++)
    for (i=0; i < 10000; i++)
      gcry_md_write (hd, buf, bufsize/10);
  gcry_md_final (hd);
  stop_timer ();
  printf (" %s", elapsed_time ());
  fflush (stdout);

  gcry_md_reset (hd);
  start_timer ();
  for (repcount=0; repcount < hash_repetitions; repcount++)
    for (i=0; i < 1000000; i++)
      gcry_md_write (hd, buf, 1);
  gcry_md_final (hd);
  stop_timer ();
  printf (" %s", elapsed_time ());
  fflush (stdout);

  start_timer ();
  for (repcount=0; repcount < hash_repetitions; repcount++)
    for (i=0; i < 1000; i++)
      for (j=0; j < bufsize; j++)
        gcry_md_putc (hd, buf[j]);
  gcry_md_final (hd);
  stop_timer ();
  printf (" %s", elapsed_time ());
  fflush (stdout);

  gcry_md_close (hd);

  /* Now 100 hash operations on 10000 bytes using the fast function.
     We initialize the buffer so that all memory pages are committed
     and we have repeatable values.  */
  if (gcry_md_get_algo_dlen (algo) > sizeof digest)
    die ("digest buffer too short\n");

  largebuf_base = malloc (10000+15);
  if (!largebuf_base)
    die ("out of core\n");
  largebuf = (largebuf_base
              + ((16 - ((size_t)largebuf_base & 0x0f)) % buffer_alignment));

  for (i=0; i < 10000; i++)
    largebuf[i] = i;
  start_timer ();
  for (repcount=0; repcount < hash_repetitions; repcount++)
    for (i=0; i < 100; i++)
      gcry_md_hash_buffer (algo, digest, largebuf, 10000);
  stop_timer ();
  printf (" %s", elapsed_time ());
  free (largebuf_base);

  putchar ('\n');
  fflush (stdout);
}
Example #10
0
static void
check_digests (void)
{
  static struct algos
  {
    int md;
    char *data;
    char *expect;
  } algos[] =
    {
      { GCRY_MD_MD4, "",
	"\x31\xD6\xCF\xE0\xD1\x6A\xE9\x31\xB7\x3C\x59\xD7\xE0\xC0\x89\xC0" },
      { GCRY_MD_MD4, "a",
	"\xbd\xe5\x2c\xb3\x1d\xe3\x3e\x46\x24\x5e\x05\xfb\xdb\xd6\xfb\x24" },
      {	GCRY_MD_MD4, "message digest",
	"\xd9\x13\x0a\x81\x64\x54\x9f\xe8\x18\x87\x48\x06\xe1\xc7\x01\x4b" },
      {	GCRY_MD_MD5, "",
	"\xD4\x1D\x8C\xD9\x8F\x00\xB2\x04\xE9\x80\x09\x98\xEC\xF8\x42\x7E" },
      {	GCRY_MD_MD5, "a",
	"\x0C\xC1\x75\xB9\xC0\xF1\xB6\xA8\x31\xC3\x99\xE2\x69\x77\x26\x61" },
      { GCRY_MD_MD5, "abc",
	"\x90\x01\x50\x98\x3C\xD2\x4F\xB0\xD6\x96\x3F\x7D\x28\xE1\x7F\x72" },
      { GCRY_MD_MD5, "message digest",
	"\xF9\x6B\x69\x7D\x7C\xB7\x93\x8D\x52\x5A\x2F\x31\xAA\xF1\x61\xD0" },
      { GCRY_MD_SHA1, "abc",
	"\xA9\x99\x3E\x36\x47\x06\x81\x6A\xBA\x3E"
	"\x25\x71\x78\x50\xC2\x6C\x9C\xD0\xD8\x9D" },
      {	GCRY_MD_SHA1,
	"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
	"\x84\x98\x3E\x44\x1C\x3B\xD2\x6E\xBA\xAE"
	"\x4A\xA1\xF9\x51\x29\xE5\xE5\x46\x70\xF1" },
      { GCRY_MD_SHA1, "!" /* kludge for "a"*1000000 */ ,
	"\x34\xAA\x97\x3C\xD4\xC4\xDA\xA4\xF6\x1E"
	"\xEB\x2B\xDB\xAD\x27\x31\x65\x34\x01\x6F" },
      {	GCRY_MD_SHA256, "abc",
	"\xba\x78\x16\xbf\x8f\x01\xcf\xea\x41\x41\x40\xde\x5d\xae\x22\x23"
	"\xb0\x03\x61\xa3\x96\x17\x7a\x9c\xb4\x10\xff\x61\xf2\x00\x15\xad" },
      {	GCRY_MD_SHA256,
	"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
	"\x24\x8d\x6a\x61\xd2\x06\x38\xb8\xe5\xc0\x26\x93\x0c\x3e\x60\x39"
	"\xa3\x3c\xe4\x59\x64\xff\x21\x67\xf6\xec\xed\xd4\x19\xdb\x06\xc1" },
      {	GCRY_MD_SHA256, "!",
	"\xcd\xc7\x6e\x5c\x99\x14\xfb\x92\x81\xa1\xc7\xe2\x84\xd7\x3e\x67"
	"\xf1\x80\x9a\x48\xa4\x97\x20\x0e\x04\x6d\x39\xcc\xc7\x11\x2c\xd0" },
      {	GCRY_MD_SHA384, "abc",
	"\xcb\x00\x75\x3f\x45\xa3\x5e\x8b\xb5\xa0\x3d\x69\x9a\xc6\x50\x07"
	"\x27\x2c\x32\xab\x0e\xde\xd1\x63\x1a\x8b\x60\x5a\x43\xff\x5b\xed"
	"\x80\x86\x07\x2b\xa1\xe7\xcc\x23\x58\xba\xec\xa1\x34\xc8\x25\xa7" },
      {	GCRY_MD_SHA512, "abc",
	"\xDD\xAF\x35\xA1\x93\x61\x7A\xBA\xCC\x41\x73\x49\xAE\x20\x41\x31"
	"\x12\xE6\xFA\x4E\x89\xA9\x7E\xA2\x0A\x9E\xEE\xE6\x4B\x55\xD3\x9A"
	"\x21\x92\x99\x2A\x27\x4F\xC1\xA8\x36\xBA\x3C\x23\xA3\xFE\xEB\xBD"
	"\x45\x4D\x44\x23\x64\x3C\xE8\x0E\x2A\x9A\xC9\x4F\xA5\x4C\xA4\x9F" },
      {	GCRY_MD_RMD160, "",
	"\x9c\x11\x85\xa5\xc5\xe9\xfc\x54\x61\x28"
	"\x08\x97\x7e\xe8\xf5\x48\xb2\x25\x8d\x31" },
      {	GCRY_MD_RMD160, "a",
	"\x0b\xdc\x9d\x2d\x25\x6b\x3e\xe9\xda\xae"
	"\x34\x7b\xe6\xf4\xdc\x83\x5a\x46\x7f\xfe" },
      {	GCRY_MD_RMD160, "abc",
	"\x8e\xb2\x08\xf7\xe0\x5d\x98\x7a\x9b\x04"
	"\x4a\x8e\x98\xc6\xb0\x87\xf1\x5a\x0b\xfc" },
      {	GCRY_MD_RMD160, "message digest",
	"\x5d\x06\x89\xef\x49\xd2\xfa\xe5\x72\xb8"
	"\x81\xb1\x23\xa8\x5f\xfa\x21\x59\x5f\x36" },
      {	GCRY_MD_CRC32, "", "\x00\x00\x00\x00" },
      {	GCRY_MD_CRC32, "foo", "\x8c\x73\x65\x21" },
      { GCRY_MD_CRC32_RFC1510, "", "\x00\x00\x00\x00" },
      {	GCRY_MD_CRC32_RFC1510, "foo", "\x73\x32\xbc\x33" },
      {	GCRY_MD_CRC32_RFC1510, "test0123456789", "\xb8\x3e\x88\xd6" },
      {	GCRY_MD_CRC32_RFC1510, "MASSACHVSETTS INSTITVTE OF TECHNOLOGY",
	"\xe3\x41\x80\xf7" },
#if 0
      {	GCRY_MD_CRC32_RFC1510, "\x80\x00", "\x3b\x83\x98\x4b" },
      {	GCRY_MD_CRC32_RFC1510, "\x00\x08", "\x0e\xdb\x88\x32" },
      {	GCRY_MD_CRC32_RFC1510, "\x00\x80", "\xed\xb8\x83\x20" },
#endif
      {	GCRY_MD_CRC32_RFC1510, "\x80", "\xed\xb8\x83\x20" },
#if 0
      {	GCRY_MD_CRC32_RFC1510, "\x80\x00\x00\x00", "\xed\x59\xb6\x3b" },
      {	GCRY_MD_CRC32_RFC1510, "\x00\x00\x00\x01", "\x77\x07\x30\x96" },
#endif
      {	GCRY_MD_CRC24_RFC2440, "", "\xb7\x04\xce" },
      {	GCRY_MD_CRC24_RFC2440, "foo", "\x4f\xc2\x55" },
      {	GCRY_MD_TIGER, "",
	"\x24\xF0\x13\x0C\x63\xAC\x93\x32\x16\x16\x6E\x76"
	"\xB1\xBB\x92\x5F\xF3\x73\xDE\x2D\x49\x58\x4E\x7A" },
      {	GCRY_MD_TIGER, "abc",
	"\xF2\x58\xC1\xE8\x84\x14\xAB\x2A\x52\x7A\xB5\x41"
	"\xFF\xC5\xB8\xBF\x93\x5F\x7B\x95\x1C\x13\x29\x51" },
      {	GCRY_MD_TIGER, "Tiger",
	"\x9F\x00\xF5\x99\x07\x23\x00\xDD\x27\x6A\xBB\x38"
	"\xC8\xEB\x6D\xEC\x37\x79\x0C\x11\x6F\x9D\x2B\xDF" },
      {	GCRY_MD_TIGER, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg"
	"hijklmnopqrstuvwxyz0123456789+-",
	"\x87\xFB\x2A\x90\x83\x85\x1C\xF7\x47\x0D\x2C\xF8"
	"\x10\xE6\xDF\x9E\xB5\x86\x44\x50\x34\xA5\xA3\x86" },
      {	GCRY_MD_TIGER, "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdef"
	"ghijklmnopqrstuvwxyz+0123456789",
	"\x46\x7D\xB8\x08\x63\xEB\xCE\x48\x8D\xF1\xCD\x12"
	"\x61\x65\x5D\xE9\x57\x89\x65\x65\x97\x5F\x91\x97" },
#if 0
      {	GCRY_MD_TIGER, "Tiger - A Fast New Hash Function, "
	"by Ross Anderson and Eli Biham",
	"0C410A042968868A1671DA5A3FD29A725EC1E457D3CDB303" },
      {	GCRY_MD_TIGER, "Tiger - A Fast New Hash Function, "
	"by Ross Anderson and Eli Biham, proceedings of Fa"
	"st Software Encryption 3, Cambridge.",
	"EBF591D5AFA655CE7F22894FF87F54AC89C811B6B0DA3193" },
      {	GCRY_MD_TIGER, "Tiger - A Fast New Hash Function, "
	"by Ross Anderson and Eli Biham, proceedings of Fa"
	"st Software Encryption 3, Cambridge, 1996.",
	"3D9AEB03D1BD1A6357B2774DFD6D5B24DD68151D503974FC" },
      {	GCRY_MD_TIGER, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefgh"
	"ijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRS"
	"TUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
	"00B83EB4E53440C5 76AC6AAEE0A74858 25FD15E70A59FFE4" },
#endif
      {	0 },
    };
  int i;

  for (i = 0; algos[i].md; i++)
    {
      if (verbose)
	fprintf (stderr, "checking `%s'\n", gcry_md_algo_name (algos[i].md));

      check_one_md (algos[i].md, algos[i].data, strlen (algos[i].data),
		    algos[i].expect);
    }

  /* TODO: test HMAC mode */
}
static void
md_bench ( const char *algoname )
{
  int algo;
  gcry_md_hd_t hd;
  int i;
  char buf[1000];
  gcry_error_t err = GPG_ERR_NO_ERROR;

  if (!algoname)
    {
      for (i=1; i < 400; i++)
        if ( !gcry_md_test_algo (i) )
          md_bench (gcry_md_algo_name (i));
      return;
    }

  algo = gcry_md_map_name (algoname);
  if (!algo)
    {
      fprintf (stderr, PGM ": invalid hash algorithm `%s'\n", algoname);
      exit (1);
    }

  err = gcry_md_open (&hd, algo, 0);
  if (err)
    {
      fprintf (stderr, PGM ": error opening hash algorithm `%s'\n", algoname);
      exit (1);
    }

  for (i=0; i < sizeof buf; i++)
    buf[i] = i;

  printf ("%-12s", gcry_md_algo_name (algo));

  start_timer ();
  for (i=0; i < 1000; i++)
    gcry_md_write (hd, buf, sizeof buf);
  gcry_md_final (hd);
  stop_timer ();
  printf (" %s", elapsed_time ());

  gcry_md_reset (hd);
  start_timer ();
  for (i=0; i < 10000; i++)
    gcry_md_write (hd, buf, sizeof buf/10);
  gcry_md_final (hd);
  stop_timer ();
  printf (" %s", elapsed_time ());

  gcry_md_reset (hd);
  start_timer ();
  for (i=0; i < 1000000; i++)
    gcry_md_write (hd, "", 1);
  gcry_md_final (hd);
  stop_timer ();
  printf (" %s", elapsed_time ());

  gcry_md_close (hd);
  putchar ('\n');
}
Example #12
0
static void
run_longtest (int algo, int gigs)
{
  gpg_error_t err;
  gcry_md_hd_t hd;
  gcry_md_hd_t hd_pre = NULL;
  gcry_md_hd_t hd_pre2 = NULL;
  gcry_md_hd_t hd_post = NULL;
  gcry_md_hd_t hd_post2 = NULL;
  char pattern[1024];
  int i, g;
  const unsigned char *digest;
  unsigned int digestlen;

  memset (pattern, 'a', sizeof pattern);

  err = gcry_md_open (&hd, algo, 0);
  if (err)
    {
      fail ("gcry_md_open failed for %s (%d): %s",
            gcry_md_algo_name (algo), algo, gpg_strerror (err));
      return;
    }

  digestlen = gcry_md_get_algo_dlen (algo);


  for (g=0; g < gigs; g++)
    {
      if (g == gigs - 1)
        {
          for (i = 0; i < 1024*1023; i++)
            gcry_md_write (hd, pattern, sizeof pattern);
          for (i = 0; i < 1023; i++)
            gcry_md_write (hd, pattern, sizeof pattern);
          err = gcry_md_copy (&hd_pre, hd);
          if (!err)
            err = gcry_md_copy (&hd_pre2, hd);
          if (err)
            die ("gcry_md_copy failed for %s (%d): %s",
                 gcry_md_algo_name (algo), algo, gpg_strerror (err));
          gcry_md_write (hd, pattern, sizeof pattern);
        }
      else
        {
          for (i = 0; i < 1024*1024; i++)
            gcry_md_write (hd, pattern, sizeof pattern);
        }
      if (g && !(g % 16))
        show_note ("%d GiB so far hashed with %s", g, gcry_md_algo_name (algo));
    }
  if (g >= 16)
    show_note ("%d GiB hashed with %s", g, gcry_md_algo_name (algo));

  err = gcry_md_copy (&hd_post, hd);
  if (err)
    die ("gcry_md_copy failed for %s (%d): %s",
         gcry_md_algo_name (algo), algo, gpg_strerror (err));
  err = gcry_md_copy (&hd_post2, hd);
  if (err)
    die ("gcry_md_copy failed for %s (%d): %s",
         gcry_md_algo_name (algo), algo, gpg_strerror (err));

  gcry_md_write (hd_pre2, pattern, sizeof pattern - 64);
  gcry_md_write (hd_pre, pattern, sizeof pattern - 1);
  gcry_md_write (hd_post, pattern, 1);
  gcry_md_write (hd_post2, pattern, 64);

  digest = gcry_md_read (hd_pre2, algo);
  if (cmp_digest (digest, digestlen, algo, gigs, -64) || verbose)
    showhex (digest, digestlen, "%d GiB %+3d %-10s ",
             gigs, -64, gcry_md_algo_name (algo));
  digest = gcry_md_read (hd_pre, algo);
  if (cmp_digest (digest, digestlen, algo, gigs, -1) || verbose)
    showhex (digest, digestlen, "%d GiB %+3d %-10s ",
             gigs, -1, gcry_md_algo_name (algo));
  digest = gcry_md_read (hd, algo);
  if (cmp_digest (digest, digestlen, algo, gigs, 0) || verbose)
    showhex (digest, digestlen, "%d GiB %+3d %-10s ",
             gigs, 0, gcry_md_algo_name (algo));
  digest = gcry_md_read (hd_post, algo);
  if (cmp_digest (digest, digestlen, algo, gigs, 1) || verbose)
    showhex (digest, digestlen, "%d GiB %+3d %-10s ",
             gigs, 1, gcry_md_algo_name (algo));
  digest = gcry_md_read (hd_post2, algo);
  if (cmp_digest (digest, digestlen, algo, gigs, 64) || verbose)
    showhex (digest, digestlen, "%d GiB %+3d %-10s ",
             gigs, 64, gcry_md_algo_name (algo));

  gcry_md_close (hd);
  gcry_md_close (hd_pre);
  gcry_md_close (hd_pre2);
  gcry_md_close (hd_post);
  gcry_md_close (hd_post2);
}
Example #13
0
static void
kdf_bench_one (int algo, int subalgo)
{
  struct bench_kdf_mode mode = { &kdf_ops };
  struct bench_obj obj = { 0 };
  double nsecs_per_iteration;
  double cycles_per_iteration;
  char algo_name[32];
  char nsecpiter_buf[16];
  char cpiter_buf[16];

  mode.algo = algo;
  mode.subalgo = subalgo;

  switch (subalgo)
    {
    case GCRY_MD_CRC32:
    case GCRY_MD_CRC32_RFC1510:
    case GCRY_MD_CRC24_RFC2440:
    case GCRY_MD_MD4:
      /* Skip CRC32s. */
      return;
    }

  if (gcry_md_get_algo_dlen (subalgo) == 0)
    {
      /* Skip XOFs */
      return;
    }

  *algo_name = 0;

  if (algo == GCRY_KDF_PBKDF2)
    {
      snprintf (algo_name, sizeof(algo_name), "PBKDF2-HMAC-%s",
		gcry_md_algo_name (subalgo));
    }

  bench_print_algo (-24, algo_name);

  obj.ops = mode.ops;
  obj.priv = &mode;

  nsecs_per_iteration = do_slope_benchmark (&obj);

  strcpy(cpiter_buf, csv_mode ? "" : "-");

  double_to_str (nsecpiter_buf, sizeof (nsecpiter_buf), nsecs_per_iteration);

  /* If user didn't provide CPU speed, we cannot show cycles/iter results.  */
  if (cpu_ghz > 0.0)
    {
      cycles_per_iteration = nsecs_per_iteration * cpu_ghz;
      double_to_str (cpiter_buf, sizeof (cpiter_buf), cycles_per_iteration);
    }

  if (csv_mode)
    {
      printf ("%s,%s,%s,,,,,,,,,%s,ns/iter,%s,c/iter\n",
	      current_section_name,
	      current_algo_name ? current_algo_name : "",
	      current_mode_name ? current_mode_name : "",
	      nsecpiter_buf,
	      cpiter_buf);
    }
  else
    {
      printf ("%14s %13s\n", nsecpiter_buf, cpiter_buf);
    }
}
gboolean
egg_symkey_generate_simple (int cipher_algo, int hash_algo, 
                            const gchar *password, gssize n_password, 
                            const guchar *salt, gsize n_salt, int iterations, 
                            guchar **key, guchar **iv)
{
	gcry_md_hd_t mdh;
	gcry_error_t gcry;
	guchar *digest;
	guchar *digested;
	guint n_digest;
	gint pass, i;
	gint needed_iv, needed_key;
	guchar *at_iv, *at_key;

	g_assert (cipher_algo);
	g_assert (hash_algo);

	g_return_val_if_fail (iterations >= 1, FALSE);
	
	if (!password)
		n_password = 0;
	if (n_password == -1)
		n_password = strlen (password);
	
	/* 
	 * If cipher algo needs more bytes than hash algo has available
	 * then the entire hashing process is done again (with the previous
	 * hash bytes as extra input), and so on until satisfied.
	 */ 
	
	needed_key = gcry_cipher_get_algo_keylen (cipher_algo);
	needed_iv = gcry_cipher_get_algo_blklen (cipher_algo);
	
	gcry = gcry_md_open (&mdh, hash_algo, 0);
	if (gcry) {
		g_warning ("couldn't create '%s' hash context: %s", 
			   gcry_md_algo_name (hash_algo), gcry_strerror (gcry));
		return FALSE;
	}

	n_digest = gcry_md_get_algo_dlen (hash_algo);
	g_return_val_if_fail (n_digest > 0, FALSE);
	
	digest = egg_secure_alloc (n_digest);
	g_return_val_if_fail (digest, FALSE);
	if (key) {
		*key = egg_secure_alloc (needed_key);
		g_return_val_if_fail (*key, FALSE);
	}
	if (iv) 
		*iv = g_new0 (guchar, needed_iv);

	at_key = key ? *key : NULL;
	at_iv = iv ? *iv : NULL;

	for (pass = 0; TRUE; ++pass) {
		gcry_md_reset (mdh);
		
		/* Hash in the previous buffer on later passes */
		if (pass > 0)
			gcry_md_write (mdh, digest, n_digest);

		if (password)
			gcry_md_write (mdh, password, n_password);
		if (salt && n_salt)
			gcry_md_write (mdh, salt, n_salt);
		gcry_md_final (mdh);
		digested = gcry_md_read (mdh, 0);
		g_return_val_if_fail (digested, FALSE);
		memcpy (digest, digested, n_digest);
		
		for (i = 1; i < iterations; ++i) {
			gcry_md_reset (mdh);
			gcry_md_write (mdh, digest, n_digest);
			gcry_md_final (mdh);
			digested = gcry_md_read (mdh, 0);
			g_return_val_if_fail (digested, FALSE);
			memcpy (digest, digested, n_digest);
		}
		
		/* Copy as much as possible into the destinations */
		i = 0; 
		while (needed_key && i < n_digest) {
			if (at_key)
				*(at_key++) = digest[i];
			needed_key--;
			i++;
		}
		while (needed_iv && i < n_digest) {
			if (at_iv) 
				*(at_iv++) = digest[i];
			needed_iv--;
			i++;
		}
		
		if (needed_key == 0 && needed_iv == 0)
			break;
	}

	egg_secure_free (digest);
	gcry_md_close (mdh);
	
	return TRUE;
}
Example #15
0
int check_hash(int fd_no, const char *f_md5, const char *f_sha256){
	int md5algo, sha256algo, i;
	char hashed_md5[33], hashed_sha256[65];
	struct stat fileStat;
	char *buffer;
	const char *md5name = gcry_md_algo_name(GCRY_MD_MD5);
	const char *sha256name = gcry_md_algo_name(GCRY_MD_SHA256);
	md5algo = gcry_md_map_name(md5name);
	sha256algo = gcry_md_map_name(sha256name);
	off_t fsize = 0, donesize = 0, diff = 0;
  	if(fstat(fd_no, &fileStat) < 0){
  		perror("Fstat error");
    	return -1;
  	}
  	fsize = fileStat.st_size;
  	FILE *fp = fdopen(fd_no, "r");
  	if(fp == NULL){
  		printf("Cannot open file for read\n");
  		return -1;
  	}
	gcry_md_hd_t hd_md5;
	gcry_md_hd_t hd_sha256;
	gcry_md_open(&hd_md5, md5algo, 0);
	gcry_md_open(&hd_sha256, sha256algo, 0);
	if(fsize < 10024){
		buffer = malloc(fsize);
  		if(buffer == NULL){
  			printf("malloc error\n");
  			return -1;
  		}
		fread(buffer, 1, fsize, fp);
		gcry_md_write(hd_md5, buffer, fsize);
		gcry_md_write(hd_sha256, buffer, fsize);
		goto nowhile;
	}
	buffer = malloc(10024);
  	if(buffer == NULL){
  		printf("malloc error\n");
  		return -1;
  	}
	while(fsize > donesize){
		fread(buffer, 1, 10024, fp);
		gcry_md_write(hd_md5, buffer, 10024);
		gcry_md_write(hd_sha256, buffer, 10024);
		donesize+=10024;
		diff=fsize-donesize;
		if(diff < 10024){
			fread(buffer, 1, diff, fp);
			gcry_md_write(hd_md5, buffer, diff);
			gcry_md_write(hd_sha256, buffer, diff);
			break;
		}
	}
	nowhile:
	gcry_md_final(hd_md5);
	gcry_md_final(hd_sha256);
	unsigned const char *md5 = gcry_md_read(hd_md5, md5algo);
	unsigned const char *sha256 = gcry_md_read(hd_sha256, sha256algo);
 	for(i=0; i<16; i++){
 		sprintf(hashed_md5+(i*2), "%02x", md5[i]);
 	}
 	for(i=0; i<32; i++){
 		sprintf(hashed_sha256+(i*2), "%02x", sha256[i]);
 	}
 	hashed_md5[32] = '\0';
 	hashed_sha256[64] = '\0';
 	free(buffer);
 	fclose(fp);
 	close(fd_no);
 	if((strcmp(f_md5, hashed_md5) != 0) || (strcmp(f_sha256, hashed_sha256) != 0)){
 		printf("Error: checksum mismatch\n");
 	}
 	else printf("Checksum ok\n");
	gcry_md_close(hd_md5);
	gcry_md_close(hd_sha256);
	return 0;
}
Example #16
0
/* This function recognizes the signature of the KSP itself. Note that this
 * function prepares the validation of the signature of the KSP with its
 * corresponding public key but does not actually do the validation. The
 * validation should be done with kmocrypt_signature_validate2() once the public
 * key has been obtained from the KOS.
 * This function sets the KMO error string. It returns -1 on failure.
 */
static int recognize_ksp_signature(struct kmocrypt_signature2 *self, kbuffer *buffer, uint32_t total_len) {
    int error = 0;
    uint32_t sig_len;
    size_t scanned_sig_len;
    int digest_len = gcry_md_get_algo_dlen(self->hash_algo);
    uint8_t digest[MAX_DIGEST_LEN];
    char hashname[MAX_HASH_ALGO_NAME_LEN];
    char signame[MAX_SIG_ALGO_NAME_LEN];
    
    /* Verify that we're using the correct signature algorithm. */
    if (self->sig_algo != GCRY_AC_RSA) {
    	kmo_seterror("Signature algorithm is not GCRY_AC_RSA");
	return -1;
    }
    
    /* Get the hash algorithm name. */
    strncpy(hashname, gcry_md_algo_name(self->hash_algo), MAX_HASH_ALGO_NAME_LEN);
    strntolower(hashname, MAX_HASH_ALGO_NAME_LEN);
    
    /* Get the signature algorithm name. */
    strncpy(signame, gcry_pk_algo_name(self->sig_algo), MAX_SIG_ALGO_NAME_LEN);
    strntolower(signame, MAX_SIG_ALGO_NAME_LEN);
    
    /* Hash the content of the KSP up to KSP signature part. */
    gcry_md_hash_buffer(self->hash_algo, digest, buffer->data, buffer->pos);
    
    /* Build the gcrypt hash of the KSP required to verify the signature. */
    error = gcry_sexp_build(&self->sig_hash, NULL, "(4:data(5:flags5:pkcs1)(4:hash %s %b))", 
                            hashname, digest_len, digest);
    if (error) {
        kmo_seterror("cannot build signature hash: %s", gcry_strerror(error));
	return -1;
    }
    
    /* Get the length of the signature. */
    if (total_len < 4) {
    	kmo_seterror("KSP signature section is too short");
	return -1;
    }
    
    sig_len = kbuffer_read32(buffer);
    
    if (total_len != 4 + sig_len) {
    	kmo_seterror("KSP signature section is malformed");
	return -1;
    }
    
    /* Get the signature MPI. */
    error = gcry_mpi_scan(&self->sig_mpi, GCRYMPI_FMT_PGP, kbuffer_current_pos(buffer), sig_len, &scanned_sig_len);
    if (error) {
    	kmo_seterror("invalid MPI in signature: %s", gcry_strerror(error));
	return -1;
    }
    
    if (scanned_sig_len != sig_len) {
    	kmo_seterror("invalid MPI in signature: unexpected size");
	return -1;
    }
    
    /* Skip the signature (just to be thorough, it's not strictly necessary). */
    buffer->pos += sig_len;
    
    /* Build the signature s-expression. */
    error = gcry_sexp_build(&self->sig_sexp, NULL, "(7:sig-val(%s(1:s %m)))", signame, self->sig_mpi);
    if (error) {
    	kmo_seterror("cannot build signature from MPI: %s", gcry_strerror(error));
	return -1;
    }
    
    return 0;
}
Example #17
0
/* Check a signature.
 *
 * Looks up the public key that created the signature (SIG->KEYID)
 * from the key db.  Makes sure that the signature is valid (it was
 * not created prior to the key, the public key was created in the
 * past, and the signature does not include any unsupported critical
 * features), finishes computing the hash of the signature data, and
 * checks that the signature verifies the digest.  If the key that
 * generated the signature is a subkey, this function also verifies
 * that there is a valid backsig from the subkey to the primary key.
 * Finally, if status fd is enabled and the signature class is 0x00 or
 * 0x01, then a STATUS_SIG_ID is emitted on the status fd.
 *
 * SIG is the signature to check.
 *
 * DIGEST contains a valid hash context that already includes the
 * signed data.  This function adds the relevant meta-data from the
 * signature packet to compute the final hash.  (See Section 5.2 of
 * RFC 4880: "The concatenation of the data being signed and the
 * signature data from the version number through the hashed subpacket
 * data (inclusive) is hashed.")
 *
 * If R_EXPIREDATE is not NULL, R_EXPIREDATE is set to the key's
 * expiry.
 *
 * If R_EXPIRED is not NULL, *R_EXPIRED is set to 1 if PK has expired
 * (0 otherwise).  Note: PK being expired does not cause this function
 * to fail.
 *
 * If R_REVOKED is not NULL, *R_REVOKED is set to 1 if PK has been
 * revoked (0 otherwise).  Note: PK being revoked does not cause this
 * function to fail.
 *
 * If R_PK is not NULL, the public key is stored at that address if it
 * was found; other wise NULL is stored.
 *
 * Returns 0 on success.  An error code otherwise.  */
gpg_error_t
check_signature2 (ctrl_t ctrl,
                  PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate,
		  int *r_expired, int *r_revoked, PKT_public_key **r_pk)
{
  int rc=0;
  PKT_public_key *pk;

  if (r_expiredate)
    *r_expiredate = 0;
  if (r_expired)
    *r_expired = 0;
  if (r_revoked)
    *r_revoked = 0;
  if (r_pk)
    *r_pk = NULL;

  pk = xtrycalloc (1, sizeof *pk);
  if (!pk)
    return gpg_error_from_syserror ();

  if  ((rc=openpgp_md_test_algo(sig->digest_algo)))
    {
      /* We don't have this digest. */
    }
  else if (!gnupg_digest_is_allowed (opt.compliance, 0, sig->digest_algo))
    {
      /* Compliance failure.  */
      log_info (_("digest algorithm '%s' may not be used in %s mode\n"),
                gcry_md_algo_name (sig->digest_algo),
                gnupg_compliance_option_string (opt.compliance));
      rc = gpg_error (GPG_ERR_DIGEST_ALGO);
    }
  else if ((rc=openpgp_pk_test_algo(sig->pubkey_algo)))
    {
      /* We don't have this pubkey algo. */
    }
  else if (!gcry_md_is_enabled (digest,sig->digest_algo))
    {
      /* Sanity check that the md has a context for the hash that the
       * sig is expecting.  This can happen if a onepass sig header
       * does not match the actual sig, and also if the clearsign
       * "Hash:" header is missing or does not match the actual sig. */
      log_info(_("WARNING: signature digest conflict in message\n"));
      rc = gpg_error (GPG_ERR_GENERAL);
    }
  else if (get_pubkey_for_sig (ctrl, pk, sig))
    rc = gpg_error (GPG_ERR_NO_PUBKEY);
  else if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
                                 pk->pubkey_algo, pk->pkey,
                                 nbits_from_pk (pk),
                                 NULL))
    {
      /* Compliance failure.  */
      log_error (_("key %s may not be used for signing in %s mode\n"),
                 keystr_from_pk (pk),
                 gnupg_compliance_option_string (opt.compliance));
      rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
    }
  else if (!pk->flags.valid)
    {
      /* You cannot have a good sig from an invalid key.  */
      rc = gpg_error (GPG_ERR_BAD_PUBKEY);
    }
  else
    {
      if (r_expiredate)
        *r_expiredate = pk->expiredate;

      rc = check_signature_end (pk, sig, digest, r_expired, r_revoked, NULL);

      /* Check the backsig.  This is a back signature (0x19) from
       * the subkey on the primary key.  The idea here is that it
       * should not be possible for someone to "steal" subkeys and
       * claim them as their own.  The attacker couldn't actually
       * use the subkey, but they could try and claim ownership of
       * any signatures issued by it.  */
      if (!rc && !pk->flags.primary && pk->flags.backsig < 2)
        {
          if (!pk->flags.backsig)
            {
              log_info (_("WARNING: signing subkey %s is not"
                          " cross-certified\n"),keystr_from_pk(pk));
              log_info (_("please see %s for more information\n"),
                        "https://gnupg.org/faq/subkey-cross-certify.html");
              /* The default option --require-cross-certification
               * makes this warning an error.  */
              if (opt.flags.require_cross_cert)
                rc = gpg_error (GPG_ERR_GENERAL);
            }
          else if(pk->flags.backsig == 1)
            {
              log_info (_("WARNING: signing subkey %s has an invalid"
                          " cross-certification\n"), keystr_from_pk(pk));
              rc = gpg_error (GPG_ERR_GENERAL);
            }
        }

    }

    if( !rc && sig->sig_class < 2 && is_status_enabled() ) {
	/* This signature id works best with DLP algorithms because
	 * they use a random parameter for every signature.  Instead of
	 * this sig-id we could have also used the hash of the document
	 * and the timestamp, but the drawback of this is, that it is
	 * not possible to sign more than one identical document within
	 * one second.	Some remote batch processing applications might
	 * like this feature here.
         *
         * Note that before 2.0.10, we used RIPE-MD160 for the hash
         * and accidentally didn't include the timestamp and algorithm
         * information in the hash.  Given that this feature is not
         * commonly used and that a replay attacks detection should
         * not solely be based on this feature (because it does not
         * work with RSA), we take the freedom and switch to SHA-1
         * with 2.0.10 to take advantage of hardware supported SHA-1
         * implementations.  We also include the missing information
         * in the hash.  Note also the SIG_ID as computed by gpg 1.x
         * and gpg 2.x didn't matched either because 2.x used to print
         * MPIs not in PGP format.  */
	u32 a = sig->timestamp;
	int nsig = pubkey_get_nsig( sig->pubkey_algo );
	unsigned char *p, *buffer;
        size_t n, nbytes;
        int i;
        char hashbuf[20];  /* We use SHA-1 here.  */

      nbytes = 6;
      for (i=0; i < nsig; i++ )
        {
          if (gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n, sig->data[i]))
            BUG();
          nbytes += n;
        }

      /* Make buffer large enough to be later used as output buffer.  */
      if (nbytes < 100)
        nbytes = 100;
      nbytes += 10;  /* Safety margin.  */

      /* Fill and hash buffer.  */
      buffer = p = xmalloc (nbytes);
      *p++ = sig->pubkey_algo;
      *p++ = sig->digest_algo;
      *p++ = (a >> 24) & 0xff;
      *p++ = (a >> 16) & 0xff;
      *p++ = (a >>  8) & 0xff;
      *p++ =  a & 0xff;
      nbytes -= 6;
      for (i=0; i < nsig; i++ )
        {
          if (gcry_mpi_print (GCRYMPI_FMT_PGP, p, nbytes, &n, sig->data[i]))
            BUG();
          p += n;
          nbytes -= n;
        }
      gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, buffer, p-buffer);

      p = make_radix64_string (hashbuf, 20);
      sprintf (buffer, "%s %s %lu",
               p, strtimestamp (sig->timestamp), (ulong)sig->timestamp);
      xfree (p);
      write_status_text (STATUS_SIG_ID, buffer);
      xfree (buffer);
    }