194 lines
7.6 KiB
Plaintext
194 lines
7.6 KiB
Plaintext
shaX-asaddi (X = 1, 256, 384, 512)
|
|
==================================
|
|
Copyright (c) 2001-2003 Allan Saddi <allan@saddi.com>
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
1. Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY ALLAN SADDI AND HIS CONTRIBUTORS ``AS IS''
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
ARE DISCLAIMED. IN NO EVENT SHALL ALLAN SADDI OR HIS CONTRIBUTORS BE
|
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
Introduction
|
|
------------
|
|
These are portable implementations of the National Institute of
|
|
Standards and Technology's Secure Hash Algorithms. Implementations
|
|
for SHA-1, SHA-256, SHA-384, and SHA-512 are available. All are
|
|
equally portable, assuming your compiler supports 64-bit integers
|
|
(which gcc does).
|
|
|
|
The following documentation and examples will refer to the SHA-1
|
|
implementation. However, they equally apply to the SHA-256, SHA-384,
|
|
and SHA-512 implementations except where noted.
|
|
|
|
API
|
|
---
|
|
SHA1Context
|
|
This is the hash context. There should be one SHA1Context for each
|
|
object to be hashed. (This only applies if hashing is being done
|
|
in parallel. Otherwise, it's perfectly safe to reuse a SHA1Context
|
|
to hash objects serially, e.g. one file at a time.)
|
|
|
|
A SHA1Context can be declared static, automatic, or allocated from
|
|
the heap. There are certain alignment restrictions, but it shouldn't
|
|
be of any concern in normal usage (malloc() should return suitably
|
|
aligned memory, and the compiler will take care of the other cases).
|
|
|
|
There's nothing really special about a SHA1Context. It should be
|
|
safe to copy it, e.g. using memcpy() or bcopy().
|
|
|
|
void SHA1Init (SHA1Context *sc);
|
|
Initializes a SHA1Context. This should be called before any of the
|
|
following functions are called.
|
|
|
|
void SHA1Update (SHA1Context *sc, const void *data, uint32_t len);
|
|
Hashes some data. len is in bytes.
|
|
|
|
void SHA1Final (SHA1Context *sc, uint8_t hash[SHA1_HASH_SIZE]);
|
|
Gets the SHA-1 hash and "closes" the context. The context should
|
|
no longer be used. (Due to padding, etc.) If you wish to hash a
|
|
new set of data using the same SHA1Context, be sure to call
|
|
SHA1Init(). If you want to continue hashing data using the
|
|
same context, simply make a copy of the context and call
|
|
SHA1Final() on the copy.
|
|
|
|
hash may be NULL, in which case no hash is generated (but the
|
|
context is still closed). Regardless if hash is NULL or not, a
|
|
word representation of the hash (32-bit words for SHA-1 and SHA-256,
|
|
64-bit words for SHA-384 and SHA-512) is available in
|
|
sc->hash[0..SHA1_HASH_WORDS-1]. This may be useful in other
|
|
applications.
|
|
|
|
If being used for cryptography, it's probably a good idea to zero-out
|
|
the SHA1Context after you're done.
|
|
|
|
Compile-Time Options
|
|
--------------------
|
|
WORDS_BIGENDIAN
|
|
Define this if you're on a big-endian processor.
|
|
|
|
RUNTIME_ENDIAN
|
|
Define this if you would rather determine processor endianess at
|
|
runtime. WORDS_BIGENDIAN will be ignored if this is defined. The
|
|
generated code may be slightly slower, but at least you won't
|
|
have to worry about big-endian vs. little-endian!
|
|
|
|
SHA1_FAST_COPY
|
|
Defining this will eliminate some copying overhead of hashed data.
|
|
Also, calculating the hash in SHA1Final() should be slightly faster.
|
|
This isn't on by default because of alignment issues. See Portability
|
|
Notes.
|
|
|
|
SHA1_UNROLL
|
|
If undefined, it will default to 1. This is the number of rounds
|
|
to perform in a loop iteration. The larger the number, the bigger
|
|
the code, but also the less loop overhead there will be. It must
|
|
be between 1 and 20 inclusive, and it must be a factor of 20 or
|
|
a product of some of its factors. (Don't worry, you'll get a nice
|
|
error message if you defined it wrong.)
|
|
|
|
SHA-256 is the only other implementation that has something
|
|
similar (SHA256_UNROLL). It must be a power of 2 between 1 and
|
|
64 inclusive and it defaults to 1.
|
|
|
|
You may want to experiment with different values. I've generally
|
|
found that big code is slower, despite being more efficient. This
|
|
is most likely due to cache space limitations.
|
|
|
|
SHA1_TEST
|
|
Define this to compile a simple test program. See the comments in
|
|
sha1.c for what the output should look like. If the output doesn't
|
|
look right, try flipping WORDS_BIGENDIAN (define it if you didn't
|
|
define it, undefine it if you did). For example:
|
|
|
|
> gcc -Wall -O2 -DSHA1_TEST -o test sha1.c
|
|
|
|
Portability Notes
|
|
-----------------
|
|
As was mentioned, you need a compiler that supports 64-bit integers.
|
|
You will also need <inttypes.h> for uint8_t, uint32_t, uint64_t. I'm not
|
|
sure how common or standard this include file is, but it was available
|
|
on all platforms I tested.
|
|
|
|
It was actually surprising to find that all but one of the processors
|
|
tested supported unaligned word accesses. (I came from a MC680x0 +
|
|
MIPS background.) I developed the code on i386 and powerpc architectures,
|
|
which both supported unaligned words. It wasn't until I tried out my
|
|
code on a sparc that I realized I needed to be a little more careful.
|
|
(Bus errors... yum!)
|
|
|
|
With SHA1_FAST_COPY undefined, the code should be very portable. If you
|
|
define it, the code may be slightly faster, but there are a few things
|
|
you need to be careful about, especially on architectures that don't
|
|
support unaligned word accesses. Here are some general guidelines:
|
|
|
|
Use SHA1_FAST_COPY if:
|
|
|
|
* You call SHA1Update() with a consistent buffer size every time.
|
|
(The last time you call it before calling SHA1Final() can be the
|
|
exception.) And:
|
|
|
|
* The buffer size is a multiple of 64-bytes (SHA-1, SHA-256) or
|
|
128-bytes (SHA-384, SHA-512). And:
|
|
|
|
* The buffer address is evenly divisible by 4 (SHA-1, SHA-256) or
|
|
evenly divisible by 8 (SHA-384, SHA-512). And finally:
|
|
|
|
* The hash address passed to SHA1Final() is evenly divisible by
|
|
4 (SHA-1, SHA-256) or evenly divisible by 8 (SHA-384, SHA-512).
|
|
|
|
You can ensure proper address alignment by using malloc() (read your
|
|
man page to verify this) or by doing something like:
|
|
|
|
union {
|
|
uint32_t w; /* use uint64_t for SHA-384, SHA-512 */
|
|
uint8_t b[SHA1_HASH_SIZE];
|
|
} hash;
|
|
...
|
|
SHA1Final (&sha, hash.b);
|
|
|
|
If you're on an architecture that supports unaligned word accesses,
|
|
it may be safe to define SHA1_FAST_COPY anyway. However, it would be
|
|
a good idea to experiment, since unaligned word accesses may actually
|
|
take longer and cancel the benefits of faster code.
|
|
|
|
Example
|
|
-------
|
|
#include <inttypes.h> /* for uint8_t, etc. */
|
|
#include <string.h> /* for memset() */
|
|
|
|
#include "sha1.h"
|
|
|
|
...
|
|
SHA1Context sha;
|
|
uint8_t hash[SHA1_HASH_SIZE];
|
|
...
|
|
SHA1Init (&sha);
|
|
...
|
|
SHA1Update (&sha, buffer, length);
|
|
...
|
|
SHA1Update (&sha, buffer2, length2);
|
|
...
|
|
call SHA1Update() with more data
|
|
...
|
|
SHA1Final (&sha, hash);
|
|
memset (&sha, 0, sizeof (sha)); /* for the truly paranoid */
|
|
...
|
|
do something with hash
|
|
...
|