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); }
/* 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; }
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); }
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); }
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; }
/* 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; }
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); }
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'); }
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); }
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; }
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; }
/* 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; }
/* 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); }