Add sha1 and rmd160 checksum tools.

Since the algorithms are already supported in libmd,
the size increase is small when a dynamic root is used.

Approved by:	joerg, ru
MFC after:	2 weeks
This commit is contained in:
Oliver Eikemeier 2004-06-11 16:07:02 +00:00
parent 79ef6aa9d1
commit cb49d42b60
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=130351
3 changed files with 206 additions and 67 deletions

View File

@ -3,7 +3,16 @@
PROG= md5
LDADD= -lmd
LINKS= ${BINDIR}/md5 ${BINDIR}/rmd160 \
${BINDIR}/md5 ${BINDIR}/sha1
MLINKS= md5.1 rmd160.1 \
md5.1 sha1.1
WARNS?= 6
WFORMAT?= 1
DPADD= ${LIBMD}
LDADD= -lmd
.include <bsd.prog.mk>

View File

@ -1,20 +1,30 @@
.\" $FreeBSD$
.Dd February 14, 1994
.Dd June 6, 2004
.Dt MD5 1
.Os
.Sh NAME
.Nm md5
.Nm md5 , sha1 , rmd160
.Nd calculate a message-digest fingerprint (checksum) for a file
.Sh SYNOPSIS
.Nm
.Nm md5
.Op Fl pqrtx
.Op Fl s Ar string
.Op Ar
.Nm sha1
.Op Fl pqrtx
.Op Fl s Ar string
.Op Ar
.Nm rmd160
.Op Fl pqrtx
.Op Fl s Ar string
.Op Ar
.Sh DESCRIPTION
The
.Nm
utility takes as input a message of arbitrary length and produces
as output a 128-bit
The
.Nm md5 , sha1
and
.Nm rmd160
utilities take as input a message of arbitrary length and produce as
output a
.Dq fingerprint
or
.Dq message digest
@ -22,17 +32,23 @@ of the input.
It is conjectured that it is computationally infeasible to
produce two messages having the same message digest, or to produce any
message having a given prespecified target message digest.
The MD5 algorithm is intended for digital signature applications, where a
The
.Tn MD5 , SHA-1
and
.Tn RIPEMD-160
algorithms are intended for digital signature applications, where a
large file must be
.Dq compressed
in a secure manner before being encrypted with a private
(secret)
key under a public-key cryptosystem such as
.Em RSA .
.Tn RSA .
.Pp
MD5 has not yet (2001-09-03) been broken, but sufficient attacks have been
.Tn MD5
has not yet (2001-09-03) been broken, but sufficient attacks have been
made that its security is in some doubt.
The attacks on MD5
The attacks on
.Tn MD5
are in the nature of finding
.Dq collisions
\(em that is, multiple
@ -41,17 +57,16 @@ to be able to determine the exact original input given a hash value.
.Pp
The following options may be used in any combination and must
precede any files named on the command line.
The MD5
sum of each file listed on the command line is printed after the options
are processed.
The hexadecimal checksum of each file listed on the command line is printed
after the options are processed.
.Bl -tag -width indent
.It Fl s Ar string
Print a checksum of the given
.Ar string .
.It Fl p
Echo stdin to stdout and appends the MD5 sum to stdout.
Echo stdin to stdout and append the checksum to stdout.
.It Fl q
Quiet mode - only the MD5 sum is printed out.
Quiet mode - only the checksum is printed out.
Overrides the
.Fl r
option.
@ -69,16 +84,44 @@ Run a built-in test script.
.El
.Sh DIAGNOSTICS
The
.Nm
utility exits 0 on success,
.Nm md5 , sha1
and
.Nm rmd160
utilities exit 0 on success,
and 1 if at least one of the input files could not be read.
.Sh SEE ALSO
.Xr cksum 1
.Xr cksum 1 ,
.Xr md5 3 ,
.Xr ripemd 3 ,
.Xr sha 3
.Rs
.%A R. Rivest
.%T The MD5 Message-Digest Algorithm
.%O RFC1321
.Re
.Rs
.%A J. Burrows
.%T The Secure Hash Standard
.%O FIPS PUB 180-1
.Re
.Rs
.%A D. Eastlake and P. Jones
.%T US Secure Hash Algorithm 1
.%O RFC 3174
.Re
.Pp
RIPEMD-160 is part of the ISO draft standard
.Qq ISO/IEC DIS 10118-3
on dedicated hash functions.
.Pp
Secure Hash Standard (SHS):
.Pa http://csrc.nist.gov/cryptval/shs.html .
.Pp
The RIPEMD-160 page:
.Pa http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html .
.Sh ACKNOWLEDGMENTS
This program is placed in the public domain for free general use by
RSA Data Security.
.Pp
Support for SHA-1 and RIPEMD-160 has been added by
.An Oliver Eikemeier Aq eik@FreeBSD.org .

View File

@ -25,6 +25,8 @@ __FBSDID("$FreeBSD$");
#include <sys/resource.h>
#include <err.h>
#include <md5.h>
#include <ripemd.h>
#include <sha.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -36,16 +38,66 @@ __FBSDID("$FreeBSD$");
*/
#define TEST_BLOCK_LEN 10000
#define TEST_BLOCK_COUNT 100000
#define MDTESTCOUNT 8
int qflag;
int rflag;
int sflag;
static void MDString(const char *);
static void MDTimeTrial(void);
static void MDTestSuite(void);
static void MDFilter(int);
static void usage(void);
typedef void (DIGEST_Init)(void *);
typedef void (DIGEST_Update)(void *, const unsigned char *, size_t);
typedef char *(DIGEST_End)(void *, char *);
extern const char *MD5TestOutput[MDTESTCOUNT];
extern const char *SHA1_TestOutput[MDTESTCOUNT];
extern const char *RIPEMD160_TestOutput[MDTESTCOUNT];
typedef struct Algorithm_t {
const char *progname;
const char *name;
const char *(*TestOutput)[MDTESTCOUNT];
DIGEST_Init *Init;
DIGEST_Update *Update;
DIGEST_End *End;
char *(*Data)(const unsigned char *, unsigned int, char *);
char *(*File)(const char *, char *);
} Algorithm_t;
static void MD5_Update(MD5_CTX *, const unsigned char *, size_t);
static void MDString(Algorithm_t *, const char *);
static void MDTimeTrial(Algorithm_t *);
static void MDTestSuite(Algorithm_t *);
static void MDFilter(Algorithm_t *, int);
static void usage(Algorithm_t *);
typedef union {
MD5_CTX md5;
SHA1_CTX sha1;
RIPEMD160_CTX ripemd160;
} DIGEST_CTX;
/* max(MD5_DIGEST_LENGTH, SHA_DIGEST_LENGTH, RIPEMD160_DIGEST_LENGTH)*2+1 */
#define HEX_DIGEST_LENGTH 41
/* algorithm function table */
struct Algorithm_t Algorithm[] = {
{ "md5", "MD5", &MD5TestOutput, (DIGEST_Init*)&MD5Init,
(DIGEST_Update*)&MD5_Update, (DIGEST_End*)&MD5End,
&MD5Data, &MD5File },
{ "sha1", "SHA1", &SHA1_TestOutput, (DIGEST_Init*)&SHA1_Init,
(DIGEST_Update*)&SHA1_Update, (DIGEST_End*)&SHA1_End,
&SHA1_Data, &SHA1_File },
{ "rmd160", "RMD160", &RIPEMD160_TestOutput,
(DIGEST_Init*)&RIPEMD160_Init, (DIGEST_Update*)&RIPEMD160_Update,
(DIGEST_End*)&RIPEMD160_End, &RIPEMD160_Data, &RIPEMD160_File }
};
static void
MD5_Update(MD5_CTX *c, const unsigned char *data, size_t len)
{
MD5Update(c, data, len);
}
/* Main driver.
@ -61,14 +113,28 @@ main(int argc, char *argv[])
{
int ch;
char *p;
char buf[33];
char buf[HEX_DIGEST_LENGTH];
int failed;
unsigned digest;
const char* progname;
if ((progname = strrchr(argv[0], '/')) == NULL)
progname = argv[0];
else
progname++;
for (digest = 0; digest < sizeof(Algorithm)/sizeof(*Algorithm); digest++)
if (strcasecmp(Algorithm[digest].progname, progname) == 0)
break;
if (Algorithm[digest].progname == NULL)
digest = 0;
failed = 0;
while ((ch = getopt(argc, argv, "pqrs:tx")) != -1)
switch (ch) {
case 'p':
MDFilter(1);
MDFilter(&Algorithm[digest], 1);
break;
case 'q':
qflag = 1;
@ -78,23 +144,23 @@ main(int argc, char *argv[])
break;
case 's':
sflag = 1;
MDString(optarg);
MDString(&Algorithm[digest], optarg);
break;
case 't':
MDTimeTrial();
MDTimeTrial(&Algorithm[digest]);
break;
case 'x':
MDTestSuite();
MDTestSuite(&Algorithm[digest]);
break;
default:
usage();
usage(&Algorithm[digest]);
}
argc -= optind;
argv += optind;
if (*argv) {
do {
p = MD5File(*argv, buf);
p = Algorithm[digest].File(*argv, buf);
if (!p) {
warn("%s", *argv);
failed++;
@ -104,11 +170,11 @@ main(int argc, char *argv[])
else if (rflag)
printf("%s %s\n", p, *argv);
else
printf("MD5 (%s) = %s\n", *argv, p);
printf("%s (%s) = %s\n", Algorithm[digest].name, *argv, p);
}
} while (*++argv);
} else if (!sflag && (optind == 1 || qflag || rflag))
MDFilter(0);
MDFilter(&Algorithm[digest], 0);
if (failed != 0)
return (1);
@ -119,35 +185,35 @@ main(int argc, char *argv[])
* Digests a string and prints the result.
*/
static void
MDString(const char *string)
MDString(Algorithm_t *alg, const char *string)
{
size_t len = strlen(string);
char buf[33];
char buf[HEX_DIGEST_LENGTH];
if (qflag)
printf("%s\n", MD5Data(string, len, buf));
printf("%s\n", alg->Data(string, len, buf));
else if (rflag)
printf("%s \"%s\"\n", MD5Data(string, len, buf), string);
printf("%s \"%s\"\n", alg->Data(string, len, buf), string);
else
printf("MD5 (\"%s\") = %s\n", string, MD5Data(string, len, buf));
printf("%s (\"%s\") = %s\n", alg->name, string, alg->Data(string, len, buf));
}
/*
* Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte blocks.
*/
static void
MDTimeTrial(void)
MDTimeTrial(Algorithm_t *alg)
{
MD5_CTX context;
DIGEST_CTX context;
struct rusage before, after;
struct timeval total;
float seconds;
unsigned char block[TEST_BLOCK_LEN];
unsigned int i;
char *p, buf[33];
char *p, buf[HEX_DIGEST_LENGTH];
printf
("MD5 time trial. Digesting %d %d-byte blocks ...",
TEST_BLOCK_COUNT, TEST_BLOCK_LEN);
("%s time trial. Digesting %d %d-byte blocks ...",
alg->name, TEST_BLOCK_COUNT, TEST_BLOCK_LEN);
fflush(stdout);
/* Initialize block */
@ -158,10 +224,10 @@ MDTimeTrial(void)
getrusage(0, &before);
/* Digest blocks */
MD5Init(&context);
alg->Init(&context);
for (i = 0; i < TEST_BLOCK_COUNT; i++)
MD5Update(&context, block, TEST_BLOCK_LEN);
p = MD5End(&context,buf);
alg->Update(&context, block, TEST_BLOCK_LEN);
p = alg->End(&context, buf);
/* Stop timer */
getrusage(0, &after);
@ -179,9 +245,7 @@ MDTimeTrial(void)
* Digests a reference suite of strings and prints the results.
*/
#define MD5TESTCOUNT 8
char *MDTestInput[] = {
const char *MDTestInput[MDTESTCOUNT] = {
"",
"a",
"abc",
@ -189,10 +253,11 @@ char *MDTestInput[] = {
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
"12345678901234567890123456789012345678901234567890123456789012345678901234567890",
"MD5 has not yet (2001-09-03) been broken, but sufficient attacks have been made that its security is in some doubt"
"MD5 has not yet (2001-09-03) been broken, but sufficient attacks have been made \
that its security is in some doubt"
};
char *MDTestOutput[MD5TESTCOUNT] = {
const char *MD5TestOutput[MDTESTCOUNT] = {
"d41d8cd98f00b204e9800998ecf8427e",
"0cc175b9c0f1b6a831c399e269772661",
"900150983cd24fb0d6963f7d28e17f72",
@ -203,17 +268,39 @@ char *MDTestOutput[MD5TESTCOUNT] = {
"b50663f41d44d92171cb9976bc118538"
};
const char *SHA1_TestOutput[MDTESTCOUNT] = {
"da39a3ee5e6b4b0d3255bfef95601890afd80709",
"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
"a9993e364706816aba3e25717850c26c9cd0d89d",
"c12252ceda8be8994d5fa0290a47231c1d16aae3",
"32d10c7b8cf96570ca04ce37f2a19d84240d3a89",
"761c457bf73b14d27e9e9265c46f4b4dda11f940",
"50abf5706a150990a08b2c5ea40fa0e585554732",
"18eca4333979c4181199b7b4fab8786d16cf2846"
};
const char *RIPEMD160_TestOutput[MDTESTCOUNT] = {
"9c1185a5c5e9fc54612808977ee8f548b2258d31",
"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe",
"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc",
"5d0689ef49d2fae572b881b123a85ffa21595f36",
"f71c27109c692c1b56bbdceb5b9d2865b3708dbc",
"b0e20b6e3116640286ed3a87a5713079b21f5189",
"9b752e45573d4b39f4dbd3323cab82bf63326bfb",
"5feb69c6bf7c29d95715ad55f57d8ac5b2b7dd32"
};
static void
MDTestSuite(void)
MDTestSuite(Algorithm_t *alg)
{
int i;
char buffer[33];
char buffer[HEX_DIGEST_LENGTH];
printf("MD5 test suite:\n");
for (i = 0; i < MD5TESTCOUNT; i++) {
MD5Data(MDTestInput[i], strlen(MDTestInput[i]), buffer);
printf("MD5 (\"%s\") = %s", MDTestInput[i], buffer);
if (strcmp(buffer, MDTestOutput[i]) == 0)
printf("%s test suite:\n", alg->name);
for (i = 0; i < MDTESTCOUNT; i++) {
(*alg->Data)(MDTestInput[i], strlen(MDTestInput[i]), buffer);
printf("%s (\"%s\") = %s", alg->name, MDTestInput[i], buffer);
if (strcmp(buffer, (*alg->TestOutput)[i]) == 0)
printf(" - verified correct\n");
else
printf(" - INCORRECT RESULT!\n");
@ -224,26 +311,26 @@ MDTestSuite(void)
* Digests the standard input and prints the result.
*/
static void
MDFilter(int tee)
MDFilter(Algorithm_t *alg, int tee)
{
MD5_CTX context;
DIGEST_CTX context;
unsigned int len;
unsigned char buffer[BUFSIZ];
char buf[33];
char buf[HEX_DIGEST_LENGTH];
MD5Init(&context);
alg->Init(&context);
while ((len = fread(buffer, 1, BUFSIZ, stdin))) {
if (tee && len != fwrite(buffer, 1, len, stdout))
err(1, "stdout");
MD5Update(&context, buffer, len);
alg->Update(&context, buffer, len);
}
printf("%s\n", MD5End(&context,buf));
printf("%s\n", alg->End(&context, buf));
}
static void
usage(void)
usage(Algorithm_t *alg)
{
fprintf(stderr, "usage: md5 [-pqrtx] [-s string] [files ...]\n");
fprintf(stderr, "usage: %s [-pqrtx] [-s string] [files ...]\n", alg->progname);
exit(1);
}