v21i019: Snefru hash and netnews validation programs, Part01/04

Rich Salz rsalz at bbn.com
Fri Mar 23 04:47:04 AEST 1990


Submitted-by: Rich $alz <rsalz at bbn.com>
Posting-number: Volume 21, Issue 19
Archive-name: snefru/part01

This is my revision of Ralph Merkle's SNEFRU program.  Snefru is a one-way
hash algorithm:  given some input text, Snefru will come up with a single
number such that no two texts will hash down to the same number.  In this
way, Snefru can tell you whether an article has been corrupted, but not if
it is authentic or not -- think of it as a super-strong checksum.

Starting with this posting, I am going to be using hashnews on all my
c.s.u articles.  While I don't think that this is worth doing for most
general Usenix articles, I think it will be an interesting experiment for
archives.

I completely rewrote and reorganized the code that Ralph has made
available.  For example, I split the comments out into manual pages, and
put all the tests out into a separate program.  What I'm making available
is a derived work, and therefore must be distributed under the same terms
as Ralph's original code.  Thanks to him and Xerox for making his work
available.  Some of the programs and manual pages are my original work,
and therefore don't contain the Xerox copyright.  They are in the public
domain, and feel free to do what you want with them.

This code needs a 32bit machine; good luck if you've only got 16 bits!

To compile, edit the Makefile if you use strchr/strrchr rather than
index/rindex.  Also edit snefru.c to determine the byte order of your
machine.  Once that's done, do "make tests" to verify the output.  If you
get wrong answers, the first thing to suspect is the byte order.

Enjoy,
	Rich $alz <rsalz at bbn.com>

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 4)."
# Contents:  HISTORY MANIFEST Makefile README TestArticle checkhash.1
#   checkhash.c hashn.c hashnews.1 hashnews.c patchlevel.h pipeit.c
#   snefru.1 snefru.c snefru.h tests.sh
# Wrapped by rsalz at litchi.bbn.com on Thu Mar 22 13:36:36 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'HISTORY' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'HISTORY'\"
else
echo shar: Extracting \"'HISTORY'\" \(4975 characters\)
sed "s/^X//" >'HISTORY' <<'END_OF_FILE'
XThis is Snefru, derived from the Xerox Secure Hash Function.
XSnefru is a one-way hash function that provides authentication.
XIt does not provide secrecy.
X
XSnefru is named after a Pharaoh of ancient Egypt.
X
XIt is based on code that is:
X    Copyright (c) Xerox Corporation 1989.  All rights reserved.
X
X    License to copy and use this software is granted provided that it
X    is identified as the 'Xerox Secure Hash Function' in all material
X    mentioning or referencing this software or this hash function.
X
X    License is also granted to make and use derivative works provided
X    that such works are identified as 'derived from the Xerox Secure
X    Hash Function' in all material mentioning or referencing the
X    derived work.
X
X    Xerox Corporation makes no representations concerning either the
X    merchantability of this software or the suitability of this
X    software for any particular purpose.  It is provided "as is"
X    without express or implied warranty of any kind.
X
X    These notices must be retained in any copies of any part of this
X    software.
X
XBased on the reference implementation (no algorithm changes) of
Xversion 2.0, July 31, 1989.  Implementor:  Ralph C. Merkle.
XThis edition is by Rich $alz, <rsalz at bbn.com>.
X$Header: HISTORY,v 1.1 90/03/22 12:57:43 rsalz Exp $
X
X
XREVISION HISTORY
X----------------
XVersion 2.0 is algorithmically different from versions 1.4 and 1.3.
X
XIn particular, version 2.0 makes the following changes:
X1)  The S-boxes in version 2.0 have been computed in accordance with a
X    publicly known algorithm.
X
X2)  The special case handling of inputs shorter than 64 bytes has been
X    deleted.  This special case code offered little performance advantage
X    and increased the complexity of the algorithm.  In addition,
X    Coppersmith noticed a weakness that affected the
X    128-bit-input/128-bit-output version of Snefru (though not the 512-bit
X    input/128-bit or 256-bit output version).
X
X3)  The parameters p0, p1, and p2 have been eliminated.  There are several
X    reasons for this change.  The principle reason is that they increase
X    the complexity both of the code and the conceptual complexity of the
X    hash function, and provide only modest improvement in security.
X
X4)  Because the parameter mechanism was used to distinguish between inputs
X    that differ only in the number of trailing 0 bits, a different
X    mechanism has been adopted.  This new mechanism simply counts the
X    number of bits in the input, and then places this 64-bit bit-count
X    into the rightmost 64-bits of the last block hashed.  A slightly
X    different method of applying the hash also been adopted.
X
X5)  Several people requested a larger output (to provide greater
X    security). Because this will not always be needed, the algorithm was
X    modified to generate either 128 bits or 256 bits of output, depending
X    on a command line option.  Notice that 128 bits of output only
X    provides 64 "real" bits of security (because of square root attacks)
X    and similarly 256 bits of output provides only 128 "real" bits of
X    security. Use of the higher security 256-bit output will slow down the
X    algorithm by about 1/3 (32 bytes per application of Hash512 versus 48
X    bytes per application of Hash512).
X
X    A 128 bit output should provide adequate security for most commercial
X    applications (barring discovery of some unexpected weakness in the
X    algorithm).  Where higher security is desired, the 256-bit output size
X    can be used.
X
X6)  Other non-algorithmic changes have been made to the code, in keeping
X    with various criticisms and comments.
X
XVersion 1.4
X    New wording of the export notice; 1.3 forbids export entirely.
X
XVersion 1.3
X    Fixes a security bug in handling short files (64 bytes or less).  Such
X    files should use the length of the file as a parameter to the hash, to
X    prevent two files of different lengths from producing the same hash
X    value if one file is a prefix of another.  This had been done for long
X    files (greater than 64 bytes in length) but was overlooked for short
X    files.
X
X    Improves the way in which the parameter is mixed into the hash.  In
X    essence, the change mixes in the parameter one more time. Although a
X    similar effect can be achieved by increasing the security parameter by
X    1 (e.g., from 2 to 3) this also increases the amount of computation
X    required by 50%.
X
X    Make some more changes in the notices that accompany the code.
X
XVersion 1.2
X    No changes in the code; only the notices that accompany the code have
X    changed, and some changes in the comments.
X
XVersion 1.1
X    Added the 'convertBytes' to convert an array of 'char' into an array
X    of unsigned long int.  This conversion is a no-op on the SUN and many
X    other computers, but will have an effect on the VAX and computers with
X    'backwards' byte ordering.  It will also SLOW DOWN THE HASH FUNCTION,
X    so it should be removed whenever possible if speed is an issue.
END_OF_FILE
if test 4975 -ne `wc -c <'HISTORY'`; then
    echo shar: \"'HISTORY'\" unpacked with wrong size!
fi
# end of 'HISTORY'
fi
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(1274 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X HISTORY                    1	Revision history.
X MANIFEST                   1	This shipping list.
X Makefile                   1	Make control file.
X README                     1	Installation notes, etc.
X TestArticle                1	Sample input to regression test.
X checkhash.1                1	Manual page for checkhash.
X checkhash.c                1	Check if an article matches its checksum.
X hash512.c                  2	Fast code to hash 512 bytes at a time.
X hashn.c                    1	Hash 2^N bytes at a time.
X hashnews.1                 1	Manual page for hashnews.
X hashnews.c                 1	Put a Snefru checksum in a news article.
X patchlevel.h               1	Misteak recorder
X pipeit.c                   1	Routines to call Snefru as a filter.
X sboxes.c                   4	The S boxes.
X snefru.1                   1	Manual page for Snefru.
X snefru.c                   1	Main driver to hash some input.
X snefru.h                   1	Header file for the package.
X testboxes.c1               3	Program to test the S boxes, part 1.
X testboxes.c2               2	Program to test the S boxes, part 2.
X tests.sh                   1	Script to perform regression tests.
END_OF_FILE
if test 1274 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(2863 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X##
X##  This is Snefru, derived from the Xerox Secure Hash Function.
X##  Snefru is a one-way hash function that provides authentication.
X##  It does not provide secrecy.
X##
X##  Snefru is named after a Pharaoh of ancient Egypt.
X##
X##  It is based on code that is:
X##      Copyright (c) Xerox Corporation 1989.  All rights reserved.
X##
X##      License to copy and use this software is granted provided that it
X##      is identified as the 'Xerox Secure Hash Function' in all material
X##      mentioning or referencing this software or this hash function.
X##
X##      License is also granted to make and use derivative works provided
X##      that such works are identified as 'derived from the Xerox Secure
X##      Hash Function' in all material mentioning or referencing the
X##      derived work.
X##
X##      Xerox Corporation makes no representations concerning either the
X##      merchantability of this software or the suitability of this
X##      software for any particular purpose.  It is provided "as is"
X##      without express or implied warranty of any kind.
X##
X##      These notices must be retained in any copies of any part of this
X##      software.
X##
X##  Based on the reference implementation (no algorithm changes) of
X##  version 2.0, July 31, 1989.  Implementor:  Ralph C. Merkle.
X##  This edition is by Rich $alz, <rsalz at bbn.com>.
X##  $Header: Makefile,v 1.1 90/03/22 12:57:52 rsalz Exp $
X##
X
X##  Add -DUSE_STRCHR here if you use strchr/strrchr.
X##  Add -DCHARPSPRINTF here if you need "extern char *sprinf();"
XDEFS	= -DCHARPSPRINTF
XCFLAGS	= $(DEFS) -O
X#CFLAGS	= $(DEFS) -g
X
X
X##
Xall:		snefru testboxes hashnews checkhash
X
Xinstall:	all
X	@echo Install according to local convention
X
Xclean:
X	rm -f foo core tags lint* a.out tests *.o Part0?
X	rm -f snefru testboxes hashnews checkhash testboxes.c
X
Xtests:		all tests.sh lint
X	@rm -f $@
X	sh ./tests.sh | tee tests
X
Xshar:
X	makekit -m -t "Now see the README"
X
X##
Xsnefru.o hash512.o sboxes.o:		snefru.h
Xtestboxes.o hashn.o hash512.o:		snefru.h
Xcheckhash.o hashnews.o pipeit.o:	snefru.h
X
Xtestboxes.c:	testboxes.c1 testboxes.c2
X	@rm -f $@
X	cat testboxes.c1 testboxes.c2 >$@
X
X##
Xsnefru:		snefru.o hash512.o sboxes.o
X	@rm -f $@
X	$(CC) $(CFLAGS) -o $@ snefru.o hash512.o sboxes.o
X
Xtestboxes:	testboxes.o hashn.o hash512.o sboxes.o
X	@rm -f $@
X	$(CC) $(CFLAGS) -o $@ testboxes.o hashn.o hash512.o sboxes.o
X
Xcheckhash:	checkhash.o pipeit.o
X	$(CC) $(CFLAGS) -o $@ checkhash.o pipeit.o
X
Xhashnews:	hashnews.o pipeit.o
X	$(CC) $(CFLAGS) -o $@ hashnews.o pipeit.o
X
X##
Xlint:		lint.s lint.t lint.h lint.c
X
Xlint.s:		snefru
X	@rm -f $@
X	lint -b -h $(DEFS) snefru.c hash512.c sboxes.c >$@
Xlint.t:		testboxes
X	@rm -f $@
X	lint -b -h $(DEFS) testboxes.c hashn.c hash512.c sboxes.c >$@
Xlint.c:		checkhash
X	@rm -f $@
X	lint -b -h $(DEFS) checkhash.c pipeit.c >$@
Xlint.h:		hashnews
X	@rm -f $@
X	lint -b -h $(DEFS) hashnews.c pipeit.c >$@
END_OF_FILE
if test 2863 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(1533 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X
XThis is my revision of Ralph Merkle's SNEFRU program.  Snefru is a one-way
Xhash algorithm:  given some input text, Snefru will come up with a single
Xnumber such that no two texts will hash down to the same number.  In this
Xway, Snefru can tell you whether an article has been corrupted, but not if
Xit is authentic or not -- think of it as a super-strong checksum.
X
XStarting with this posting, I am going to be using hashnews on all my
Xc.s.u articles.  While I don't think that this is worth doing for most
Xgeneral Usenix articles, I think it will be an interesting experiment for
Xarchives.
X
XI completely rewrote and reorganized the code that Ralph has made
Xavailable.  For example, I split the comments out into manual pages, and
Xput all the tests out into a separate program.  What I'm making available
Xis a derived work, and therefore must be distributed under the same terms
Xas Ralph's original code.  Thanks to him and Xerox for making his work
Xavailable.  Some of the programs and manual pages are my original work,
Xand therefore don't contain the Xerox copyright.  They are in the public
Xdomain, and feel free to do what you want with them.
X
XThis code needs a 32bit machine; good luck if you've only got 16 bits!
X
XTo compile, edit the Makefile if you use strchr/strrchr rather than
Xindex/rindex.  Also edit snefru.c to determine the byte order of your
Xmachine.  Once that's done, do "make tests" to verify the output.  If you
Xget wrong answers, the first thing to suspect is the byte order.
X
XEnjoy,
X	Rich $alz <rsalz at bbn.com>
END_OF_FILE
if test 1533 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'TestArticle' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'TestArticle'\"
else
echo shar: Extracting \"'TestArticle'\" \(1456 characters\)
sed "s/^X//" >'TestArticle' <<'END_OF_FILE'
XPath: papaya.bbn.com!rsalz
XFrom: rsalz at bbn.com (Rich Salz)
XNewsgroups: bbn.test
XSubject: This is a test of the hashing function
XMessage-ID: <2340 at litchi.bbn.com>
XDate: 22 Mar 90 15:53:47 GMT
XDistribution: bbn
XOrganization: BBN Systems and Technology, Inc.
XLines: 24
X
XThis is my revision of Ralph Merkle's SNEFRU program.  Snefru is a one-way
Xhash algorithm:  given some input text, Snefru will come up with a single
Xnumber.  No two texts will hash down to the same number.  (Think of it as
Xa super-strong checksum.)
X
XI completely rewrote and reorganized the code that Ralph has made
Xavailable.  For example, I split the comments out into manual pages, and
Xput all the tests out into a separate program.  What I'm making available
Xis a derived work, and therefore must be distributed under the same terms
Xas Ralph's original code.  Thanks to him and Xerox for making his work
Xavailable.  Some of the programs and manual pages are my work, and
Xtherefore don't contain the Xerox copyright.  They are in the public
Xdomain, and feel free to do what you want with them.
X
XThis code needs a 32bit machine; good luck trying to port it elsewhere!
XTo compile, edit the Makefile if you use strchr/strrchr rather than
Xindex/rindex.  Also edit snefru.c to determine the byte order of your
Xmachine.
X
X	/rich $alz <rsalz at bbn.com>
X-- 
XPlease send comp.sources.unix-related mail to rsalz at uunet.uu.net.
XUse a domain-based address or give alternate paths, or you may lose out.
END_OF_FILE
if test 1456 -ne `wc -c <'TestArticle'`; then
    echo shar: \"'TestArticle'\" unpacked with wrong size!
fi
# end of 'TestArticle'
fi
if test -f 'checkhash.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'checkhash.1'\"
else
echo shar: Extracting \"'checkhash.1'\" \(972 characters\)
sed "s/^X//" >'checkhash.1' <<'END_OF_FILE'
X.TH HASHNEWS 1 LOCAL
X.SH NAME
Xcheckhash \- Check the Snefru hash code on a Usenet article
X.SH SYNOPSIS
X.B checkhash
X[
X.B \-n
X] [
X.I input
X]
X.SH DESCRIPTION
X.I Checkhash
Xreads a Usenet article from the named file, or standard input if no file
Xis given.
XIt filters out the headers and calls
X.IR snefru (1L)
Xto generate a one-way hash code for the article.
XIt compares this with the hash given in the header, and prints a message
Xindicating whether they match or not.
XTo suppress the message, use the ``\-s'' flag.
X.PP
XThe program will exit with status zero if the article is okay, a
Xone if the hash codes don't match, or a two if no checksum header
Xcan be found.
X.SH WARNING
X.I Checkhash
Xwill only prove if an article has been tampered with; it does not
Xprovide any authentication.
XAlso, see the warnings in the
X.I snefru
Xmanpage.
X.SH AUTHOR
X.nf
XRich $alz <rsalz at bbn.com>
X$Header: checkhash.1,v 1.1 90/03/22 12:58:13 rsalz Exp $
X.fi
X.SH "SEE ALSO"
Xhashnews(1L), snefru(1L).
END_OF_FILE
if test 972 -ne `wc -c <'checkhash.1'`; then
    echo shar: \"'checkhash.1'\" unpacked with wrong size!
fi
# end of 'checkhash.1'
fi
if test -f 'checkhash.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'checkhash.c'\"
else
echo shar: Extracting \"'checkhash.c'\" \(2841 characters\)
sed "s/^X//" >'checkhash.c' <<'END_OF_FILE'
X/*
X**  Verify a Usenet article with a Snefru hash header.
X*/
X#include <stdio.h>
X#include <ctype.h>
X#include "snefru.h"
X#ifdef	RCSID
Xstatic char RCS[] =
X	"$Header: checkhash.c,v 1.1 90/03/22 12:58:18 rsalz Exp $";
X#endif	/* RCSID */
X
X#ifndef	isascii
X#define isascii(c)	(1)
X#endif	/* isascii */
X
Xextern char	*optarg;
Xextern int	optind;
X
Xextern char	*mktemp();
Xextern char	*SnefruClose();
Xextern char	*strcpy();
Xextern FILE	*SnefruOpen();
X
X
Xstatic void
XUsage()
X{
X    (void)fprintf(stderr, "Usage: checkhash [filename]\n");
X    exit(1);
X}
X
X
Xmain(ac, av)
X    int		ac;
X    char	*av[];
X{
X    char	*p;
X    char	buff[BUFSIZ];
X    char	Checksum[40];
X    FILE	*Input;
X    FILE	*Snefru;
X    int		i;
X    int		Silent;
X
X    /* Set defaults. */
X    Silent = FALSE;
X
X    /* Parse JCL. */
X    while ((i = getopt(ac, av, "s")) != EOF)
X	switch (i) {
X	default:
X	    Usage();
X	    /* NOTREACHED */
X	case 's':
X	    Silent = TRUE;
X	    break;
X	}
X
X    /* Get input. */
X    ac -= optind;
X    av += optind;
X    switch (ac) {
X    default:
X	Usage();
X    case 0:
X	Input = stdin;
X	break;
X    case 1:
X	if ((Input = fopen(av[0], "r")) == NULL) {
X	    perror("No input");
X	    (void)fprintf(stderr, "Can't open \"%s\" for reading.\n", av[0]);
X	    exit(1);
X	}
X	break;
X    }
X
X    /* Read headers, looking for the checksum. */
X    Checksum[0] = '\0';
X    while (fgets(buff, sizeof buff, Input)) {
X	if (buff[0] == '\n')
X	    break;
X	if (buff[0] == HDRFIRSTCHAR
X	 && strncmp(buff, CHECKSUMHDR, sizeof CHECKSUMHDR - 1) == 0) {
X	    p = &buff[sizeof CHECKSUMHDR] + 1;
X	    /* Right length, allowing for the newline? */
X	    if (strlen(p) != HDRTEXTSIZE + 1) {
X		if (!Silent)
X		    (void)printf("Wrong length:\n\t%s", buff);
X		continue;
X	    }
X	    (void)strcpy(Checksum, p);
X	    Checksum[HDRTEXTSIZE] = '\0';
X	    for (p = Checksum; *p; p++)
X		if (*p != ' ' && !(isascii(*p) && isxdigit(*p)))
X		    break;
X	    if (*p) {
X		if (!Silent)
X		    (void)printf("Bad character '%c':\n\t%s", *p, buff);
X		/* Broke out before reaching the end, invalid header. */
X		Checksum[0] = '\0';
X	    }
X	}
X    }
X
X    if (Checksum[0] == '\0') {
X	if (!Silent)
X	    (void)printf("No valid checksum header found.\n");
X	exit(2);
X    }
X
X    /* Call up Snefru. */
X    if ((Snefru = SnefruOpen()) == NULL) {
X	if (!Silent)
X	    perror("Can't open pipe to snefru");
X	exit(2);
X    }
X
X    /* Send the rest of the article down the pipe. */
X    while (fgets(buff, sizeof buff, Input))
X	(void)fputs(buff, Snefru);
X    (void)fclose(Input);
X
X    if ((p = SnefruClose()) == NULL) {
X	if (!Silent)
X	    perror("Can't open tempfile");
X	exit(2);
X    }
X
X    /* Compare them. */
X    if (strcmp(p, Checksum) == 0) {
X	if (!Silent)
X	    (void)printf("Valid.\n");
X	exit(0);
X    }
X    if (!Silent) {
X	(void)printf("Invalid!\n");
X	(void)printf("Computed: %s\n", p);
X	(void)printf("  Posted: %s\n", Checksum);
X    }
X    exit(1);
X}
END_OF_FILE
if test 2841 -ne `wc -c <'checkhash.c'`; then
    echo shar: \"'checkhash.c'\" unpacked with wrong size!
fi
# end of 'checkhash.c'
fi
if test -f 'hashn.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'hashn.c'\"
else
echo shar: Extracting \"'hashn.c'\" \(3463 characters\)
sed "s/^X//" >'hashn.c' <<'END_OF_FILE'
X/*
X**  This is Snefru, derived from the Xerox Secure Hash Function.
X**  Snefru is a one-way hash function that provides authentication.
X**  It does not provide secrecy.
X**
X**  Snefru is named after a Pharaoh of ancient Egypt.
X**
X**  It is based on code that is:
X**	Copyright (c) Xerox Corporation 1989.  All rights reserved.
X**
X**	License to copy and use this software is granted provided that it
X**	is identified as the 'Xerox Secure Hash Function' in all material
X**	mentioning or referencing this software or this hash function.
X**
X**	License is also granted to make and use derivative works provided
X**	that such works are identified as 'derived from the Xerox Secure
X**	Hash Function' in all material mentioning or referencing the
X**	derived work.
X**
X**	Xerox Corporation makes no representations concerning either the
X**	merchantability of this software or the suitability of this
X**	software for any particular purpose.  It is provided "as is"
X**	without express or implied warranty of any kind.
X**
X**	These notices must be retained in any copies of any part of this
X**	software.
X**
X**  Based on the reference implementation (no algorithm changes) of
X**  version 2.0, July 31, 1989.  Implementor:  Ralph C. Merkle.
X**  This edition is by Rich $alz, <rsalz at bbn.com>.
X*/
X#include "snefru.h"
X#ifdef	RCSID
Xstatic char RCS[] =
X	"$Header: hashn.c,v 1.1 90/03/22 12:58:33 rsalz Exp $";
X#endif	/* RCSID */
X
X
Xstatic int	ShiftTable[4] = { 16, 8, 16, 24 };
X
X/*
X**  Compute the hash.
X**  Note that we are computing level * wordCount * 4 rounds.
X*/
XHashN(output, wordCount, input, level, OutputBlockSize)
X    WORD32	output[OUTPUTBLOCKSIZE];
X    int		wordCount;
X    WORD32	input[];
X    int		level;
X    int		OutputBlockSize;
X{
X    WORD32	mask;
X    WORD32	block[WORDCOUNT];	/* array of data being hashed  */
X    WORD32	SBoxEntry;
X    int		shift;
X    int		i;
X    int		index;
X    int		next;
X    int		last;
X    int		ByteInWord;
X
X    /* wordCount is a power of two. */
X    mask = wordCount - 1;
X
X#if	0
X    /* Test for various error conditions and logic problems.  */
X    if (level * 2 > SBOXCOUNT)
X	abort("Too few S-boxes");
X    if (wordCount > WORDCOUNT)
X	abort("Logic error, wordCount > WORDCOUNT");
X    if (wordCount != 16)
X	abort("Security warning, input size not equal to 512 bits");
X    /* Spectacularly insecure for small blocks, so... */
X    if (wordCount < 4)
X	abort("wordCount too small");
X    if ((wordCount & mask) != 0)
X	abort("Logic error, wordCount not a power of 2");
X    if (OutputBlockSize > wordCount)
X	abort("Logic error, OutputBlockSize is too big");
X    if (OutputBlockSize != 4 && OutputBlockSize != 8)
X	abort("Output size neither 128 nor 256 bits");
X#endif	/* 0 */
X
X    /* Initialize the block to be encrypted from the input  */
X    for (i = 0; i < wordCount; i++)
X	block[i] = input[i];
X
X    for (index = 0; index < level; index++) {
X	for (ByteInWord = 0; ByteInWord < 4; ByteInWord++) {
X	    for (i = 0; i < wordCount; i++) {
X		next = (i + 1) & mask;
X		last = (i + mask) & mask; /* last = (i-1) MOD wordCount */
X		SBoxEntry =
X		    SnefruSBoxes[2 * index + ((i / 2) & 1)][block[i] & 0xFF];
X		block[next] ^= SBoxEntry;
X		block[last] ^= SBoxEntry;
X	    }
X	    /* Rotate right all 32-bit words in the entire block at once.  */
X	    for (shift = ShiftTable[ByteInWord], i = 0; i < wordCount; i++)
X		block[i] = (block[i] >> shift) | (block[i] << (32 - shift));
X	}
X    }
X
X    for (i = 0; i < OutputBlockSize; i++)
X	output[i] = input[i] ^ block[mask - i];
X}
END_OF_FILE
if test 3463 -ne `wc -c <'hashn.c'`; then
    echo shar: \"'hashn.c'\" unpacked with wrong size!
fi
# end of 'hashn.c'
fi
if test -f 'hashnews.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'hashnews.1'\"
else
echo shar: Extracting \"'hashnews.1'\" \(1229 characters\)
sed "s/^X//" >'hashnews.1' <<'END_OF_FILE'
X.TH HASHNEWS 1 LOCAL
X.SH NAME
Xhashnews \- add a Snefru hash to a Usenet article
X.SH SYNOPSIS
X.B hashnews
X[
X.B \-n
X] [
X.I input
X]
X.SH DESCRIPTION
X.I Hashnews
Xreads an article intended for Usenet posting and calls
X.IR snefru (1L)
Xto generate a one-way hash code for the article.
X.PP
XIf a file is named on the command line, then
X.I hashnews
Xwill overwrite the named file after inserting the Snefru hashcode.
XIf no file is named, the program will read the article from standard
Xinput, and write the new article on standard output; this makes it
Xconvenient to do ``:%!hashnews'' from
X.IR vi (1)
Xjust before exiting the editor with your article in it.
X.PP
XBy default,
X.I hashnews
Xwill try to read the file ``.signature'' in your home directory and
Xappend it to the article.
XIt tries to simulate the actions of B2.11
X.IR inews (8).
XTo suppress this check (for example, if you append your own signature),
Xuse the ``\-n'' flag.
X.SH WARNING
X.I Hashnews
Xwill only prove if an article has been tampered with; it does not
Xprovide any authentication.
XAlso, see the warnings in the
X.I snefru
Xmanpage.
X.SH AUTHOR
X.nf
XRich $alz <rsalz at bbn.com>
X$Header: hashnews.1,v 1.1 90/03/22 12:58:39 rsalz Exp $
X.fi
X.SH "SEE ALSO"
Xcheckhash(1L), snefru(1L).
END_OF_FILE
if test 1229 -ne `wc -c <'hashnews.1'`; then
    echo shar: \"'hashnews.1'\" unpacked with wrong size!
fi
# end of 'hashnews.1'
fi
if test -f 'hashnews.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'hashnews.c'\"
else
echo shar: Extracting \"'hashnews.c'\" \(5078 characters\)
sed "s/^X//" >'hashnews.c' <<'END_OF_FILE'
X/*
X**  Call SNEFRU on something about to be feed into INEWS.  Then, rewrite
X**  the file to add the X-Snefru-Checksum header.
X*/
X#include <stdio.h>
X#include <pwd.h>
X#include "snefru.h"
X#ifdef	RCSID
Xstatic char RCS[] =
X	"$Header: hashnews.c,v 1.1 90/03/22 12:58:44 rsalz Exp $";
X#endif	/* RCSID */
X
X#ifdef	USE_STRCHR
X#define IDX	strchr
X#else
X#define IDX	index
X#endif	/* USE_STRCHR */
X
X#ifndef	SEEK_ABS
X#define SEEK_ABS	0
X#endif	/* SEEK_ABS */
X
Xextern char	*optarg;
Xextern int	optind;
X
Xextern char		*getenv();
Xextern char		*IDX();
Xextern char		*mktemp();
Xextern char		*SnefruClose();
Xextern char		*strcpy();
Xextern FILE		*SnefruOpen();
Xextern long		ftell();
Xextern struct passwd	*getpwuid();
X#ifdef	CHARPSPRINTF
Xextern char	*sprintf();
X#endif	/* CHARPSPRINTF */
X
Xstatic void
XUsage()
X{
X    (void)fprintf(stderr, "Usage: snefru_news articlename\n");
X    exit(1);
X}
X
X
X/*
X**  Simulate what B2.11 inews does for appeneding signatures.
X*/
Xstatic int
XAppendSignature(Snefru)
X    FILE		*Snefru;
X{
X    char		*p;
X    char		buff[256];
X    FILE		*F;
X    int			i;
X    struct passwd	*pwd;
X
X    if ((p = getenv("HOME")) == NULL
X     && (p = getenv("LOGDIR")) == NULL) {
X	if ((pwd = getpwuid(getuid())) == NULL)
X	    return 0;
X	p = pwd->pw_dir;
X    }
X    (void)sprintf(buff, "%s/.signature", p);
X    if ((F = fopen(buff, "r")) == NULL)
X	return 0;
X    for (i = 0; fgets(buff, sizeof buff, F); i++)
X	if (IDX(buff, '\n') == NULL) {
X	    i = 0;
X	    break;
X	}
X    if (i > 4 || i == 0) {
X	(void)fclose(F);
X	return 0;
X    }
X    (void)fprintf(Snefru, "-- \n");
X    rewind(F);
X    while (fgets(buff, sizeof buff, F))
X	(void)fputs(buff, Snefru);
X    (void)fclose(F);
X    return i;
X}
X
X
Xmain(ac, av)
X    int		ac;
X    char	*av[];
X{
X    int		i;
X    int		CheckSignature;
X    FILE	*Input;
X    FILE	*Snefru;
X    FILE	*Output;
X    FILE	*Body;
X    char	buff[BUFSIZ];
X    char	*p;
X    char	tempfile[20];
X    char	bodyfile[20];
X    long	cookie;
X
X    /* Set defaults. */
X    CheckSignature = TRUE;
X
X    /* Parse JCL. */
X    while ((i = getopt(ac, av, "n")) != EOF)
X	switch (i) {
X	default:
X	    Usage();
X	case 'n':
X	    CheckSignature = FALSE;
X	    break;
X	}
X
X    /* Get input. */
X    ac -= optind;
X    av += optind;
X    switch (ac) {
X    default:
X	Usage();
X	/* NOTREACHED */
X    case 0:
X	/* We're being piped into.  Create a temp file to hold the
X	 * article body. */
X	Input = stdin;
X	(void)strcpy(bodyfile, "/tmp/hashBXXXXXX");
X	(void)mktemp(bodyfile);
X	if ((Body = fopen(bodyfile, "w")) == NULL) {
X	    perror("No temporary");
X	    (void)fprintf(stderr, "Can't open \"%s\" for writing.\n",
X		    bodyfile);
X	    exit(1);
X	}
X	break;
X    case 1:
X	if ((Input = fopen(av[0], "r")) == NULL) {
X	    perror("No input");
X	    (void)fprintf(stderr, "Can't open \"%s\" for reading.\n", av[0]);
X	    exit(1);
X	}
X	Body = NULL;
X	break;
X    }
X
X    /* Get output file. */
X    (void)strcpy(tempfile, "/tmp/hashHXXXXXX");
X    (void)mktemp(tempfile);
X    if ((Output = fopen(tempfile, "w")) == NULL) {
X	perror("No output");
X	(void)fprintf(stderr, "Can't open \"%s\" for writing.\n", tempfile);
X	exit(1);
X    }
X
X    /* Open stream to snefru. */
X    if ((Snefru = SnefruOpen()) == NULL) {
X	perror("Can't open pipe to snefru");
X	(void)fclose(Output);
X	(void)unlink(tempfile);
X	exit(1);
X    }
X
X    /* Read article, skipping headers. */
X    while (fgets(buff, sizeof buff, Input)) {
X	if (buff[strlen(buff) - 1] != '\n')
X	    (void)fprintf(stderr, "Warning, line truncated:\n%s\n",
X		    buff);
X	if (buff[0] == '\n')
X	    break;
X	(void)fputs(buff, Output);
X    }
X
X    /* If not from stdin we can seek, so remember where the headers end. */
X    if (Body == NULL)
X	cookie = ftell(Input);
X
X    /* Send rest of article to snefru. */
X    while (fgets(buff, sizeof buff, Input)) {
X	if (buff[strlen(buff) - 1] != '\n')
X	    (void)fprintf(stderr, "Warning, line truncated:\n%s\n",
X		    buff);
X	(void)fputs(buff, Snefru);
X	if (Body)
X	    (void)fputs(buff, Body);
X    }
X
X    /* Do the signature? */
X    if (CheckSignature) {
X	if ((i = AppendSignature(Snefru)) == 0)
X	    (void)fprintf(stderr, ".signature unreadable or too long...\n");
X    }
X
X    (void)fclose(Input);
X
X    /* Write the checksum. */
X    if (p = SnefruClose())
X	(void)fprintf(Output, "%s: %s\n", CHECKSUMHDR, p);
X    else
X	(void)fprintf(stderr, "Snefru checksum lost!?\n");
X
X    /* Send the article body. */
X    if (Body) {
X	(void)fclose(Body);
X	Input = fopen(bodyfile, "r");
X    }
X    else {
X	Input = fopen(av[0], "r");
X	(void)fseek(Input, cookie, SEEK_ABS);
X    }
X    (void)fputs("\n", Output);
X    while (fgets(buff, sizeof buff, Input))
X	(void)fputs(buff, Output);
X    (void)fclose(Output);
X
X    if (Input == stdin)
X	/* Input is stdin, so send output to stdout. */
X	Output = stdout;
X    else if ((Output = fopen(av[0], "w")) == NULL) {
X	perror("Can't rewrite file");
X	(void)fprintf(stderr,
X		"Can't overwrite \"%s\", output is in \"%s\".\n",
X		av[0], tempfile);
X	exit(1);
X    }
X
X    Input = fopen(tempfile, "r");
X    while (fgets(buff, sizeof buff, Input))
X	(void)fputs(buff, Output);
X
X    if (Output != stdout);
X	(void)unlink(tempfile);
X    (void)fclose(Output);
X    exit(0);
X}
END_OF_FILE
if test 5078 -ne `wc -c <'hashnews.c'`; then
    echo shar: \"'hashnews.c'\" unpacked with wrong size!
fi
# end of 'hashnews.c'
fi
if test -f 'patchlevel.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'patchlevel.h'\"
else
echo shar: Extracting \"'patchlevel.h'\" \(408 characters\)
sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
X/*
X**  Header file for Snefru package.
X**  Based on the reference implementation (no algorithm changes) of
X**  version 2.0, July 31, 1989.  Implementor:  Ralph C. Merkle.
X**  This edition is by Rich $alz, <rsalz at bbn.com>.
X**
X**  $Log:	patchlevel.h,v $
X**  Revision 1.1  90/03/22  13:34:53  rsalz
X**  Initial revision
X**  
X**  $Header: patchlevel.h,v 1.1 90/03/22 13:34:53 rsalz Exp $
X*/
X#define PATCHLEVEL	0
END_OF_FILE
if test 408 -ne `wc -c <'patchlevel.h'`; then
    echo shar: \"'patchlevel.h'\" unpacked with wrong size!
fi
# end of 'patchlevel.h'
fi
if test -f 'pipeit.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pipeit.c'\"
else
echo shar: Extracting \"'pipeit.c'\" \(1397 characters\)
sed "s/^X//" >'pipeit.c' <<'END_OF_FILE'
X/*
X**  Utility routines to interface to the Snefru program as a filter.
X*/
X#include <stdio.h>
X#include "snefru.h"
X#ifdef	RCSID
Xstatic char RCS[] =
X	"$Header: pipeit.c,v 1.1 90/03/22 12:59:01 rsalz Exp $";
X#endif	/* RCSID */
X
X
X#ifdef	USE_STRCHR
X#define RDX	strrchr
X#else
X#define RDX	rindex
X#endif	/* USE_STRCHR */
X
Xstatic char	OutputFile[] = "/tmp/hashcodeXXXXXX";
Xstatic char	ChecksumBuffer[HDRTEXTSIZE + 2];
Xstatic FILE	*Stream;
X
Xextern char	*RDX();
Xextern char	*mktemp();
X#ifdef	CHARPSPRINTF
Xextern char	*sprintf();
X#endif	/* CHARPSPRINTF */
X
X
X/*
X**  Spawn a Snefru that has its output redirected.
X*/
XFILE *
XSnefruOpen()
X{
X    char	buff[sizeof OutputFile + 20];
X
X    /* Open stream to snefru. */
X    (void)mktemp(OutputFile);
X    (void)sprintf(buff, "snefru >%s", OutputFile);
X    if ((Stream = popen(buff, "w")) == NULL)
X	(void)unlink(OutputFile);
X    return Stream;
X}
X
X
X/*
X**  Close the pipe and read in the Snefru's output.
X*/
Xchar *
XSnefruClose()
X{
X    FILE	*F;
X    char	*p;
X
X    (void)pclose(Stream);
X
X    /* Open the output file, read the one line. */
X    if ((F = fopen(OutputFile, "r")) == NULL)
X	return NULL;
X    p = fgets(ChecksumBuffer, sizeof ChecksumBuffer, F);
X    (void)fclose(F);
X    (void)unlink(OutputFile);
X    if (p == NULL)
X	return NULL;
X
X    /* Kill the newline. */
X    if ((p = RDX(ChecksumBuffer, '\n')) == NULL)
X	return NULL;
X    *p = '\0';
X    return ChecksumBuffer;
X}
END_OF_FILE
if test 1397 -ne `wc -c <'pipeit.c'`; then
    echo shar: \"'pipeit.c'\" unpacked with wrong size!
fi
# end of 'pipeit.c'
fi
if test -f 'snefru.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'snefru.1'\"
else
echo shar: Extracting \"'snefru.1'\" \(3886 characters\)
sed "s/^X//" >'snefru.1' <<'END_OF_FILE'
X.TH SNEFRU 1 LOCAL
X.SH NAME
Xsnefru \- Experimental secure one-way hash function
X.SH SYNOPSIS
X.B snefru
X[
X.BI \-l #
X] [
X.BI \-o #
X]
X.SH DESCRIPTION
X.I Snefru
Xreads standard input, hashes it with a cryptographically secure one-way
Xhash function, and prints the hash code on the standard output.
XThe input can be any size.
XThe output can be either 128 bits, printed as four 32-byte hexadecimal
Xnumbers, or 256 bits, printed as eight numbers.
XTo set the output, use the ``\-o'' flag, with either the value four or
Xeight.
X.PP
XThe security level is set by the ``\-l'' flag, which determines the number
Xof iterations in the hash.
XPick a number between two and four, inclusive.
X.PP
XThe primary use of one-way hash functions is to determine if there have
Xbeen any unauthorized, malicious, or accidental changes made to a file.
XFor example, if an executable program file produces the following hash:
X.RS
X209884c4 2e89d967 5456ac0e 61269550
X.RE
Xthen any change to that program file will cause the hash to be changed.
XThus, the tampering can be detected by comparing the current output value
Xwith the previously computed (and presumably correct) output value.
X.SH INTERNALS
X.I Hash512
Xis the central routine in this program.
XIt is used in this
Xprogram in a linear fashion \(em i.e., a sequential file is hashed down by
Xrepeated applications of
X.IR Hash512 .
XChanging a single bit in the file would then require completely
Xre-computing the hash from the point of change onward.
X.PP
X.I Hash512
Xcan be used in a tree-structured fashion to authenticate a large
Xtable of data.
XThis would imply that changing a single bit would not force a complete
Xre-computation of the hash value, but would instead require only
X.I "log n"
Xre-computations of
X.I Hash512
Xto ``patch up'' the changes along the path from the root to the
Xchanged leaf entry.
XA tree-structured application also has the advantage that any single entry
Xin the table can subsequently be authenticated by someone who knows only
Xthe ``authentication path'' from the root of the tree to the leaf entry.
XThese concepts are discussed more thoroughly in
X.I "Secrecy, Authentication, and Public Key Systems"
Xby Ralph C. Merkle, UMI Research Press, 1982 (see particularly Chapter 2,
X.IR "One Way Hash Functions" ).
XThe use of a tree-structured pattern of applications of a one-way hash
Xfunction is covered by U.S. Patent #4,309,569,
X.I "Method of Providing Digital Signatures"
X(contact Stanford University, Office of Technology Licensing).
X.PP
XAt the present time (July 31, 1989) the author knows of no method for
Xbreaking this one-way function, (i.e., finding two input files that
Xproduce the same output value).
XThe algorithm has undergone some review for security.
XFurther review is expected.  Use of this algorithm for production use is
Xnot recomended at this time.
XNote that we are specifically examining the security of
X.I Hash512
Xwith a 512-bit input and a 128-bit output, and
X.I Hash512
Xwith a 512-bit input and a 256-bit output.
XUse of other sizes is not recomended at this time.
XIn particular, we recomend against the use of output sizes smaller than
X128 bits, and recomend against the use of an input that is less than two
Xtimes the size of the output.
XWhen the input size equals the output size,
X.I Snefru
Xsuffers a serious degradation in security (an observation due to
XCoppersmith).
X.SH WARNINGS
XIf anyone using this program finds two different inputs that produce the
Xsame output, please contact
X.RS
X.nf
XRalph C. Merkle, <merkle at xerox.com>
XXerox PARC
X3333 Coyote Hill Road
XPalo Alto, CA 94304
X(415) 494\-4000
X.fi
X.RE
X.SH AUTHOR
X.nf
XBased on the reference implementation (no algorithm changes) of
Xversion 2.0, July 31, 1989.  Implementor:  Ralph C. Merkle.
XThis edition is by Rich $alz, <rsalz at bbn.com>.
X$Header: snefru.1,v 1.1 90/03/22 13:00:08 rsalz Exp $
X.fi
X.SH "SEE ALSO"
X.IR "A Software One Way Hash Function" ,
Xby Ralph C. Merkle.
END_OF_FILE
if test 3886 -ne `wc -c <'snefru.1'`; then
    echo shar: \"'snefru.1'\" unpacked with wrong size!
fi
# end of 'snefru.1'
fi
if test -f 'snefru.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'snefru.c'\"
else
echo shar: Extracting \"'snefru.c'\" \(8565 characters\)
sed "s/^X//" >'snefru.c' <<'END_OF_FILE'
X/*
X**  This is Snefru, derived from the Xerox Secure Hash Function.
X**  Snefru is a one-way hash function that provides authentication.
X**  It does not provide secrecy.
X**
X**  Snefru is named after a Pharaoh of ancient Egypt.
X**
X**  It is based on code that is:
X**	Copyright (c) Xerox Corporation 1989.  All rights reserved.
X**
X**	License to copy and use this software is granted provided that it
X**	is identified as the 'Xerox Secure Hash Function' in all material
X**	mentioning or referencing this software or this hash function.
X**
X**	License is also granted to make and use derivative works provided
X**	that such works are identified as 'derived from the Xerox Secure
X**	Hash Function' in all material mentioning or referencing the
X**	derived work.
X**
X**	Xerox Corporation makes no representations concerning either the
X**	merchantability of this software or the suitability of this
X**	software for any particular purpose.  It is provided "as is"
X**	without express or implied warranty of any kind.
X**
X**	These notices must be retained in any copies of any part of this
X**	software.
X**
X**  Based on the reference implementation (no algorithm changes) of
X**  version 2.0, July 31, 1989.  Implementor:  Ralph C. Merkle.
X**  This edition is by Rich $alz, <rsalz at bbn.com>.
X*/
X#include <stdio.h>
X#include "snefru.h"
X#ifdef	RCSID
Xstatic char RCS[] =
X	"$Header: snefru.c,v 1.1 90/03/22 13:00:13 rsalz Exp $";
X#endif	/* RCSID */
X
X#define SIZEOF(s)	(sizeof s / sizeof s[0])
X
X
X/*
X**  Get the byte order.  If the four bytes 1 2 3 4 are stored as 1234,
X**  then we can do punning on the byte/word buffers, and just quickly
X**  copy things.  If not, we have to shuffle between buffers.
X*/
X#if	defined(sun) && !defined(i386)
X    /* All Sun's except the 386i. */
X#define BYTESHILO
X#endif	/* .. */
X
X#if	defined(mc300) || defined(mc500) || defined(u3b2)
X    /* The Masscomp MC5500 and MC5500-PEP and the ATT3b2. */
X#define BYTESHILO
X#endif	/* .. */
X
Xextern char	*optarg;
Xextern int	optind;
X
X
X/*
X**  Convert a byte array to an array of WORD32.  Primarily intended to
X**  eliminate the byte-ordering problem (e.g., a Vax orders the bytes in a
X**  character array differently than a Sun does).  Using this will slow the
X**  hash function!  This is only needed on Vax-like machines, and can be
X**  removed for Sun3-like byteorders.
X*/
Xstatic void
XBytesToWords(Cbuffer, Wbuffer)
X    register char	*Cbuffer;
X    register WORD32	*Wbuffer;
X{
X#ifdef	BYTESHILO
X    register WORD32	*pun;
X    register int	i;
X
X    for (pun = (WORD32 *)Cbuffer, i = BUFFERSIZEINWORDS; --i >= 0; )
X	*Wbuffer++ = *pun++;
X#else	/* BYTESHILO */
X    register int	 i;
X    register WORD32	 t0;
X    register WORD32	 t1;
X    register WORD32	 t2;
X    register WORD32	 t3;
X
X    for (i = BUFFERSIZEINWORDS; --i >= 0; Cbuffer += 4) {
X	t0 = Cbuffer[0] & 0xFF;
X	t1 = Cbuffer[1] & 0xFF;
X	t2 = Cbuffer[2] & 0xFF;
X	t3 = Cbuffer[3] & 0xFF;
X	*Wbuffer++ = (t0 << 24) | (t1 << 16) | (t2 << 8) | t3;
X    }
X#endif	/* BYTESHILO */
X}
X
X
Xstatic void
XUsage()
X{
X    (void)fprintf(stderr, "Usage: snefru [-l#] [-o#] [inputfile]\n");
X    (void)fprintf(stderr, "Where %s and %s.\n",
X	     "-l takes 2, 3, or 4", "-o takes 4 or 8");
X    exit(1);
X}
X
X
X/*
X**  Read the input, hashes it, and prints the result.  Much of the logic
X**  in the main program is taken up with the trivia of buffer management,
X**  error checking, command-line parameter checking, self-tests, and the
X**  like. The actual use of the hash function occupies a modest portion of
X**  the overall program.
X**
X**  The basic idea is simple.  As an example, if H is the hash function
X**  that produces either 128-bit (or 256-bit) outputs, and if we pick an
X**  input string that is 3 "chunks" long then we are computing:
X**
X**  output = H( H( H( H(0 || chunk[0]) || chunk[1]) || chunk[2]) || bit-length)
X**
X**  "||" is the concatenation operator, and is used to concatenate the
X**  output field of the preceding computation of H with the next "chunk"
X**  of bits from the input.
X**
X**  "bit-length" is a "chunk" sized field into which has been put the
X**  length of the input, in bits, right justified.  Note that the size of
X**  a "chunk" is just the input size minus the output size.
X**
X**  "0" is a vector of 0 bits of the same size (in bits) as the output of
X**  H (i.e., either 128 or 256 bits).
X**
X**  "chunk" is an array which holds the input string.  The final element of
X**  the array is left justified and zero-filled on the right.
X**
X*/
Xmain(ac, av)
X    int		ac;
X    char	*av[];
X{
X    WORD32	BitCount[2];
X    WORD32	hashArray[INPUTBLOCKSIZE];
X    WORD32	hash[OUTPUTBLOCKSIZE];
X    WORD32	Wbuffer[BUFFERSIZEINWORDS];
X    char	Cbuffer[BUFFERSIZE];
X    int		OutputBlockSize;
X    int		ChunkSize;
X    int		ByteCount;
X    int		Index;
X    int		GotEOF;
X    int		i;
X    int		level;
X
X    /* Set up defaults.  Four 32-bit word (128 bits) with two iterations. */
X    OutputBlockSize = 4;
X    ChunkSize = INPUTBLOCKSIZE - 4;
X    level = 2;
X
X    /* Parse JCL. */
X    while ((i = getopt(ac, av, "l:o:")) != EOF)
X	switch (i) {
X	default:
X	    Usage();
X	    /* NOTREACHED */
X	case 'l':
X	    level = atoi(optarg);
X	    if (level != 2 && level != 3 && level != 4)
X		Usage();
X	    break;
X	case 'o':
X	    OutputBlockSize = atoi(optarg);
X	    if (OutputBlockSize != 4 && OutputBlockSize != 8)
X		Usage();
X	    ChunkSize = INPUTBLOCKSIZE - OutputBlockSize;
X	    if ((BUFFERSIZEINWORDS % ChunkSize) != 0) {
X		(void)fprintf(stderr, "Buffer size is fouled up\n");
X		exit(1);
X	    }
X	    break;
X	}
X
X    /* Get input. */
X    ac -= optind;
X    av += optind;
X    switch (ac) {
X    default:
X	Usage();
X	/* NOTREACHED */
X    case 0:
X	break;
X    case 1:
X	if (freopen(av[0], "r", stdin) == NULL) {
X	    perror("No input");
X	    (void)fprintf(stderr, "Can't open \"%s\" for reading.\n", av[0]);
X	    Usage();
X	}
X	break;
X    }
X
X    /* Set up for the fast hash routine  */
X    SetupHash512();
X
X    BitCount[0] = 0;
X    BitCount[1] = 0;
X
X    /* Get some input. */
X    ByteCount = fread(Cbuffer, sizeof Cbuffer[0], SIZEOF(Cbuffer), stdin);
X    if (ByteCount < 0) {
X	perror("First read failed");
X	exit(1);
X    }
X    GotEOF = ByteCount != SIZEOF(Cbuffer);
X
X    /* Increment bit-count; bump upper 32 bits when lower 32 wraps. */
X    BitCount[1] += ByteCount * 8;
X    if (BitCount[1] < ByteCount * 8)
X	BitCount[0]++;
X
X    /* Zero out rest of buffer, convert to words, set readpoint. */
X    for (i = ByteCount; i < SIZEOF(Cbuffer); i++)
X	Cbuffer[i] = 0;
X    BytesToWords(Cbuffer, Wbuffer);
X
X    for (i = 0; i < SIZEOF(hashArray); i++)
X	hashArray[i] = 0;
X
X    /* Hash each chunk in the input (either 48 byte chunks or 32 byte chunks)
X     * and keep the result in hashArray.  Note that the first 16 (32)
X     * bytes of hashArray holds the output of the previous hash computation. */
X    Index = 0;
X    while (ByteCount > 0) {
X	if (Index + ChunkSize > SIZEOF(Cbuffer)) {
X	    (void)fprintf(stderr, "Can't happen, buffer overrun.\n");
X	    exit(1);
X	}
X
X	/* Get next chunk and hash it in. */
X	for (i = 0; i < ChunkSize; i++)
X	    hashArray[OutputBlockSize + i] = Wbuffer[Index + i];
X	Hash512(hashArray, hashArray, level, OutputBlockSize);
X
X	/* Move to next chunk. */
X	Index += ChunkSize;
X	ByteCount -= ChunkSize * 4;
X
X	/* Out of data -- read some more */
X	if (ByteCount <= 0) {
X	    if (GotEOF == 1)
X		ByteCount = 0;
X	    else {
X		if (ByteCount != 0) {
X		    (void)fprintf(stderr, "Can't happen, error near EOF.\n");
X		    exit(1);
X		}
X		ByteCount = fread(Cbuffer, sizeof Cbuffer[0],
X				SIZEOF(Cbuffer), stdin);
X		if (ByteCount < 0) {
X		    perror("Read failed");
X		    exit(1);
X		}
X		if (ByteCount != SIZEOF(Cbuffer))
X		    GotEOF = 1;
X	    }
X
X	    /* Increment bit-count; bump upper 32 bits when lower 32 wraps. */
X	    BitCount[1] += ByteCount * 8;
X	    if (BitCount[1] < ByteCount * 8)
X		BitCount[0] += 1;
X
X	    /* Zero out rest of buffer, convert to words, set readpoint. */
X	    for (i = ByteCount; i < SIZEOF(Cbuffer); i++)
X		Cbuffer[i] = 0;
X	    BytesToWords(Cbuffer, Wbuffer);
X	    Index = 0;
X	}
X    }
X
X
X    /* Zero out the remainder of hashArray.  */
X    for (i = 0; i < ChunkSize; i++)
X	hashArray[OutputBlockSize + i] = 0;
X
X    /* Put the 64-bit bit-count into the final 64-bits of the block about to
X     * be hashed */
X    hashArray[INPUTBLOCKSIZE - 2] = BitCount[0];
X    hashArray[INPUTBLOCKSIZE - 1] = BitCount[1];
X
X    /* Final hash down. */
X    Hash512(hash, hashArray, level, OutputBlockSize);
X
X    /* 'hash' now holds the hashed result, which is printed on stdout. */
X    for (i = 0; i < OutputBlockSize; i++)
X	(void)printf("%s%08x", i ? " " : "", hash[i]);
X    (void)printf("\n");
X    exit(0);
X}
END_OF_FILE
if test 8565 -ne `wc -c <'snefru.c'`; then
    echo shar: \"'snefru.c'\" unpacked with wrong size!
fi
# end of 'snefru.c'
fi
if test -f 'snefru.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'snefru.h'\"
else
echo shar: Extracting \"'snefru.h'\" \(2314 characters\)
sed "s/^X//" >'snefru.h' <<'END_OF_FILE'
X/*
X**  This is Snefru, derived from the Xerox Secure Hash Function.
X**  Snefru is a one-way hash function that provides authentication.
X**  It does not provide secrecy.
X**
X**  Snefru is named after a Pharaoh of ancient Egypt.
X**
X**  It is based on code that is:
X**	Copyright (c) Xerox Corporation 1989.  All rights reserved.
X**
X**	License to copy and use this software is granted provided that it
X**	is identified as the 'Xerox Secure Hash Function' in all material
X**	mentioning or referencing this software or this hash function.
X**
X**	License is also granted to make and use derivative works provided
X**	that such works are identified as 'derived from the Xerox Secure
X**	Hash Function' in all material mentioning or referencing the
X**	derived work.
X**
X**	Xerox Corporation makes no representations concerning either the
X**	merchantability of this software or the suitability of this
X**	software for any particular purpose.  It is provided "as is"
X**	without express or implied warranty of any kind.
X**
X**	These notices must be retained in any copies of any part of this
X**	software.
X**
X**  Based on the reference implementation (no algorithm changes) of
X**  version 2.0, July 31, 1989.  Implementor:  Ralph C. Merkle.
X**  This edition is by Rich $alz, <rsalz at bbn.com>.
X**  $Header: snefru.h,v 1.1 90/03/22 13:00:52 rsalz Exp $
X*/
X#include "patchlevel.h"
X
X#if	!defined(lint) && !defined(SABER)
X#define RCSID
X#endif	/* .. */
X
X    /* Size in 32-bit words of an input block to the hash routine. */
X#define INPUTBLOCKSIZE		  16
X    /* Size in 32-bit words of largest output block from the hash routine. */
X#define OUTPUTBLOCKSIZE		   8
X    /* This MUST be 3 * 2**n, where n > 5.  */
X#define BUFFERSIZE		3072
X    /* Buffer size is normally in bytes, but sometimes we need it in words. */
X#define BUFFERSIZEINWORDS	(BUFFERSIZE / 4)
X    /* Number of S boxes. */
X#define SBOXCOUNT		   8
X    /* Maximum valid value for wordCount. */
X#define WORDCOUNT		  16
X
X    /* This MUST be 32 bits. */
Xtypedef unsigned long int	 WORD32;
X    /* An S-box. */
Xtypedef WORD32			 SBOX[256];
X
X    /* The standard S boxes are defined in another file. */
Xextern SBOX	 SnefruSBoxes[SBOXCOUNT];
X
X#define CHECKSUMHDR	"X-Checksum-Snefru"
X#define HDRFIRSTCHAR	'X'
X#define TRUE		1
X#define FALSE		0
X#define HDRTEXTSIZE	(8 + 1 + 8 + 1 + 8 + 1 + 8)
END_OF_FILE
if test 2314 -ne `wc -c <'snefru.h'`; then
    echo shar: \"'snefru.h'\" unpacked with wrong size!
fi
# end of 'snefru.h'
fi
if test -f 'tests.sh' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tests.sh'\"
else
echo shar: Extracting \"'tests.sh'\" \(4334 characters\)
sed "s/^X//" >'tests.sh' <<'END_OF_FILE'
X#! /bin/sh
X##
X##  This is Snefru, derived from the Xerox Secure Hash Function.
X##  Snefru is a one-way hash function that provides authentication.
X##  It does not provide secrecy.
X##
X##  Snefru is named after a Pharaoh of ancient Egypt.
X##
X##  It is based on code that is:
X##      Copyright (c) Xerox Corporation 1989.  All rights reserved.
X##
X##      License to copy and use this software is granted provided that it
X##      is identified as the 'Xerox Secure Hash Function' in all material
X##      mentioning or referencing this software or this hash function.
X##
X##      License is also granted to make and use derivative works provided
X##      that such works are identified as 'derived from the Xerox Secure
X##      Hash Function' in all material mentioning or referencing the
X##      derived work.
X##
X##      Xerox Corporation makes no representations concerning either the
X##      merchantability of this software or the suitability of this
X##      software for any particular purpose.  It is provided "as is"
X##      without express or implied warranty of any kind.
X##
X##      These notices must be retained in any copies of any part of this
X##      software.
X##
X##  Based on the reference implementation (no algorithm changes) of
X##  version 2.0, July 31, 1989.  Implementor:  Ralph C. Merkle.
X##  This edition is by Rich $alz, <rsalz at bbn.com>.
X##  $Header: tests.sh,v 1.1 90/03/22 13:01:34 rsalz Exp $
X##
X##  Script to test SNEFRU one-way hash program.
X##
X
X##  This is a pain in the neck; we (portably) want a file with only a newline
X##  in it.
XT=snefruT$$
Xcat <<\EOF >$T
X
XEOF
X
Xtrap 'exec rm -f snefru?$$' 1 2 3 15
XI=snefruI$$
XO=snefruO$$
X
Xecho 'Testing SNEFRU...'
Xecho 'If you see any unusual output, examine this script to see what failed.'
Xecho ''
X./testboxes
X
Xecho ''
Xecho 'Testing known hashes...'
X./snefru <$T >$O
Xecho '13af7619 ab98d4b5 f5e0a9e6 b26b5452' >$I
Xdiff $O $I
X
Xecho 1 | ./snefru >$O
Xecho '578c83f8 8fe1f6a8 c119d2ba 3a9256c2' >$I
Xdiff $O $I
X
Xecho 12 | ./snefru >$O
Xecho '255468d4 b4bd985b 696a7313 6027fc80' >$I
Xdiff $O $I
X
Xecho 123 | ./snefru >$O
Xecho 'f5339a52 9c4dafc5 34fe3f0d 7a66baf7' >$I
Xdiff $O $I
X
Xecho 1234 | ./snefru >$O
Xecho '2645ff86 9a6c0ec6 5c49c20d d9050165' >$I
Xdiff $O $I
X
Xecho 12345 | ./snefru >$O
Xecho '387d2929 8ed52ece 88e64f38 fe4fdb11' >$I
Xdiff $O $I
X
Xecho 123456 | ./snefru >$O
Xecho 'f29f8915 d23a0e02 838cc2e2 75f5dfe7' >$I
Xdiff $O $I
X
Xecho 1234567 | ./snefru >$O
Xecho '4fb0f76e 9af16a2d 61844b9c e833e18f' >$I
Xdiff $O $I
X
Xecho 12345678 | ./snefru >$O
Xecho 'aacc56fc 85910fef e81fc697 6b061f4e' >$I
Xdiff $O $I
X
Xecho 123456789 | ./snefru >$O
Xecho 'e6997849 44ed68a1 c762ea1e 90c77967' >$I
Xdiff $O $I
X
X./snefru -l4 -o8 <$T >$O
Xecho \
X '6c504351 ce7f4b7a 93adb29a f9781ff9 2150f157 fee18661 eef511a3 0fc83ddf' >$I
Xdiff $O $I
X
Xecho '1' | ./snefru -l4 -o8 >$O
Xecho \
X '65d657f8 85ad8b4a b35999cc 3ded8b82 7cf71fa4 25424750 35778910 d6c2e320' >$I
Xdiff $O $I
X
Xecho '12' | ./snefru -l4 -o8 >$O
Xecho \
X '7636f3d1 af139cf9 58f46f99 66221282 a444732a 7de59da5 d3481c6b bd6e7092' >$I
Xdiff $O $I
X
Xecho '123' | ./snefru -l4 -o8 >$O
Xecho \
X 'cd3c7163 5b14c7c2 c24be864 4baab592 b8ab5b99 91ee5ee5 b3cf7a7f c6426ad7' >$I
Xdiff $O $I
X
Xecho '1234' | ./snefru -l4 -o8 >$O
Xecho \
X '9ba783a1 290cb21e fe196a02 3286ece5 49394c75 1ddd607e 5d67c4dc 549c62eb' >$I
Xdiff $O $I
X
Xecho '12345' | ./snefru -l4 -o8 >$O
Xecho \
X 'c9680da8 ef00d2f8 4459a8e9 b50ada71 c63cae6f dcb6f774 f6998783 30a4a1f4' >$I
Xdiff $O $I
X
Xecho '123456' | ./snefru -l4 -o8 >$O
Xecho \
X '7656d389 f980bbe8 94152abe c6dc5f16 faf21c60 3b8f5098 861acf3c c059467b' >$I
Xdiff $O $I
X
Xecho '1234567' | ./snefru -l4 -o8 >$O
Xecho \
X 'd96eb599 8377bb1d 74a02a2f 00ac9a85 3175250e 4796af36 36609747 372bba80' >$I
Xdiff $O $I
X
Xecho '12345678' | ./snefru -l4 -o8 >$O
Xecho \
X 'b7818f09 2118e98a 140af09a 6cca4e6f 1eba88e7 52c20174 653637c9 d628f33f' >$I
Xdiff $O $I
X
Xecho '123456789' | ./snefru -l4 -o8 >$O
Xecho \
X 'c2242249 1187baaa 94725400 08dffd5b 38f01557 9f3f2390 50969991 fdc1a810' >$I
Xdiff $O $I
X
X
Xecho ''
Xecho 'Testing hashnews...'
Xcat TestArticle >snefruA$$
X./hashnews -n snefruA$$
Xecho 'X-Checksum-Snefru: 1cb551db 1a84ad94 3d5d4267 571a9efd' >$I
Xgrep '^X-Checksum-Snefru: ' snefruA$$ >$O
Xdiff $O $I
X./hashnews -n <TestArticle >$O
Xdiff snefruA$$ $O
X
Xecho ''
Xecho 'Testing checkhash...'
Xcheckhash snefruA$$
X
Xrm -f snefru?$$
Xecho ''
Xecho 'Done.'
END_OF_FILE
if test 4334 -ne `wc -c <'tests.sh'`; then
    echo shar: \"'tests.sh'\" unpacked with wrong size!
fi
# end of 'tests.sh'
fi
echo shar: End of archive 1 \(of 4\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 4 archives.
    echo "Now see the README"
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.



More information about the Comp.sources.unix mailing list