/* Finalize an operation and return the digest. If R_DLEN is not NULL the length of the digest will be stored at that address. The returned value is valid as long as the context exists. On error NULL is returned. */ const void * _gcry_hmac256_finalize (hmac256_context_t hd, size_t *r_dlen) { finalize (hd); if (hd->use_hmac) { hmac256_context_t tmphd; tmphd = _gcry_hmac256_new (NULL, 0); if (!tmphd) return NULL; _gcry_hmac256_update (tmphd, hd->opad, 64); _gcry_hmac256_update (tmphd, hd->buf, 32); finalize (tmphd); memcpy (hd->buf, tmphd->buf, 32); _gcry_hmac256_release (tmphd); } if (r_dlen) *r_dlen = 32; return (void*)hd->buf; }
int main (int argc, char **argv) { const char *pgm; int last_argc = -1; const char *key; size_t keylen; FILE *fp; hmac256_context_t hd; const unsigned char *digest; char buffer[4096]; size_t n, dlen, idx; int use_stdin = 0; int use_binary = 0; assert (sizeof (u32) == 4); #ifdef __WIN32 setmode (fileno (stdin), O_BINARY); #endif if (argc) { pgm = strrchr (*argv, '/'); if (pgm) pgm++; else pgm = *argv; argc--; argv++; } else pgm = "?"; while (argc && last_argc != argc ) { last_argc = argc; if (!strcmp (*argv, "--")) { argc--; argv++; break; } else if (!strcmp (*argv, "--version")) { fputs ("hmac256 (Libgcrypt) " VERSION "\n" "Copyright (C) 2008 Free Software Foundation, Inc.\n" "License LGPLv2.1+: GNU LGPL version 2.1 or later " "<http://gnu.org/licenses/old-licenses/lgpl-2.1.html>\n" "This is free software: you are free to change and " "redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law.\n", stdout); exit (0); } else if (!strcmp (*argv, "--binary")) { argc--; argv++; use_binary = 1; } } if (argc < 1) { fprintf (stderr, "usage: %s [--binary] key [filename]\n", pgm); exit (1); } #ifdef __WIN32 if (use_binary) setmode (fileno (stdout), O_BINARY); #endif key = *argv; argc--, argv++; keylen = strlen (key); use_stdin = !argc; if (selftest ()) { fprintf (stderr, "%s: fatal error: self-test failed\n", pgm); exit (2); } for (; argc || use_stdin; argv++, argc--) { const char *fname = use_stdin? "-" : *argv; fp = use_stdin? stdin : fopen (fname, "rb"); if (!fp) { fprintf (stderr, "%s: can't open `%s': %s\n", pgm, fname, strerror (errno)); exit (1); } hd = _gcry_hmac256_new (key, keylen); if (!hd) { fprintf (stderr, "%s: can't allocate context: %s\n", pgm, strerror (errno)); exit (1); } while ( (n = fread (buffer, 1, sizeof buffer, fp))) _gcry_hmac256_update (hd, buffer, n); if (ferror (fp)) { fprintf (stderr, "%s: error reading `%s': %s\n", pgm, fname, strerror (errno)); exit (1); } if (!use_stdin) fclose (fp); digest = _gcry_hmac256_finalize (hd, &dlen); if (!digest) { fprintf (stderr, "%s: error computing HMAC: %s\n", pgm, strerror (errno)); exit (1); } if (use_binary) { if (fwrite (digest, dlen, 1, stdout) != 1) { fprintf (stderr, "%s: error writing output: %s\n", pgm, strerror (errno)); exit (1); } if (use_stdin) break; } else { for (idx=0; idx < dlen; idx++) printf ("%02x", digest[idx]); _gcry_hmac256_release (hd); if (use_stdin) { putchar ('\n'); break; } printf (" %s\n", fname); } } return 0; }
static int selftest (void) { static struct { const char * const desc; const char * const data; const char * const key; const unsigned char expect[32]; } tv[] = { { "data-28 key-4", "what do ya want for nothing?", "Jefe", { 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43 } }, { "data-9 key-20", "Hi There", "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" "\x0b\x0b\x0b\x0b", { 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7 } }, { "data-50 key-20", "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" "\xdd\xdd", "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" "\xaa\xaa\xaa\xaa", { 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe } }, { "data-50 key-26", "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" "\xcd\xcd", "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" "\x11\x12\x13\x14\x15\x16\x17\x18\x19", { 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07, 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b } }, { "data-54 key-131", "Test Using Larger Than Block-Size Key - Hash Key First", "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" "\xaa\xaa\xaa", { 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54 } }, { "data-152 key-131", "This is a test using a larger than block-size key and a larger " "than block-size data. The key needs to be hashed before being " "used by the HMAC algorithm.", "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" "\xaa\xaa\xaa", { 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2 } }, { NULL } }; int tvidx; for (tvidx=0; tv[tvidx].desc; tvidx++) { hmac256_context_t hmachd; const unsigned char *digest; size_t dlen; hmachd = _gcry_hmac256_new (tv[tvidx].key, strlen (tv[tvidx].key)); if (!hmachd) return -1; _gcry_hmac256_update (hmachd, tv[tvidx].data, strlen (tv[tvidx].data)); digest = _gcry_hmac256_finalize (hmachd, &dlen); if (!digest) { _gcry_hmac256_release (hmachd); return -1; } if (dlen != sizeof (tv[tvidx].expect) || memcmp (digest, tv[tvidx].expect, sizeof (tv[tvidx].expect))) { _gcry_hmac256_release (hmachd); return -1; } _gcry_hmac256_release (hmachd); } return 0; /* Succeeded. */ }
/* Convenience function to compute the HMAC-SHA256 of one file. The user needs to provide a buffer RESULT of at least 32 bytes, he needs to put the size of the buffer into RESULTSIZE and the FILENAME. KEY and KEYLEN are as described for _gcry_hmac256_new. On success the function returns the valid length of the result buffer (which will be 32) or -1 on error. On error ERRNO is set appropriate. */ int _gcry_hmac256_file (void *result, size_t resultsize, const char *filename, const void *key, size_t keylen) { FILE *fp; hmac256_context_t hd; size_t buffer_size, nread, digestlen; char *buffer; const unsigned char *digest; fp = fopen (filename, "rb"); if (!fp) return -1; hd = _gcry_hmac256_new (key, keylen); if (!hd) { fclose (fp); return -1; } buffer_size = 32768; buffer = malloc (buffer_size); if (!buffer) { fclose (fp); _gcry_hmac256_release (hd); return -1; } while ( (nread = fread (buffer, 1, buffer_size, fp))) _gcry_hmac256_update (hd, buffer, nread); free (buffer); if (ferror (fp)) { fclose (fp); _gcry_hmac256_release (hd); return -1; } fclose (fp); digest = _gcry_hmac256_finalize (hd, &digestlen); if (!digest) { _gcry_hmac256_release (hd); return -1; } if (digestlen > resultsize) { _gcry_hmac256_release (hd); gpg_err_set_errno (EINVAL); return -1; } memcpy (result, digest, digestlen); _gcry_hmac256_release (hd); return digestlen; }
/* Create a new context. On error NULL is returned and errno is set appropriately. If KEY is given the function computes HMAC using this key; with KEY given as NULL, a plain SHA-256 digest is computed. */ hmac256_context_t _gcry_hmac256_new (const void *key, size_t keylen) { hmac256_context_t hd; hd = malloc (sizeof *hd); if (!hd) return NULL; hd->h0 = 0x6a09e667; hd->h1 = 0xbb67ae85; hd->h2 = 0x3c6ef372; hd->h3 = 0xa54ff53a; hd->h4 = 0x510e527f; hd->h5 = 0x9b05688c; hd->h6 = 0x1f83d9ab; hd->h7 = 0x5be0cd19; hd->nblocks = 0; hd->count = 0; hd->finalized = 0; hd->use_hmac = 0; if (key) { int i; unsigned char ipad[64]; memset (ipad, 0, 64); memset (hd->opad, 0, 64); if (keylen <= 64) { memcpy (ipad, key, keylen); memcpy (hd->opad, key, keylen); } else { hmac256_context_t tmphd; tmphd = _gcry_hmac256_new (NULL, 0); if (!tmphd) { free (hd); return NULL; } _gcry_hmac256_update (tmphd, key, keylen); finalize (tmphd); memcpy (ipad, tmphd->buf, 32); memcpy (hd->opad, tmphd->buf, 32); _gcry_hmac256_release (tmphd); } for (i=0; i < 64; i++) { ipad[i] ^= 0x36; hd->opad[i] ^= 0x5c; } hd->use_hmac = 1; _gcry_hmac256_update (hd, ipad, 64); my_wipememory (ipad, 64); } return hd; }