blob: da1cfd9edefbd22259f941d03aa5f8a22b965633 [file] [log] [blame] [edit]
/*
* hmac.c
*
* Version 1.0.0
*
* Written by Aaron D. Gifford <me@aarongifford.com>
*
* Copyright 1998, 2000 Aaron D. Gifford. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* This is a simple command-line program to compute HMAC-SHA-1 for a
* message using key. It's used like this:
*
* ./hmac <key-file> [<mesage-file>]
* OR
* ./hmac -k <key-data> [<message-file>]
*
* If the message file is not specified, the program reads
* from standard input. The key data can either be read
* from the specified file, or from the command line.
*
* Compiles and works on my FreeBSD 4.0 system using:
*
* cc -o hmac hmac.c hmac_sha1.c sha1.c
*
* Or if you don't wish to use Steve Reid's public domain implementation
* of SHA1 and your machine has SHA1 available in a library, you can edit
* hmac_sha1.h and make sure it includes the appropriate header, then do
* something like this (which also works on my FreeBSD system which includes
* Eric A. Young's SSH1 implementation in libmd):
*
* cc -o hmac hmac.c hmac_sha1.c -lmd
*
*
* Examples: (these work for me on my FreeBSD machine)
*
* echo -n 'what do ya want for nothing?' | ./hmac -k Jefe
*
* This SHOULD give the result RFC 2202 says you should get
* for HMAC-SHA-1 test case #3:
*
* 0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79
*
* Another test vector, test case #7 can be reproduced thus:
*
* echo -n 'Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data' | ./hmac -k `perl -e 'print pack("C",0xaa) x 80;'`
*
* Which SHOULD give:
*
* 0xe8e99d0f45237d786d6bbaa7965c7808bbff1a91
*
* Here are all the HMAC-SHA1 test cases from RFC 2202:
*
* 1)
* key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
* key_len = 20
* data = "Hi There"
* data_len = 8
* digest = 0xb617318655057264e28bc0b6fb378c8ef146be00
*
* 2)
* key = "Jefe"
* key_len = 4
* data = "what do ya want for nothing?"
* data_len = 28
* digest = 0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79
*
* 3)
* key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
* key_len = 20
* data = 0xdd repeated 50 times
* data_len = 50
* digest = 0x125d7342b9ac11cd91a39af48aa17b4f63f175d3
*
* 4)
* key = 0x0102030405060708090a0b0c0d0e0f10111213141516171819
* key_len = 25
* data = 0xcd repeated 50 times
* data_len = 50
* digest = 0x4c9007f4026250c6bc8414f9bf50c86c2d7235da
*
* 5)
* key = 0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
* key_len = 20
* data = "Test With Truncation"
* data_len = 20
* digest = 0x4c1a03424b55e07fe7f27be1d58bb9324a9a5a04
* digest-96 = 0x4c1a03424b55e07fe7f27be1
*
* 6)
* key = 0xaa repeated 80 times
* key_len = 80
* data = "Test Using Larger Than Block-Size Key - Hash Key First"
* data_len = 54
* digest = 0xaa4ae5e15272d00e95705637ce8a3b55ed402112
*
* 7)
* key = 0xaa repeated 80 times
* key_len = 80
* data = "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"
* data_len = 73
* digest = 0xe8e99d0f45237d786d6bbaa7965c7808bbff1a91
*
*/
#include <stdio.h>
#include <sysexits.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include "hmac_sha1.h"
void usage(char *prog) {
fprintf(stderr, "Usage:\n\t%s <key-file> [<message-file>]\n\tOR\n\t%s -k <key-data> [<message-file>]\n\n", prog, prog);
exit(EX_USAGE);
}
void hexout(unsigned char *data, int datalen) {
printf("0x");
while (datalen-- > 0)
printf("%02x",(unsigned char)*data++);
printf("\n");
}
#define BUFLEN 4096
int main(int argc, char **argv) {
int kl, l, fd, i;
FILE *IN;
HMAC_SHA1_CTX ctx;
unsigned char buf[BUFLEN];
HMAC_SHA1_Init(&ctx);
if (argc < 2 || argc > 4)
usage(argv[0]);
if (*argv[1] == '-') {
if (*(argv[1]+1) != 'k' || (*(argv[1]+1) != '\0' && *(argv[1]+2)))
usage(argv[0]);
if (argc < 3)
usage(argv[0]);
if (strlen(argv[2]) < 1)
fprintf(stderr, "%s: WARNING: Key contains no data. Using null key anyway.\n", argv[0]);
HMAC_SHA1_UpdateKey(&ctx, argv[2], strlen(argv[2]));
HMAC_SHA1_EndKey(&ctx);
i = 3;
} else {
if ((IN = fopen(argv[1], "r")) == NULL) {
perror(argv[0]);
exit(EX_NOINPUT);
}
fd = fileno(IN);
kl = 0;
while ((l = read(fd,buf,BUFLEN)) > 0) {
kl += l;
HMAC_SHA1_UpdateKey(&ctx, buf, l);
}
fclose(IN);
if (kl == 0)
fprintf(stderr, "%s: WARNING: File %s contained no key data. Using null key anyway.\n", argv[0], argv[1]);
HMAC_SHA1_EndKey(&ctx);
i = 2;
}
if (argc == i) {
/* Read data from STDIN */
fd = fileno(stdin);
} else if (argc == (i + 1)) {
/* Read data from FILE */
if ((IN = fopen(argv[i], "r")) == NULL) {
perror(argv[0]);
exit(EX_NOINPUT);
}
fd = fileno(IN);
} else {
usage(argv[0]);
}
HMAC_SHA1_StartMessage(&ctx);
kl = 0;
while ((l = read(fd,buf,BUFLEN)) > 0) {
kl += l;
HMAC_SHA1_UpdateMessage(&ctx, buf, l);
}
if (argc == (i + 1))
fclose(IN);
HMAC_SHA1_EndMessage(buf, &ctx);
hexout(buf, HMAC_SHA1_DIGEST_LENGTH);
return 1;
}