We currently have a MD5 driver, but no SHA1 driver, even though
we have SHA1 as part of libmd. So I took md5.c from /usr/src/sbin/md5
and made sha1.c as well as a respective man page. Attached is the
source file, the manual page for it, as well as a makefile.

Hope this is useful and makes its way into the tree. Md5 has some
questionable attacks against it, and Schneier claims that
sha is resillient to such attacks.

mike
/*
 * Derived from:
 *
 * MDDRIVER.C - test driver for MD2, MD4 and MD5
 */

/*
 * Further dervied from the FreeBSD md5 driver program.
 * Converted to generate SHA 160 bit hashes.
 * Mike Wiacek <[EMAIL PROTECTED]> 12/14/2001
 */

#ifndef lint
static const char rcsid[] =
  "$FreeBSD$";
#endif /* not lint */

#include <sys/types.h>
#include <err.h>
#include <sha.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

/*
 * Length of test block, number of test blocks.
 */
#define TEST_BLOCK_LEN 10000
#define TEST_BLOCK_COUNT 100000

int qflag;
int rflag;

static void SHAString(const char *);
static void SHATimeTrial(void);
static void SHATestSuite(void);
static void SHAFilter(int);
static void usage(void);

/* Main driver.

Arguments (may be any combination):
  -sstring - digests string
  -t       - runs time trial
  -x       - runs test script
  filename - digests file
  (none)   - digests standard input
 */

main(int argc, char *argv[])
{
        int     ch;
        char   *p;
        unsigned char   buf[41] = {0};

        while ((ch = getopt(argc, argv, "pqrs:tx")) != -1)
                switch (ch) {
                case 'p':
                        SHAFilter(1);
                        break;
                case 'q':
                        qflag = 1;
                        break;
                case 'r':
                        rflag = 1;
                        break;
                case 's':
                        SHAString(optarg);
                        break;
                case 't':
                        SHATimeTrial();
                        break;
                case 'x':
                        SHATestSuite();
                        break;
                default:
                        usage();
                }
        argc -= optind;
        argv += optind;

        if (*argv) {
                do {
                        p = SHA1_File(*argv, buf);
                        if (!p)
                                warn("%s", *argv);
                        else
                                if (qflag)
                                        printf("%s\n", p);
                                else if (rflag)
                                        printf("%s %s\n", p, *argv);
                                else
                                        printf("SHA1 (%s) = %s\n", *argv, p);
                } while (*++argv);
        } else if (optind == 1 || qflag || rflag)
                SHAFilter(0);

        return (0);
}
/*
 * Digests a string and prints the result.
 */
static void
SHAString(const char *string)
{
        size_t len = strlen(string);
        unsigned char buf[41] = {0};

        if (qflag)
                printf("%s\n", SHA1_Data(string, len, buf));
        else if (rflag)
                printf("%s \"%s\"\n", SHA1_Data(string, len, buf), string);
        else
                printf("SHA1 (\"%s\") = %s\n", string, SHA1_Data(string, len, buf));
}
/*
 * Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte blocks.
 */
static void
SHATimeTrial(void)
{
        SHA_CTX context;
        time_t  endTime, startTime;
        unsigned char block[TEST_BLOCK_LEN];
        unsigned int i;
        char   *p;
        unsigned char buf[41] = {0};


        printf
            ("SHA1 time trial. Digesting %d %d-byte blocks ...",
            TEST_BLOCK_COUNT, TEST_BLOCK_LEN);
        fflush(stdout);

        /* Initialize block */
        for (i = 0; i < TEST_BLOCK_LEN; i++)
                block[i] = (unsigned char) (i & 0xff);

        /* Start timer */
        time(&startTime);

        /* Digest blocks */
        SHA_Init(&context);
        for (i = 0; i < TEST_BLOCK_COUNT; i++)
                SHA_Update(&context, block, TEST_BLOCK_LEN);
        p = SHA1_End(&context,buf);

        /* Stop timer */
        time(&endTime);

        printf(" done\n");
        printf("Digest = %s", p);
        printf("\nTime = %ld seconds\n", (long) (endTime - startTime));
        /* Be careful that endTime-startTime is not zero. (Bug fix from Ric
         * Anderson, [EMAIL PROTECTED]) */
        printf
            ("Speed = %ld bytes/second\n",
            (long) TEST_BLOCK_LEN * (long) TEST_BLOCK_COUNT / ((endTime - startTime) 
!= 0 ? (endTime - startTime) : 1));
}
/*
 * Digests a reference suite of strings and prints the results.
 */
static void
SHATestSuite(void)
{

        printf("SHA1 test suite:\n");

        SHAString("");
        SHAString("a");
        SHAString("abc");
        SHAString("message digest");
        SHAString("abcdefghijklmnopqrstuvwxyz");
        SHAString
            ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
        SHAString
            ("1234567890123456789012345678901234567890\
1234567890123456789012345678901234567890");
}

/*
 * Digests the standard input and prints the result.
 */
static void
SHAFilter(int tee)
{
        SHA_CTX context;
        unsigned int len;
        unsigned char buffer[BUFSIZ];
        unsigned char buf[41] = {0};

        SHA_Init(&context);
        while ((len = fread(buffer, 1, BUFSIZ, stdin))) {
                if (tee && len != fwrite(buffer, 1, len, stdout))
                        err(1, "stdout");
                SHA_Update(&context, buffer, len);
        }
        printf("%s\n", SHA1_End(&context,buf));
}

static void
usage(void)
{

        fprintf(stderr, "usage: sha1 [-pqrtx] [-s string] [files ...]\n");
        exit(1);
}
.\" $FreeBSD$
.Dd February 14, 1994
.Dt SHA1 1
.Os
.Sh NAME
.Nm sha1
.Nd calculate a message-digest fingerprint (checksum) for a file
.Sh SYNOPSIS
.Nm
.Op Fl pqrtx
.Op Fl s Ar string
.Op Ar
.Sh DESCRIPTION
.Nm Sha1
takes as input a message of arbitrary length and produces
as output a 160-bit
.Dq fingerprint
or
.Dq message digest
of the input, using the National Institute of Standards and Technology's Secure
Hash Algorithm. 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.
.Pp
The following options may be used in any combination and must
precede any files named on the command line.  The SHA1
sum 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 SHA1 sum to stdout.
.It Fl q
Quiet mode - only the SHA1 sum is printed out.  Overrides the
.Fl r
option.
.It Fl r
Reverses the format of the output.  This helps with visual diffs.  Does nothing
when combined with the
.Fl ptx
options.
.It Fl t
Run a built-in time trial.
.It Fl x
Run a built-in test script.
.El
.Sh SEE ALSO
.Xr cksum 1
.Xr md5 1
.Rs
.%A D. Eastlake
.%T US Secure Hash Algorithm 1 (SHA1)
.%O RFC3174
.Re
#       @(#)Makefile    8.1 (Berkeley) 6/9/93
# $FreeBSD$

PROG=   sha1

LDADD+= -lmd -g
DPADD+= ${LIBMD}

.include <bsd.prog.mk>

Reply via email to