if (printResults == PRINTTEXT)
printf("\nError %d. Should be %d.\n", err, shaNull);
if ((printPassFail == PRINTPASSFAIL) ||
((printPassFail == PRINTFAIL) && (err != shaNull)))
printf("%s sha null: %s\n", hashes[hashno].name,
(err == shaNull) ? "PASSED" : "FAILED");
}
}
/* replace a hex string in place with its value */
int unhexStr(char *hexstr)
{
char *o = hexstr;
int len = 0, nibble1 = 0, nibble2 = 0;
if (!hexstr) return 0;
for ( ; *hexstr; hexstr++) {
if (isalpha((int)(unsigned char)(*hexstr))) {
nibble1 = tolower(*hexstr) - ’a’ + 10;
} else if (isdigit((int)(unsigned char)(*hexstr))) {
nibble1 = *hexstr - ’0’;
} else {
printf("\nError: bad hex character ’%c’\n", *hexstr);
}
if (!*++hexstr) break;
if (isalpha((int)(unsigned char)(*hexstr))) {
nibble2 = tolower(*hexstr) - ’a’ + 10;
} else if (isdigit((int)(unsigned char)(*hexstr))) {
nibble2 = *hexstr - ’0’;
} else {
printf("\nError: bad hex character ’%c’\n", *hexstr);
}
*o++ = (char)((nibble1 << 4) | nibble2);
len++;
}
return len;
}
int main(int argc, char **argv)
{
int i, err;
int loopno, loopnohigh = 1;
int hashno, hashnolow = 0, hashnohigh = HASHCOUNT - 1;
int testno, testnolow = 0, testnohigh;
int ntestnohigh = 0;
int printResults = PRINTTEXT;
int printPassFail = 1;
int checkErrors = 0;
char *hashstr = 0;
int hashlen = 0;
const char *resultstr = 0;
char *randomseedstr = 0;
int runHmacTests = 0;
char *hmacKey = 0;
int hmaclen = 0;
int randomcount = RANDOMCOUNT;
const char *hashfilename = 0;
const char *hashFilename = 0;
int extrabits = 0, numberExtrabits = 0;
int strIsHex = 0;
while ((i = xgetopt(argc, argv, "b:B:ef:F:h:Hk:l:mpPr:R:s:S:t:wxX"))
!= -1)
switch (i) {
case ’b’: extrabits = strtol(xoptarg, 0, 0); break;
case ’B’: numberExtrabits = atoi(xoptarg); break;
case ’e’: checkErrors = 1; break;
case ’f’: hashfilename = xoptarg; break;
case ’F’: hashFilename = xoptarg; break;
case ’h’: hashnolow = hashnohigh = findhash(argv[0], xoptarg);
break;
case ’H’: strIsHex = 1; break;
case ’k’: hmacKey = xoptarg; hmaclen = strlen(xoptarg); break;
case ’l’: loopnohigh = atoi(xoptarg); break;
case ’m’: runHmacTests = 1; break;
case ’P’: printPassFail = 0; break;
case ’p’: printResults = PRINTNONE; break;
case ’R’: randomcount = atoi(xoptarg); break;
case ’r’: randomseedstr = xoptarg; break;
case ’s’: hashstr = xoptarg; hashlen = strlen(hashstr); break;
case ’S’: resultstr = xoptarg; break;
case ’t’: testnolow = ntestnohigh = atoi(xoptarg) - 1; break;
case ’w’: printResults = PRINTRAW; break;
case ’x’: printResults = PRINTHEX; break;
case ’X’: printPassFail = 2; break;
default: usage(argv[0]);
}
if (strIsHex) {
hashlen = unhexStr(hashstr);
unhexStr(randomseedstr);
hmaclen = unhexStr(hmacKey);
}
testnohigh = (ntestnohigh != 0) ? ntestnohigh:
runHmacTests ? (HMACTESTCOUNT-1) : (TESTCOUNT-1);
if ((testnolow < 0) ||
(testnohigh >= (runHmacTests ? HMACTESTCOUNT : TESTCOUNT)) ||
(hashnolow < 0) || (hashnohigh >= HASHCOUNT) ||
(hashstr && (testnolow == testnohigh)) ||
(randomcount < 0) ||
(resultstr && (!hashstr && !hashfilename && !hashFilename)) ||
((runHmacTests || hmacKey) && randomseedstr) ||
(hashfilename && hashFilename))
usage(argv[0]);
/*
* Perform SHA/HMAC tests
*/
for (hashno = hashnolow; hashno <= hashnohigh; ++hashno) {
if (printResults == PRINTTEXT)
printf("Hash %s\n", hashes[hashno].name);
err = shaSuccess;
for (loopno = 1; (loopno <= loopnohigh) && (err == shaSuccess);
++loopno) {
if (hashstr)
err = hash(0, loopno, hashno, hashstr, hashlen, 1,
numberExtrabits, extrabits, (const unsigned char *)hmacKey,
hmaclen, resultstr, hashes[hashno].hashsize, printResults,
printPassFail);
else if (randomseedstr)
randomtest(hashno, randomseedstr, hashes[hashno].hashsize, 0,
randomcount, printResults, printPassFail);
else if (hashfilename)
err = hashfile(hashno, hashfilename, extrabits,
numberExtrabits, 0,
(const unsigned char *)hmacKey, hmaclen,
resultstr, hashes[hashno].hashsize,
printResults, printPassFail);
else if (hashFilename)
err = hashfile(hashno, hashFilename, extrabits,
numberExtrabits, 1,
(const unsigned char *)hmacKey, hmaclen,
resultstr, hashes[hashno].hashsize,
printResults, printPassFail);
else /* standard tests */ {
for (testno = testnolow;
(testno <= testnohigh) && (err == shaSuccess); ++testno) {
if (runHmacTests) {
err = hash(testno, loopno, hashno,
hmachashes[testno].dataarray[hashno] ?
hmachashes[testno].dataarray[hashno] :
hmachashes[testno].dataarray[1] ?
hmachashes[testno].dataarray[1] :
hmachashes[testno].dataarray[0],
hmachashes[testno].datalength[hashno] ?
hmachashes[testno].datalength[hashno] :
hmachashes[testno].datalength[1] ?
hmachashes[testno].datalength[1] :
hmachashes[testno].datalength[0],
1, 0, 0,
(const unsigned char *)(
hmachashes[testno].keyarray[hashno] ?
hmachashes[testno].keyarray[hashno] :
hmachashes[testno].keyarray[1] ?
hmachashes[testno].keyarray[1] :
hmachashes[testno].keyarray[0]),
hmachashes[testno].keylength[hashno] ?
hmachashes[testno].keylength[hashno] :
hmachashes[testno].keylength[1] ?
hmachashes[testno].keylength[1] :
hmachashes[testno].keylength[0],
hmachashes[testno].resultarray[hashno],
hmachashes[testno].resultlength[hashno],
printResults, printPassFail);
} else {
err = hash(testno, loopno, hashno,
hashes[hashno].tests[testno].testarray,
hashes[hashno].tests[testno].length,
hashes[hashno].tests[testno].repeatcount,
hashes[hashno].tests[testno].numberExtrabits,
hashes[hashno].tests[testno].extrabits, 0, 0,
hashes[hashno].tests[testno].resultarray,
hashes[hashno].hashsize,
printResults, printPassFail);
}
}
if (!runHmacTests) {
randomtest(hashno, hashes[hashno].randomtest,
hashes[hashno].hashsize, hashes[hashno].randomresults,
RANDOMCOUNT, printResults, printPassFail);
}
}
}
}
/* Test some error returns */
if (checkErrors) {
testErrors(hashnolow, hashnohigh, printResults, printPassFail);
}
return 0;
}
/*
* Compare two strings, case independently.
* Equivalent to strcasecmp() found on some systems.
*/
int scasecmp(const char *s1, const char *s2)
{
for (;;) {
char u1 = tolower(*s1++);
char u2 = tolower(*s2++);
if (u1 != u2)
return u1 - u2;
if (u1 == ’\0’)
return 0;
}
}
/*
* This is a copy of getopt provided for those systems that do not
* have it. The name was changed to xgetopt to not conflict on those
* systems that do have it. Similarly, optarg, optind and opterr
* were renamed to xoptarg, xoptind and xopterr.
*
* Copyright 1990, 1991, 1992 by the Massachusetts Institute of
* Technology and UniSoft Group Limited.
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear in
* supporting documentation, and that the names of MIT and UniSoft not
* be used in advertising or publicity pertaining to distribution of
* the software without specific, written prior permission. MIT and
* UniSoft make no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* $XConsortium: getopt.c,v 1.2 92/07/01 11:59:04 rws Exp $
* NB: Reformatted to match above style.
*/
char *xoptarg;
int xoptind = 1;
int xopterr = 1;
static int xgetopt(int argc, char **argv, const char *optstring)
{
static int avplace;
char *ap;
char *cp;
int c;
if (xoptind >= argc)
return EOF;
ap = argv[xoptind] + avplace;
/* At beginning of arg but not an option */
if (avplace == 0) {
if (ap[0] != ’-’)
return EOF;
else if (ap[1] == ’-’) {
/* Special end of options option */
xoptind++;
return EOF;
} else if (ap[1] == ’\0’)
return EOF; /* single ’-’ is not allowed */
}
/* Get next letter */
avplace++;
c = *++ap;
cp = strchr(optstring, c);
if (cp == NULL || c == ’:’) {
if (xopterr)
fprintf(stderr, "Unrecognised option -- %c\n", c);
return ’?’;
}
if (cp[1] == ’:’) {
/* There should be an option arg */
avplace = 0;
if (ap[1] == ’\0’) {
/* It is a separate arg */
if (++xoptind >= argc) {
if (xopterr)
fprintf(stderr, "Option requires an argument\n");
return ’?’;
}
xoptarg = argv[xoptind++];
} else {
/* is attached to option letter */
xoptarg = ap + 1;
++xoptind;
}
} else {
/* If we are out of letters then go to next arg */
if (ap[1] == ’\0’) {
++xoptind;
avplace = 0;
}
xoptarg = NULL;
}
return c;
}
9. Security Considerations
This document is intended to provides the Internet community
convenient access to source code that implements the United States of
America Federal Information Processing Standard Secure Hash
Algorithms (SHAs) [FIPS180-2] and HMACs based upon these one-way hash
functions. See license in Section 1.1. No independent assertion of
the security of this hash function by the authors for any particular
use is intended.
10. Normative References
[FIPS180-2] "Secure Hash Standard", United States of America,
National Institute of Standards and Technology, Federal
Information Processing Standard (FIPS) 180-2,
http://csrc.nist.gov/publications/fips/fips180-2/
fips180-2withchangenotice.pdf.
[RFC2104] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-
Hashing for Message Authentication", RFC 2104, February
1997.
11. Informative References
[RFC2202] Cheng, P. and R. Glenn, "Test Cases for HMAC-MD5 and
HMAC-SHA-1", RFC 2202, September 1997.
[RFC3174] Eastlake 3rd, D. and P. Jones, "US Secure Hash Algorithm
1 (SHA1)", RFC 3174, September 2001.
[RFC3874] Housley, R., "A 224-bit One-way Hash Function: SHA-224",
RFC 3874, September 2004.
[RFC4086] Eastlake, D., 3rd, Schiller, J., and S. Crocker,
"Randomness Requirements for Security", BCP 106, RFC
4086, June 2005.
[RFC4231] Nystrom, M., "Identifiers and Test Vectors for HMAC-SHA-
224, HMAC-SHA-256, HMAC-SHA-384, and HMAC-SHA-512", RFC
4231, December 2005.
[SHAVS] "The Secure Hash Algorithm Validation System (SHAVS)",
http://csrc.nist.gov/cryptval/shs/SHAVS.pdf.
Authors’ Addresses
Donald E. Eastlake, 3rd
Motorola Laboratories
155 Beaver Street
Milford, MA 01757 USA
Phone: +1-508-786-7554 (w)
EMail: donald.eastlake@motorola.com
Tony Hansen
AT&T Laboratories
200 Laurel Ave.
Middletown, NJ 07748 USA
Phone: +1-732-420-8934 (w)
EMail: tony+shs@maillennium.att.com
Full Copyright Statement
Copyright (C) The Internet Society (2006).
This document is subject to the rights, licenses and restrictions
contained in BCP 78, and except as set forth therein, the authors
retain all their rights.
This document and the information contained herein are provided on an
"AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
Intellectual Property
The IETF takes no position regarding the validity or scope of any
Intellectual Property Rights or other rights that might be claimed to
pertain to the implementation or use of the technology described in
this document or the extent to which any license under such rights
might or might not be available; nor does it represent that it has
made any independent effort to identify any such rights. Information
on the procedures with respect to rights in RFC documents can be
found in BCP 78 and BCP 79.
Copies of IPR disclosures made to the IETF Secretariat and any
assurances of licenses to be made available, or the result of an
attempt made to obtain a general license or permission for the use of
such proprietary rights by implementers or users of this
specification can be obtained from the IETF on-line IPR repository at
http://www.ietf.org/ipr.
The IETF invites any interested party to bring to its attention any
copyrights, patents or patent applications, or other proprietary
rights that may cover technology that may be required to implement
this standard. Please address the information to the IETF at
ietf-ipr@ietf.org.
Acknowledgement
Funding for the RFC Editor function is provided by the IETF
Administrative Support Activity (IASA).