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:
parent
79ef6aa9d1
commit
cb49d42b60
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=130351
@ -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>
|
||||
|
@ -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 .
|
||||
|
181
sbin/md5/md5.c
181
sbin/md5/md5.c
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user