From 7b89bf6cc758b9ac74a225f3cafb9f64992dee7a Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Mon, 23 Sep 2013 10:06:33 -0700 Subject: [PATCH] Add FixedArray, IntrusiveArray, Crypto --- Builds/VisualStudio2012/beast.vcxproj | 32 + Builds/VisualStudio2012/beast.vcxproj.filters | 47 +- beast/Crypto.h | 26 + beast/FixedArray.h | 165 +++ beast/Intrusive.h | 1 + beast/crypto/Crypto.cpp | 25 + beast/crypto/Sha256.h | 156 +++ beast/crypto/impl/Sha256.cpp | 147 +++ beast/crypto/impl/sha2/README | 277 +++++ beast/crypto/impl/sha2/sha2.c | 1052 +++++++++++++++++ beast/crypto/impl/sha2/sha2.h | 135 +++ beast/crypto/impl/sha2/sha2prog.c | 132 +++ beast/crypto/impl/sha2/sha2speed.c | 174 +++ beast/crypto/impl/sha2/sha2test.pl | 358 ++++++ beast/intrusive/IntrusiveArray.h | 187 +++ beast/net/IPEndpoint.h | 10 +- modules/beast_crypto/math/BinaryEncoding.cpp | 6 +- modules/beast_crypto/math/UnsignedInteger.h | 68 +- 18 files changed, 2954 insertions(+), 44 deletions(-) create mode 100644 beast/Crypto.h create mode 100644 beast/FixedArray.h create mode 100644 beast/crypto/Crypto.cpp create mode 100644 beast/crypto/Sha256.h create mode 100644 beast/crypto/impl/Sha256.cpp create mode 100644 beast/crypto/impl/sha2/README create mode 100644 beast/crypto/impl/sha2/sha2.c create mode 100644 beast/crypto/impl/sha2/sha2.h create mode 100644 beast/crypto/impl/sha2/sha2prog.c create mode 100644 beast/crypto/impl/sha2/sha2speed.c create mode 100644 beast/crypto/impl/sha2/sha2test.pl create mode 100644 beast/intrusive/IntrusiveArray.h diff --git a/Builds/VisualStudio2012/beast.vcxproj b/Builds/VisualStudio2012/beast.vcxproj index f55e325993..f0916e7e26 100644 --- a/Builds/VisualStudio2012/beast.vcxproj +++ b/Builds/VisualStudio2012/beast.vcxproj @@ -21,6 +21,8 @@ + + @@ -87,7 +89,11 @@ + + + + @@ -95,6 +101,7 @@ + @@ -384,6 +391,31 @@ + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + true diff --git a/Builds/VisualStudio2012/beast.vcxproj.filters b/Builds/VisualStudio2012/beast.vcxproj.filters index b0278d174b..7afce30be6 100644 --- a/Builds/VisualStudio2012/beast.vcxproj.filters +++ b/Builds/VisualStudio2012/beast.vcxproj.filters @@ -67,6 +67,12 @@ beast_core + + beast\crypto\impl\sha2 + + + beast\crypto\impl\sha2 + @@ -249,6 +255,15 @@ {1fff3bd8-44ae-41df-8dd4-8bb6f07b2908} + + {9c1ef4c4-5623-4500-859f-12d6ce5ae362} + + + {fc3d3f14-9ba1-43e4-b086-cbbd2f63b944} + + + {44489531-f44a-439a-a6ea-d32c252b1e8b} + @@ -530,7 +545,6 @@ beast_core\zip\zlib - beast_core\memory @@ -1161,6 +1175,22 @@ beast\http + + + beast + + + beast\intrusive + + + beast + + + beast\crypto\impl\sha2 + + + beast\crypto + @@ -1712,6 +1742,21 @@ beast\http\impl + + beast\crypto\impl\sha2 + + + beast\crypto\impl\sha2 + + + beast\crypto\impl\sha2 + + + beast\crypto + + + beast\crypto\impl + diff --git a/beast/Crypto.h b/beast/Crypto.h new file mode 100644 index 0000000000..a5f9f6d12a --- /dev/null +++ b/beast/Crypto.h @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CRYPTO_H_INCLUDED +#define BEAST_CRYPTO_H_INCLUDED + +#include "crypto/api/Sha256.h" + +#endif + diff --git a/beast/FixedArray.h b/beast/FixedArray.h new file mode 100644 index 0000000000..e9d50488af --- /dev/null +++ b/beast/FixedArray.h @@ -0,0 +1,165 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_FIXEDARRAY_H_INCLUDED +#define BEAST_FIXEDARRAY_H_INCLUDED + +#include "Config.h" + +#include +#include +#include + +namespace beast { + +// Ideas from Boost + +/** An array whose size is determined at compile-time. + The interface tries to follow std::vector as closely as possible within + the limitations of having a fixed size. +*/ +template +class FixedArray +{ +public: + T values [N]; + + typedef T value_type; + typedef T* iterator; + typedef T const* const_iterator; + typedef T& reference; + typedef T const& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + // iterators + iterator begin() { return values; } + const_iterator begin() const { return values; } + const_iterator cbegin() const { return values; } + iterator end() { return values+N; } + const_iterator end() const { return values+N; } + const_iterator cend() const { return values+N; } + + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + const_reverse_iterator crbegin() const { return const_reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } + const_reverse_iterator crend() const { return const_reverse_iterator(begin()); } + + reference operator[](size_type i) + { + bassert (i < N); + return values[i]; + } + + const_reference operator[](size_type i) const + { + bassert (i < N); + return values[i]; + } + + reference at(size_type i) { rangecheck(i); return values[i]; } + const_reference at(size_type i) const { rangecheck(i); return values[i]; } + + reference front() { return values[0]; } + reference back() { return values[N-1]; } + const_reference front () const { return values[0]; } + const_reference back() const { return values[N-1]; } + + static size_type size() { return N; } + static bool empty() { return false; } + static size_type max_size() { return N; } + + enum { static_size = N }; + + T const* data() const { return values; } + T* data() { return values; } + T* c_array() { return values; } + + template + FixedArray& operator= (FixedArray const& rhs) + { + std::copy (rhs.begin(), rhs.end(), begin()); + return *this; + } + + void assign (T const& value) { fill (value); } + + void fill (T const& value) + { + std::fill_n (begin(), size(), value); + } + + void clear () + { + fill (T ()); + } + + static void rangecheck (size_type i) + { + if (i >= size()) + throw std::out_of_range ("FixedArray<>: index out of range"); + } +}; + +//------------------------------------------------------------------------------ + +template +bool operator== (FixedArray const& lhs, FixedArray const& rhs) +{ + return std::equal (lhs.begin(), lhs.end(), rhs.begin()); +} + +template +bool operator!= (FixedArray const& lhs, FixedArray const& rhs) +{ + return !(lhs==rhs); +} + +template +bool operator< (FixedArray const& lhs, FixedArray const& rhs) +{ + return std::lexicographical_compare (lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); +} + +template +bool operator> (FixedArray const& lhs, FixedArray const& rhs) +{ + return rhs +bool operator<= (FixedArray const& lhs, FixedArray const& rhs) +{ + return !(rhs +bool operator>= (FixedArray const& lhs, FixedArray const& rhs) +{ + return !(lhs + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "BeastConfig.h" + +#include "../CStdInt.h" +#include "../config/PlatformConfig.h" + +#include "impl/Sha256.cpp" diff --git a/beast/crypto/Sha256.h b/beast/crypto/Sha256.h new file mode 100644 index 0000000000..95865d8b34 --- /dev/null +++ b/beast/crypto/Sha256.h @@ -0,0 +1,156 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CRYPTO_Sha256_H_INCLUDED +#define BEAST_CRYPTO_Sha256_H_INCLUDED + +#include "../config/PlatformConfig.h" +#include "../CStdInt.h" +#include "../FixedArray.h" + +//------------------------------------------------------------------------------ + +namespace beast { +namespace Sha256 { + +enum +{ + digestLength = 32, + blockLength = 64 +}; + +/** A container suitable for holding the resulting hash. */ +typedef FixedArray digest_type; + +namespace detail { +struct Context +{ + beast::uint32 state[8]; + beast::uint64 bitcount; + beast::uint8 buffer[Sha256::blockLength]; +}; +} + +/** Computes the Sha256 hash of data. */ +class Context +{ +public: + /** Create a new hasher prepared for input. */ + Context(); + + /** Update the hashing context with the input sequence. */ + /** @{ */ + void update (void const* buffer, std::size_t bytes); + + void update (int8 const* begin, int8 const* end) + { + update (begin, end - begin); + } + + void update (uint8 const* begin, uint8 const* end) + { + update (begin, end - begin); + } + + template + void update (T const& t) + { + update (&t, sizeof(T)); + } + /** @} */ + + /** Finalize the hash process and store the digest. + The memory pointed to by `digest` must be at least digestLength + bytes. This object may not be re-used after calling finish. + @return A pointer to the passed hash buffer. + */ + /** @{ */ + void* finish (void* digest); + + digest_type& finish (digest_type& digest) + { + finish (digest.c_array()); + return digest; + } + + digest_type finish () + { + digest_type digest; + finish (digest); + return digest; + } + /** @} */ + +private: + detail::Context m_context; +}; + +//------------------------------------------------------------------------------ + +/** Returns the hash produced by a single octet equal to zero. */ +digest_type const& empty_digest(); + +/** Performs an entire hashing operation in a single step. + A zero length input sequence produces the empty_digest(). + @return The resulting digest depending on the arguments. +*/ +/** @{ */ +void* hash (void const* buffer, std::size_t bytes, void* digest); +digest_type& hash ( void const* buffer, std::size_t bytes, digest_type& digest); +digest_type hash (void const* buffer, std::size_t bytes); +void* hash (int8 const* begin, int8 const* end, void* digest); +void* hash (uint8 const* begin, uint8 const* end, void* digest); +digest_type hash (int8 const* begin, int8 const* end); +digest_type hash (uint8 const* begin, uint8 const* end); + +template +void* hash (T const& t, void* digest) +{ + return hash (&t, sizeof(T), digest); +} + +template +digest_type& hash (T const& t, digest_type& digest) +{ + return hash (&t, sizeof(T), digest); +} + +template +digest_type hash (T const& t) +{ + digest_type digest; + hash (&t, sizeof(T), digest); + return digest; +} +/** @} */ + +/** Calculate the hash of a hash in one step. + The memory pointed to by source_digest must be at + least digestLength bytes or undefined behavior results. +*/ +/** @{ */ +void* hash (void const* source_digest, void* digest); +digest_type& hash (void const* source_digest, digest_type& digest); +digest_type hash (void const* source_digest);; +/** @} */ + +} +} + +#endif diff --git a/beast/crypto/impl/Sha256.cpp b/beast/crypto/impl/Sha256.cpp new file mode 100644 index 0000000000..261508ea92 --- /dev/null +++ b/beast/crypto/impl/Sha256.cpp @@ -0,0 +1,147 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "../Sha256.h" + +namespace beast { +namespace Sha256 { + +#ifndef LITTLE_ENDIAN +# define LITTLE_ENDIAN 1234 +#endif +#ifndef BIG_ENDIAN +# define BIG_ENDIAN 4321 +#endif +#if !defined(BYTE_ORDER) +# if BEAST_BIG_ENDIAN +# define BYTE_ORDER BIG_ENDIAN +# else +# define BYTE_ORDER LITTLE_ENDIAN +# endif +#endif + +//#define SHA2_USE_INTTYPES_H + +namespace detail { +typedef uint8 u_int8_t; +typedef uint32 u_int32_t; +typedef uint64 u_int64_t; +#include "sha2/sha2.c" +} + +Context::Context () +{ + detail::SHA256_Init (&m_context); +} + +void Context::update (void const* buffer, std::size_t bytes) +{ + detail::SHA256_Update (&m_context, static_cast (buffer), bytes); +} + +void* Context::finish (void* hash) +{ + detail::SHA256_Final (static_cast (hash), &m_context); + return hash; +} + +//------------------------------------------------------------------------------ + +digest_type const& empty_digest() +{ + struct Holder + { + Holder () + { + uint8 zero (0); + hash (zero, digest); + } + + digest_type digest; + }; + + static Holder const holder; + + return holder.digest; +} + +void* hash (void const* buffer, std::size_t bytes, void* digest) +{ + Context h; + h.update (buffer, bytes); + h.finish (digest); + return digest; +} + +digest_type& hash (void const* buffer, std::size_t bytes, digest_type& digest) +{ + hash (buffer, bytes, digest.c_array()); + return digest; +} + +digest_type hash (void const* buffer, std::size_t bytes) +{ + digest_type digest; + hash (buffer, bytes, digest); + return digest; +} + +void* hash (int8 const* begin, int8 const* end, void* digest) +{ + return hash (begin, end - begin, digest); +} + +void* hash (uint8 const* begin, uint8 const* end, void* digest) +{ + return hash (begin, end - begin, digest); +} + +digest_type hash (int8 const* begin, int8 const* end) +{ + digest_type digest; + hash (begin, end - begin, digest); + return digest; +} + +digest_type hash (uint8 const* begin, uint8 const* end) +{ + digest_type digest; + hash (begin, end - begin, digest); + return digest; +} + +void* hash (void const* source_digest, void* digest) +{ + return hash (source_digest, digestLength, digest); +} + +digest_type& hash (void const* source_digest, digest_type& digest) +{ + return hash (source_digest, digestLength, digest); +} + +digest_type hash (void const* source_digest) +{ + digest_type digest; + hash (source_digest, digestLength, digest); + return digest; +} + +} +} diff --git a/beast/crypto/impl/sha2/README b/beast/crypto/impl/sha2/README new file mode 100644 index 0000000000..a1b684d1e0 --- /dev/null +++ b/beast/crypto/impl/sha2/README @@ -0,0 +1,277 @@ +VERSION: + +This is version 1.0.1 RELEASE + +While this is my "release" version, due to lack of additional +official test vectors against which to verify this implementation's +correctness, beware that there may be implementation bugs. Also, +it has not yet been tested on very many other architectures, +big-endian machines in particular. + + +LICENSE: + +This implementation is released freely under an open-source BSD +license which appears at the top of each source code file. + + +WHAT IT IS: + +The files sha2.h and sha2.c implement the SHA-256, SHA-384, and SHA-512 +hash algorithms as described in the PDF document found at the following +web address: + + http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf + +The interface is similar to the interface to SHA-1 found in the OpenSSL +library. + +The file sha2prog.c is a simple program that accepts input from either +STDIN or reads one or more files specified on the command line, and then +generates the specified hash (either SHA-256, SHA-384, SHA-512, or any +combination thereof, including all three at once). + + +LIMITATIONS: + +This implementation has several limitations: + + * Input data is only accepted in octet-length increments. No sub-byte + data is handled. The NIST document describes how to handle sub-byte + input data, but for ease of implementation this version will only + accept message data in multiples of bytes. + * This implementation utilizes 64-bit integer data types. If your + system and compiler does not have a 64-bit integer data type, this + implementation will not work. + * Because of the use of 64-bit operations, many 32-bit architectures + that do have 64-bit data types but do operations most efficiently + on 32-bit words, this implementation may be slower than an + implementation designed to use only 32-bit words (emulating the + 64-bit operations). + * On platforms with 128-bit integer data types, the SHA-384 and SHA-512 + bit counters used by this implementation might be better off using + the 128-bit type instead of simulating it with two 64-bit integers. + * This implementation was written in C in hopes of portability and for + the fun of it during my spare time. It is probably not the most + efficient or fastest C implementation. I welcome suggestions, + however, that suggest ways to speed things up without breaking + portability. I also welcome suggestions to improve portability. + * As mentioned above, this code has NOT been thoroughly tested. + This is perhaps the most severe limitation. + + +BEFORE YOU COMPILE (OPTIONS): + +Each of the options described below may either be defined in the sha2.h +header file (or in the sha2.c file in some cases), or on the command +line at compile time if your compiler supports such things. For +example: + + #define SHA2_USE_INTTYPES_H + #define SHA2_UNROLL_TRANSFORM + +Or: + + cc -c -DSHA2_UNROLL_TRANSFORM sha2.c + cc -c -DBYTE_ORDER=4321 -DBIG_ENDIAN=4321 sha2.c + +Here are the available options. Read on below for a description of +each one: + + SHA2_USE_INTTYPES_H + SHA2_USE_MEMSET_MEMCPY/SHA2_USE_BZERO_BCOPY + SHA2_UNROLL_TRANSFORM + BYTE_ORDER (LITTLE_ENDIAN/BIG_ENDIAN) + +* SHA2_USE_INTTYPES_H option: +By default, this code uses u_intXX_t data types for 8 bit, 32 bit, and +64 bit unsigned integer type definitions. Most BSD systems define these, +as does Linux. However, some (like Compaq's Tru64 Unix) may instead +use uintXX_t data types as defined by recent ANSI C standards and as +included in the inttypes.h header file. Those wanting to use inttypes.h +need to define this either in sha.h or at compile time. + +On those systems where NEITHER definitions are available, you will need +to edit both sha2.h and sha2.c and define things by hand in the appropriate +sections. + +* BYTE_ORDER definitions: +This code assumes that BYTE_ORDER will be defined by the system during +compile to either equal LITTLE_ENDIAN or BIG_ENDIAN. If your system +does not define these, you may need to define them by hand in the sha.c +file according to the byte ordering conventions of your system. + +* SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY +The code in sha2.c can use either memset()/memcpy() for memory block +operations, or bzero()/mcopy(). If you define neither of these, the +code will default to memset()/memcpy(). You can define either at the +command line or in sha2.h or in sha2.c. + +* SHA2_UNROLL_TRANSFORM +By defining this either on the command line or in sha2.h or sha2.c, +the code will use macros to partially "unroll" the SHA transform +function. This usually generates bigger executables. It CAN (but +not necessarily WILL) generate faster code when you tell your compiler +to optimize things. For example, on the FreeBSD and Linux x86 systems +I tested things on (using gcc), when I optimized with just -O2 and +unrolled the transform, the hash transform was faster by 15-30%. On +these same systems, if I did NO optimization, the unrolled transform +was SLOWER, much slower (I'm guessing because the code was breaking +the cache, but I'm not sure). Your mileage may vary. + + +PORTABILITY: + +The code in sha2.c and sha2.h is intended to be portable. It may +require that you do a few #definitions in the .h file. I've successfully +compiled and tested the sha2.c and sha2.h code on Apple's OS X (on +a PPC), FreeBSD 4.1.1 on Intel, Linux on Intel, FreeBSD on the Alpha, +and even under Windows98SE using Metrowerks C. The utility/example +programs (sha2prog.c, sha2test.c, and sha2speed.c) will very likely +have more trouble in portability since they do I/O. + +To get sha2.c/sha2.h working under Windows, I had to define +SHA2_USE_INTTYPES_H, BYTE_ORDER, LITTLE_ENDIAN, and had to comment +out the include of in sha2.h. With a bit more work +I got the test program to run and verified that all the test +cases passed. + + +SUGGESTIONS/BUG FIXES: + +If you make changes to get it working on other architectures, if you fix +any bugs, or if you make changes that improve this implementation's +efficiency that would be relatively portable and you're willing to release +your changes under the same license, please send them to me for possible +inclusion in future versions. + +If you know where I can find some additional test vectors, please let me +know. + + +CHANGE HISTORY: + +0.8 to 0.9 - Fixed spelling errors, changed to u_intXX_t type usage, + removed names from prototypes, added prototypes to sha2.c, + and a few things I can't recall. + +0.9 to 0.9.5 - Add a new define in sha2.c that permits one to compile + it to either use memcpy()/memset() or bcopy()/bzero() + for memory block copying and zeroing. Added support + for unrolled SHA-256/384/512 transform loops. Just + compile with SHA2_UNROLL_TRANSFORM to enable. It takes + longer to compile, but I hope it is a bit faster. I + need to do some test to see whether or not it is. Oh, + in sha2.c, you either need to define SHA2_USE_BZERO_BCOPY + or SHA2_USE_MEMSET_MEMCPY to choose which way you want + to compile. *Whew* It's amazing how quickly something + simple starts to grow more complex even in the span of + just a few hours. I didn't really intend to do this much. +0.9.5 to 0.9.6 - Added a test program (sha2test) which tests against several + known test vectors. WARNING: Some of the test output + hashes are NOT from NIST's documentation and are the + output of this implementation and so may be incorrect. +0.9.6 to 0.9.7 - Fixed a bug that could cause invalid output in certain + cases and added an assumed scenario where zero-length + data is hashed. Also changed the rotation macros to use + a temporary variable as this reduces the number of operations. + When data is fed in blocks of the right length, copying of + data is reduced in this version. Added SHAYXZ_Data() + functions for ease of hashing a set of data. Added another + file sha2speed.c for doing speed testing. Added another test + vector with a larger data size (16KB). Fixed u_intXX_t and + uintXX_t handling by adding a define for SHA2_USE_INTTYPES_H + as well as made a few other minor changes to get rid of + warnings when compiling on Compaq's Tru64 Unix. +0.9.7 to 0.9.8 - The bug fix in 0.9.7 was incomplete and in some cases made + things worse. I believe that 0.9.8 fixes the bug completely + so that output is correct. I cannot verify this, however, + because of the lack of test vectors against which to do such + verification. All versions correctly matched the very few + NIST-provided vectors, but unfortunately the bug only + appeared in longer message data sets. +0.9.8 to 0.9.9 - Fixed some really bad typos and mistakes on my part that + only affected big-endian systems. I didn't have direct + access for testing before this version. Thanks to + Lucas Marshall for giving me access to his OS X system. +0.9.9 to 1.0.0b1 Added a few more test samples and made a few changes to + make things easier compiling on several other platforms. + Also I experimented with alternate macro definitions + in the SHA2_UNROLL_TRANSFORM version (see sha2.slower.c) + and eliminated the T1 temporary variable (the compiler + would of course still use internal temporary storage + during expression evaluation, but I'd hoped the compiler + would be more efficient), but unfortunately under FreeBSD + 4.1.1-STABLE on an x86 platform, the change slowed things + down. +1.0.0b1 to 1.0 RELEASE Fixed an off-by-one implementation bug that affected + SHA-256 when hashed data length L = 55 + 64 * X where X is + either zero or a positive integer, and another (basically + the same bug) bug in SHA-384 and SHA-512 that showed up when + hashed data lengths L = 111 + 128 * X. Thanks to Rogier + van de Pol for sending me test data that revealed the bug. + The fix was very simple (just two tiny changes). Also, + I finally put the files into RCS so future changes will be + easier to manage. The sha2prog.c file was rewritten to + be more useful to me, and I got rid of the old C testing + program and now use a perl script with a subdirectory full + of test data. It's a more flexible test system. + +1.0 to 1.0.1 - Specified the specific *_CTX structure in the MEMSET_BZERO + macro doing clean-up after hashing. This should eliminate + some warnings using Clang in version 3.0 (trunk 135348). + Thanks, Stephane Leon for reporting this. + + +LATEST VERSION: + +The latest version and documentation (if any ;) should always be available +on the web at: + + http://www.aarongifford.com/computers/sha.html + + +CONTACT ME: + +I can be reached via email at: + + Aaron Gifford + +Please don't send support questions. I don't have the time to answer and +they'll probably be ignored. Bug fixes, or patches that add something useful +will be gratefully accepted, however. + +If you use this implementation, I would enjoy getting a brief email message +letting me know who you are and what use to which it is being put. There +is no requirement to do so. I just think it would be fun. + + +EXAMPLES: + +Here's an example of compiling and using the sha2 program (in this example +I build it using the unrolled transform version with -O2 optimizations), +and then running the perl testing script: + + cc -O2 -DSHA2_UNROLL_TRANSFORM -Wall -o sha2 sha2prog.c sha2.c + % ./sha2test.pl + + [most of the perl script output deleted for brevity] + + ===== RESULTS (18 VECTOR DATA FILES HASHED) ===== + + HASH TYPE NO. OF TESTS PASSED FAILED + --------- ------------ ------ ------ + SHA-256 18 18 0 + SHA-384 18 18 0 + SHA-512 18 18 0 + ---------------------------------------------- + TOTAL: 54 54 0 + + NO ERRORS! ALL TESTS WERE SUCCESSFUL! + + ALL TEST VECTORS PASSED! + +That's all folks! Have fun! + +Aaron out. + diff --git a/beast/crypto/impl/sha2/sha2.c b/beast/crypto/impl/sha2/sha2.c new file mode 100644 index 0000000000..ab71a26644 --- /dev/null +++ b/beast/crypto/impl/sha2/sha2.c @@ -0,0 +1,1052 @@ +/* + * FILE: sha2.c + * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ + * + * Copyright (c) 2000-2001, Aaron D. Gifford + * 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. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``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 THE AUTHOR OR CONTRIBUTOR(S) 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. + * + */ + +#include /* memcpy()/memset() or bcopy()/bzero() */ +#include /* assert() */ +#include "sha2.h" + +/* + * ASSERT NOTE: + * Some sanity checking code is included using assert(). On my FreeBSD + * system, this additional code can be removed by compiling with NDEBUG + * defined. Check your own systems manpage on assert() to see how to + * compile WITHOUT the sanity checking code on your system. + * + * UNROLLED TRANSFORM LOOP NOTE: + * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform + * loop version for the hash transform rounds (defined using macros + * later in this file). Either define on the command line, for example: + * + * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c + * + * or define below: + * + * #define SHA2_UNROLL_TRANSFORM + * + */ + + +/*** SHA-256/384/512 Machine Architecture Definitions *****************/ +/* + * BYTE_ORDER NOTE: + * + * Please make sure that your system defines BYTE_ORDER. If your + * architecture is little-endian, make sure it also defines + * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are + * equivilent. + * + * If your system does not define the above, then you can do so by + * hand like this: + * + * #define LITTLE_ENDIAN 1234 + * #define BIG_ENDIAN 4321 + * + * And for little-endian machines, add: + * + * #define BYTE_ORDER LITTLE_ENDIAN + * + * Or for big-endian machines: + * + * #define BYTE_ORDER BIG_ENDIAN + * + * The FreeBSD machine this was written on defines BYTE_ORDER + * appropriately by including (which in turn includes + * where the appropriate definitions are actually + * made). + */ +#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) +#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN +#endif + +/* + * Define the followingsha2_* types to types of the correct length on + * the native archtecture. Most BSD systems and Linux define u_intXX_t + * types. Machines with very recent ANSI C headers, can use the + * uintXX_t definintions from inttypes.h by defining SHA2_USE_INTTYPES_H + * during compile or in the sha.h header file. + * + * Machines that support neither u_intXX_t nor inttypes.h's uintXX_t + * will need to define these three typedefs below (and the appropriate + * ones in sha.h too) by hand according to their system architecture. + * + * Thank you, Jun-ichiro itojun Hagino, for suggesting using u_intXX_t + * types and pointing out recent ANSI C support for uintXX_t in inttypes.h. + */ + +typedef u_int8_t sha2_byte; /* Exactly 1 byte */ +typedef u_int32_t sha2_word32; /* Exactly 4 bytes */ +typedef u_int64_t sha2_word64; /* Exactly 8 bytes */ + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +/* NOTE: Most of these are in sha2.h */ +#define SHA256_SHORT_BLOCK_LENGTH (Sha256::blockLength - 8) +#define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16) +#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) + +/*** ENDIAN REVERSAL MACROS *******************************************/ +#if BYTE_ORDER == LITTLE_ENDIAN +#define REVERSE32(w,x) { \ + sha2_word32 tmp = (w); \ + tmp = (tmp >> 16) | (tmp << 16); \ + (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ +} +#define REVERSE64(w,x) { \ + sha2_word64 tmp = (w); \ + tmp = (tmp >> 32) | (tmp << 32); \ + tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ + ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ + (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ + ((tmp & 0x0000ffff0000ffffULL) << 16); \ +} +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +/* + * Macro for incrementally adding the unsigned 64-bit integer n to the + * unsigned 128-bit integer (represented using a two-element array of + * 64-bit words): + */ +#define ADDINC128(w,n) { \ + (w)[0] += (sha2_word64)(n); \ + if ((w)[0] < (n)) { \ + (w)[1]++; \ + } \ +} + +/* + * Macros for copying blocks of memory and for zeroing out ranges + * of memory. Using these macros makes it easy to switch from + * using memset()/memcpy() and using bzero()/bcopy(). + * + * Please define either SHA2_USE_MEMSET_MEMCPY or define + * SHA2_USE_BZERO_BCOPY depending on which function set you + * choose to use: + */ +#if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY) +/* Default to memset()/memcpy() if no option is specified */ +#define SHA2_USE_MEMSET_MEMCPY 1 +#endif +#if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY) +/* Abort with an error if BOTH options are defined */ +#error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both! +#endif + +#ifdef SHA2_USE_MEMSET_MEMCPY +#define MEMSET_BZERO(p,l) memset((p), 0, (l)) +#define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l)) +#endif +#ifdef SHA2_USE_BZERO_BCOPY +#define MEMSET_BZERO(p,l) bzero((p), (l)) +#define MEMCPY_BCOPY(d,s,l) bcopy((s), (d), (l)) +#endif + + +/*** THE SIX LOGICAL FUNCTIONS ****************************************/ +/* + * Bit shifting and rotation (used by the six SHA-XYZ logical functions: + * + * NOTE: The naming of R and S appears backwards here (R is a SHIFT and + * S is a ROTATION) because the SHA-256/384/512 description document + * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this + * same "backwards" definition. + */ +/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ +#define R(b,x) ((x) >> (b)) +/* 32-bit Rotate-right (used in SHA-256): */ +#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) +/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ +#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) + +/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +/* Four of six logical functions used in SHA-256: */ +#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) +#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) +#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) +#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) + +/* Four of six logical functions used in SHA-384 and SHA-512: */ +#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) +#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) +#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) +#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) + +/*** INTERNAL FUNCTION PROTOTYPES *************************************/ +/* NOTE: These should not be accessed directly from outside this + * library -- they are intended for private internal visibility/use + * only. + */ +void SHA512_Last(SHA512_CTX*); +void SHA256_Transform(Sha256::detail::Context*, const sha2_word32*); +void SHA512_Transform(SHA512_CTX*, const sha2_word64*); + + +/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ +/* Hash constant words K for SHA-256: */ +const static sha2_word32 K256[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/* Initial hash value H for SHA-256: */ +const static sha2_word32 sha256_initial_hash_value[8] = { + 0x6a09e667UL, + 0xbb67ae85UL, + 0x3c6ef372UL, + 0xa54ff53aUL, + 0x510e527fUL, + 0x9b05688cUL, + 0x1f83d9abUL, + 0x5be0cd19UL +}; + +/* Hash constant words K for SHA-384 and SHA-512: */ +const static sha2_word64 K512[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + +/* Initial hash value H for SHA-384 */ +const static sha2_word64 sha384_initial_hash_value[8] = { + 0xcbbb9d5dc1059ed8ULL, + 0x629a292a367cd507ULL, + 0x9159015a3070dd17ULL, + 0x152fecd8f70e5939ULL, + 0x67332667ffc00b31ULL, + 0x8eb44a8768581511ULL, + 0xdb0c2e0d64f98fa7ULL, + 0x47b5481dbefa4fa4ULL +}; + +/* Initial hash value H for SHA-512 */ +const static sha2_word64 sha512_initial_hash_value[8] = { + 0x6a09e667f3bcc908ULL, + 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, + 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, + 0x5be0cd19137e2179ULL +}; + +/* + * Constant used by SHA256/384/512_End() functions for converting the + * digest to a readable hexadecimal character string: + */ +static const char *sha2_hex_digits = "0123456789abcdef"; + + +/*** SHA-256: *********************************************************/ +void SHA256_Init(Sha256::detail::Context* context) { + if (context == (Sha256::detail::Context*)0) { + return; + } + MEMCPY_BCOPY(context->state, sha256_initial_hash_value, Sha256::digestLength); + MEMSET_BZERO(context->buffer, Sha256::blockLength); + context->bitcount = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-256 round macros: */ + +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE32(*data++, W256[j]); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + W256[j]; \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + (W256[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256(a,b,c,d,e,f,g,h) \ + s0 = W256[(j+1)&0x0f]; \ + s0 = sigma0_256(s0); \ + s1 = W256[(j+14)&0x0f]; \ + s1 = sigma1_256(s1); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +void SHA256_Transform(Sha256::detail::Context* context, const sha2_word32* data) { + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + /* Rounds 0 to 15 (unrolled): */ + ROUND256_0_TO_15(a,b,c,d,e,f,g,h); + ROUND256_0_TO_15(h,a,b,c,d,e,f,g); + ROUND256_0_TO_15(g,h,a,b,c,d,e,f); + ROUND256_0_TO_15(f,g,h,a,b,c,d,e); + ROUND256_0_TO_15(e,f,g,h,a,b,c,d); + ROUND256_0_TO_15(d,e,f,g,h,a,b,c); + ROUND256_0_TO_15(c,d,e,f,g,h,a,b); + ROUND256_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds to 64: */ + do { + ROUND256(a,b,c,d,e,f,g,h); + ROUND256(h,a,b,c,d,e,f,g); + ROUND256(g,h,a,b,c,d,e,f); + ROUND256(f,g,h,a,b,c,d,e); + ROUND256(e,f,g,h,a,b,c,d); + ROUND256(d,e,f,g,h,a,b,c); + ROUND256(c,d,e,f,g,h,a,b); + ROUND256(b,c,d,e,f,g,h,a); + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void SHA256_Transform(Sha256::detail::Context* context, const sha2_word32* data) { + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, T2, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Copy data while converting to host byte order */ + REVERSE32(*data++,W256[j]); + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-256 compression function to update a..h with copy */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W256[(j+1)&0x0f]; + s0 = sigma0_256(s0); + s1 = W256[(j+14)&0x0f]; + s1 = sigma1_256(s1); + + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void SHA256_Update(Sha256::detail::Context* context, const sha2_byte *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + assert(context != (Sha256::detail::Context*)0 && data != (sha2_byte*)0); + + usedspace = (context->bitcount >> 3) % Sha256::blockLength; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = Sha256::blockLength - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; + SHA256_Transform(context, (sha2_word32*)context->buffer); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= Sha256::blockLength) { + /* Process as many complete blocks as we can */ + SHA256_Transform(context, (sha2_word32*)data); + context->bitcount += Sha256::blockLength << 3; + len -= Sha256::blockLength; + data += Sha256::blockLength; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void SHA256_Final(sha2_byte digest[], Sha256::detail::Context* context) { + sha2_word32 *d = (sha2_word32*)digest; + unsigned int usedspace; + + /* Sanity check: */ + assert(context != (Sha256::detail::Context*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + usedspace = (context->bitcount >> 3) % Sha256::blockLength; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount,context->bitcount); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < Sha256::blockLength) { + MEMSET_BZERO(&context->buffer[usedspace], Sha256::blockLength - usedspace); + } + /* Do second-to-last transform: */ + SHA256_Transform(context, (sha2_word32*)context->buffer); + + /* And set-up for the last transform: */ + MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + } + } else { + /* Set-up for the last transform: */ + MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Set the bit count: */ + *(sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; + + /* Final transform: */ + SHA256_Transform(context, (sha2_word32*)context->buffer); + +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE32(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + MEMCPY_BCOPY(d, context->state, Sha256::digestLength); +#endif + } + + /* Clean up state data: */ + MEMSET_BZERO(context, sizeof(Sha256::detail::Context)); + usedspace = 0; +} + +char *SHA256_End(Sha256::detail::Context* context, char buffer[]) { + sha2_byte digest[Sha256::digestLength], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (Sha256::detail::Context*)0); + + if (buffer != (char*)0) { + SHA256_Final(digest, context); + + for (i = 0; i < Sha256::digestLength; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + MEMSET_BZERO(context, sizeof(Sha256::detail::Context)); + } + MEMSET_BZERO(digest, Sha256::digestLength); + return buffer; +} + +char* SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { + Sha256::detail::Context context; + + SHA256_Init(&context); + SHA256_Update(&context, data, len); + return SHA256_End(&context, digest); +} + + +/*** SHA-512: *********************************************************/ +void SHA512_Init(SHA512_CTX* context) { + if (context == (SHA512_CTX*)0) { + return; + } + MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); + MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-512 round macros: */ +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE64(*data++, W512[j]); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + W512[j]; \ + (d) += T1, \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + (W512[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512(a,b,c,d,e,f,g,h) \ + s0 = W512[(j+1)&0x0f]; \ + s0 = sigma0_512(s0); \ + s1 = W512[(j+14)&0x0f]; \ + s1 = sigma1_512(s1); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { + sha2_word64 a, b, c, d, e, f, g, h, s0, s1; + sha2_word64 T1, *W512 = (sha2_word64*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + ROUND512_0_TO_15(a,b,c,d,e,f,g,h); + ROUND512_0_TO_15(h,a,b,c,d,e,f,g); + ROUND512_0_TO_15(g,h,a,b,c,d,e,f); + ROUND512_0_TO_15(f,g,h,a,b,c,d,e); + ROUND512_0_TO_15(e,f,g,h,a,b,c,d); + ROUND512_0_TO_15(d,e,f,g,h,a,b,c); + ROUND512_0_TO_15(c,d,e,f,g,h,a,b); + ROUND512_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds up to 79: */ + do { + ROUND512(a,b,c,d,e,f,g,h); + ROUND512(h,a,b,c,d,e,f,g); + ROUND512(g,h,a,b,c,d,e,f); + ROUND512(f,g,h,a,b,c,d,e); + ROUND512(e,f,g,h,a,b,c,d); + ROUND512(d,e,f,g,h,a,b,c); + ROUND512(c,d,e,f,g,h,a,b); + ROUND512(b,c,d,e,f,g,h,a); + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { + sha2_word64 a, b, c, d, e, f, g, h, s0, s1; + sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + REVERSE64(*data++, W512[j]); + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-512 compression function to update a..h with copy */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W512[(j+1)&0x0f]; + s0 = sigma0_512(s0); + s1 = W512[(j+14)&0x0f]; + s1 = sigma1_512(s1); + + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0); + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA512_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); + ADDINC128(context->bitcount, freespace << 3); + len -= freespace; + data += freespace; + SHA512_Transform(context, (sha2_word64*)context->buffer); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, len); + ADDINC128(context->bitcount, len << 3); + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA512_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + SHA512_Transform(context, (sha2_word64*)data); + ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); + len -= SHA512_BLOCK_LENGTH; + data += SHA512_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + ADDINC128(context->bitcount, len << 3); + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void SHA512_Last(SHA512_CTX* context) { + unsigned int usedspace; + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount[0],context->bitcount[0]); + REVERSE64(context->bitcount[1],context->bitcount[1]); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA512_BLOCK_LENGTH) { + MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA512_Transform(context, (sha2_word64*)context->buffer); + + /* And set-up for the last transform: */ + MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2); + } + } else { + /* Prepare for final transform: */ + MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Store the length of input data (in bits): */ + *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; + *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; + + /* Final transform: */ + SHA512_Transform(context, (sha2_word64*)context->buffer); +} + +void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) { + sha2_word64 *d = (sha2_word64*)digest; + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + SHA512_Last(context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH); +#endif + } + + /* Zero out state data */ + MEMSET_BZERO(context, sizeof(SHA512_CTX)); +} + +char *SHA512_End(SHA512_CTX* context, char buffer[]) { + sha2_byte digest[SHA512_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0); + + if (buffer != (char*)0) { + SHA512_Final(digest, context); + + for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + MEMSET_BZERO(context, sizeof(SHA512_CTX)); + } + MEMSET_BZERO(digest, SHA512_DIGEST_LENGTH); + return buffer; +} + +char* SHA512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { + SHA512_CTX context; + + SHA512_Init(&context); + SHA512_Update(&context, data, len); + return SHA512_End(&context, digest); +} + + +/*** SHA-384: *********************************************************/ +void SHA384_Init(SHA384_CTX* context) { + if (context == (SHA384_CTX*)0) { + return; + } + MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH); + MEMSET_BZERO(context->buffer, SHA384_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +void SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) { + SHA512_Update((SHA512_CTX*)context, data, len); +} + +void SHA384_Final(sha2_byte digest[], SHA384_CTX* context) { + sha2_word64 *d = (sha2_word64*)digest; + + /* Sanity check: */ + assert(context != (SHA384_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + SHA512_Last((SHA512_CTX*)context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 6; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + MEMCPY_BCOPY(d, context->state, SHA384_DIGEST_LENGTH); +#endif + } + + /* Zero out state data */ + MEMSET_BZERO(context, sizeof(SHA384_CTX)); +} + +char *SHA384_End(SHA384_CTX* context, char buffer[]) { + sha2_byte digest[SHA384_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA384_CTX*)0); + + if (buffer != (char*)0) { + SHA384_Final(digest, context); + + for (i = 0; i < SHA384_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + MEMSET_BZERO(context, sizeof(SHA384_CTX)); + } + MEMSET_BZERO(digest, SHA384_DIGEST_LENGTH); + return buffer; +} + +char* SHA384_Data(const sha2_byte* data, size_t len, char digest[SHA384_DIGEST_STRING_LENGTH]) { + SHA384_CTX context; + + SHA384_Init(&context); + SHA384_Update(&context, data, len); + return SHA384_End(&context, digest); +} diff --git a/beast/crypto/impl/sha2/sha2.h b/beast/crypto/impl/sha2/sha2.h new file mode 100644 index 0000000000..a3c38807d2 --- /dev/null +++ b/beast/crypto/impl/sha2/sha2.h @@ -0,0 +1,135 @@ +/* + * FILE: sha2.h + * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ + * + * Copyright (c) 2000-2001, Aaron D. Gifford + * 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. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``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 THE AUTHOR OR CONTRIBUTOR(S) 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. + * + * $Id: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $ + */ + +#ifndef __SHA2_H__ +#define __SHA2_H__ + +//#ifdef __cplusplus +//extern "C" { +//#endif + +/* + * Import u_intXX_t size_t type definitions from system headers. You + * may need to change this, or define these things yourself in this + * file. + */ +#include + + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +#define SHA256_DIGEST_STRING_LENGTH (Sha256::digestLength * 2 + 1) +#define SHA384_BLOCK_LENGTH 128 +#define SHA384_DIGEST_LENGTH 48 +#define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) +#define SHA512_BLOCK_LENGTH 128 +#define SHA512_DIGEST_LENGTH 64 +#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) + +/*** SHA-256/384/512 Context Structures *******************************/ +/* NOTE: If your architecture does not define either u_intXX_t types or + * uintXX_t (from inttypes.h), you may need to define things by hand + * for your system: + */ +#if 0 +typedef unsigned char u_int8_t; /* 1-byte (8-bits) */ +typedef unsigned int u_int32_t; /* 4-bytes (32-bits) */ +typedef unsigned long long u_int64_t; /* 8-bytes (64-bits) */ +#endif +/* + * Most BSD systems already define u_intXX_t types, as does Linux. + * Some systems, however, like Compaq's Tru64 Unix instead can use + * uintXX_t types defined by very recent ANSI C standards and included + * in the file: + * + * #include + * + */ +typedef struct _SHA512_CTX { + u_int64_t state[8]; + u_int64_t bitcount[2]; + u_int8_t buffer[SHA512_BLOCK_LENGTH]; +} SHA512_CTX; + +typedef SHA512_CTX SHA384_CTX; + + +/*** SHA-256/384/512 Function Prototypes ******************************/ +#ifndef NOPROTO + +void SHA256_Init(Sha256::detail::Context *); +void SHA256_Update(Sha256::detail::Context*, const u_int8_t*, size_t); +void SHA256_Final(u_int8_t[Sha256::digestLength], Sha256::detail::Context*); +char* SHA256_End(Sha256::detail::Context*, char[SHA256_DIGEST_STRING_LENGTH]); +char* SHA256_Data(const u_int8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); + +void SHA384_Init(SHA384_CTX*); +void SHA384_Update(SHA384_CTX*, const u_int8_t*, size_t); +void SHA384_Final(u_int8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*); +char* SHA384_End(SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH]); +char* SHA384_Data(const u_int8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH]); + +void SHA512_Init(SHA512_CTX*); +void SHA512_Update(SHA512_CTX*, const u_int8_t*, size_t); +void SHA512_Final(u_int8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); +char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); +char* SHA512_Data(const u_int8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); + +#else /* NOPROTO */ + +void SHA256_Init(); +void SHA256_Update(); +void SHA256_Final(); +char* SHA256_End(); +char* SHA256_Data(); + +void SHA384_Init(); +void SHA384_Update(); +void SHA384_Final(); +char* SHA384_End(); +char* SHA384_Data(); + +void SHA512_Init(); +void SHA512_Update(); +void SHA512_Final(); +char* SHA512_End(); +char* SHA512_Data(); + +#endif /* NOPROTO */ + +//#ifdef __cplusplus +//} +//#endif /* __cplusplus */ + +#endif /* __SHA2_H__ */ + diff --git a/beast/crypto/impl/sha2/sha2prog.c b/beast/crypto/impl/sha2/sha2prog.c new file mode 100644 index 0000000000..012701e898 --- /dev/null +++ b/beast/crypto/impl/sha2/sha2prog.c @@ -0,0 +1,132 @@ +/* + * FILE: sha2prog.c + * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ + * + * Copyright (c) 2000-2001, Aaron D. Gifford + * 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. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``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 THE AUTHOR OR CONTRIBUTOR(S) 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. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "sha2.h" + +void usage(char *prog, char *msg) { + fprintf(stderr, "%s\nUsage:\t%s [options] []\nOptions:\n\t-256\tGenerate SHA-256 hash\n\t-384\tGenerate SHA-284 hash\n\t-512\tGenerate SHA-512 hash\n\t-ALL\tGenerate all three hashes\n\t-q\tQuiet mode - only output hexadecimal hashes, one per line\n\n", msg, prog); + exit(-1); +} + +#define BUFLEN 16384 + +int main(int argc, char **argv) { + int kl, l, fd, ac; + int quiet = 0, hash = 0; + char *av, *file = (char*)0; + FILE *IN = (FILE*)0; + SHA256_CTX ctx256; + SHA384_CTX ctx384; + SHA512_CTX ctx512; + unsigned char buf[BUFLEN]; + + SHA256_Init(&ctx256); + SHA384_Init(&ctx384); + SHA512_Init(&ctx512); + + /* Read data from STDIN by default */ + fd = fileno(stdin); + + ac = 1; + while (ac < argc) { + if (*argv[ac] == '-') { + av = argv[ac] + 1; + if (!strcmp(av, "q")) { + quiet = 1; + } else if (!strcmp(av, "256")) { + hash |= 1; + } else if (!strcmp(av, "384")) { + hash |= 2; + } else if (!strcmp(av, "512")) { + hash |= 4; + } else if (!strcmp(av, "ALL")) { + hash = 7; + } else { + usage(argv[0], "Invalid option."); + } + ac++; + } else { + file = argv[ac++]; + if (ac != argc) { + usage(argv[0], "Too many arguments."); + } + if ((IN = fopen(file, "r")) == NULL) { + perror(argv[0]); + exit(-1); + } + fd = fileno(IN); + } + } + if (hash == 0) + hash = 7; /* Default to ALL */ + + kl = 0; + while ((l = read(fd,buf,BUFLEN)) > 0) { + kl += l; + SHA256_Update(&ctx256, (unsigned char*)buf, l); + SHA384_Update(&ctx384, (unsigned char*)buf, l); + SHA512_Update(&ctx512, (unsigned char*)buf, l); + } + if (file) { + fclose(IN); + } + + if (hash & 1) { + SHA256_End(&ctx256, buf); + if (!quiet) + printf("SHA-256 (%s) = ", file); + printf("%s\n", buf); + } + if (hash & 2) { + SHA384_End(&ctx384, buf); + if (!quiet) + printf("SHA-384 (%s) = ", file); + printf("%s\n", buf); + } + if (hash & 4) { + SHA512_End(&ctx512, buf); + if (!quiet) + printf("SHA-512 (%s) = ", file); + printf("%s\n", buf); + } + + return 1; +} + diff --git a/beast/crypto/impl/sha2/sha2speed.c b/beast/crypto/impl/sha2/sha2speed.c new file mode 100644 index 0000000000..2e135750fa --- /dev/null +++ b/beast/crypto/impl/sha2/sha2speed.c @@ -0,0 +1,174 @@ +/* + * FILE: sha2speed.c + * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ + * + * Copyright (c) 2000-2001, Aaron D. Gifford + * 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. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``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 THE AUTHOR OR CONTRIBUTOR(S) 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. + * + * $Id: sha2speed.c,v 1.1 2001/11/08 00:02:23 adg Exp adg $ + */ + +#include +#include +#include +#include + +#include "sha2.h" + +#define BUFSIZE 16384 + +void usage(char *prog) { + fprintf(stderr, "Usage:\t%s [] [] []\n", prog); + exit(-1); +} + +void printspeed(char *caption, unsigned long bytes, double time) { + if (bytes / 1073741824UL > 0) { + printf("%s %.4f sec (%.3f GBps)\n", caption, time, (double)bytes/1073741824UL/time); + } else if (bytes / 1048576 > 0) { + printf("%s %.4f (%.3f MBps)\n", caption, time, (double)bytes/1048576/time); + } else if (bytes / 1024 > 0) { + printf("%s %.4f (%.3f KBps)\n", caption, time, (double)bytes/1024/time); + } else { + printf("%s %.4f (%f Bps)\n", caption, time, (double)bytes/time); + } +} + + +int main(int argc, char **argv) { + SHA256_CTX c256; + SHA384_CTX c384; + SHA512_CTX c512; + char buf[BUFSIZE]; + char md[SHA512_DIGEST_STRING_LENGTH]; + int bytes, blocks, rep, i, j; + struct timeval start, end; + double t, ave256, ave384, ave512; + double best256, best384, best512; + + if (argc > 4) { + usage(argv[0]); + } + + /* Default to 1024 16K blocks (16 MB) */ + bytes = 1024 * 1024 * 16; + if (argc > 1) { + blocks = atoi(argv[1]); + } + blocks = bytes / BUFSIZE; + + /* Default to 10 repetitions */ + rep = 10; + if (argc > 2) { + rep = atoi(argv[2]); + } + + /* Set up the input data */ + if (argc > 3) { + memset(buf, atoi(argv[2]), BUFSIZE); + } else { + memset(buf, 0xb7, BUFSIZE); + } + + ave256 = ave384 = ave512 = 0; + best256 = best384 = best512 = 100000; + for (i = 0; i < rep; i++) { + SHA256_Init(&c256); + SHA384_Init(&c384); + SHA512_Init(&c512); + + gettimeofday(&start, (struct timezone*)0); + for (j = 0; j < blocks; j++) { + SHA256_Update(&c256, (unsigned char*)buf, BUFSIZE); + } + if (bytes % BUFSIZE) { + SHA256_Update(&c256, (unsigned char*)buf, bytes % BUFSIZE); + } + SHA256_End(&c256, md); + gettimeofday(&end, (struct timezone*)0); + t = ((end.tv_sec - start.tv_sec) * 1000000.0 + (end.tv_usec - start.tv_usec)) / 1000000.0; + ave256 += t; + if (t < best256) { + best256 = t; + } + printf("SHA-256[%d] (%.4f/%.4f/%.4f seconds) = 0x%s\n", i+1, t, ave256/(i+1), best256, md); + + gettimeofday(&start, (struct timezone*)0); + for (j = 0; j < blocks; j++) { + SHA384_Update(&c384, (unsigned char*)buf, BUFSIZE); + } + if (bytes % BUFSIZE) { + SHA384_Update(&c384, (unsigned char*)buf, bytes % BUFSIZE); + } + SHA384_End(&c384, md); + gettimeofday(&end, (struct timezone*)0); + t = ((end.tv_sec - start.tv_sec) * 1000000.0 + (end.tv_usec - start.tv_usec)) / 1000000.0; + ave384 += t; + if (t < best384) { + best384 = t; + } + printf("SHA-384[%d] (%.4f/%.4f/%.4f seconds) = 0x%s\n", i+1, t, ave384/(i+1), best384, md); + + gettimeofday(&start, (struct timezone*)0); + for (j = 0; j < blocks; j++) { + SHA512_Update(&c512, (unsigned char*)buf, BUFSIZE); + } + if (bytes % BUFSIZE) { + SHA512_Update(&c512, (unsigned char*)buf, bytes % BUFSIZE); + } + SHA512_End(&c512, md); + gettimeofday(&end, (struct timezone*)0); + t = ((end.tv_sec - start.tv_sec) * 1000000.0 + (end.tv_usec - start.tv_usec)) / 1000000.0; + ave512 += t; + if (t < best512) { + best512 = t; + } + printf("SHA-512[%d] (%.4f/%.4f/%.4f seconds) = 0x%s\n", i+1, t, ave512/(i+1), best512, md); + } + ave256 /= rep; + ave384 /= rep; + ave512 /= rep; + printf("\nTEST RESULTS SUMMARY:\nTEST REPETITIONS: %d\n", rep); + if (bytes / 1073741824UL > 0) { + printf("TEST SET SIZE: %.3f GB\n", (double)bytes/1073741824UL); + } else if (bytes / 1048576 > 0) { + printf("TEST SET SIZE: %.3f MB\n", (double)bytes/1048576); + } else if (bytes /1024 > 0) { + printf("TEST SET SIZE: %.3f KB\n", (double)bytes/1024); + } else { + printf("TEST SET SIZE: %d B\n", bytes); + } + printspeed("SHA-256 average:", bytes, ave256); + printspeed("SHA-256 best: ", bytes, best256); + printspeed("SHA-384 average:", bytes, ave384); + printspeed("SHA-384 best: ", bytes, best384); + printspeed("SHA-512 average:", bytes, ave512); + printspeed("SHA-512 best: ", bytes, best512); + + return 1; +} + diff --git a/beast/crypto/impl/sha2/sha2test.pl b/beast/crypto/impl/sha2/sha2test.pl new file mode 100644 index 0000000000..dc884d8c17 --- /dev/null +++ b/beast/crypto/impl/sha2/sha2test.pl @@ -0,0 +1,358 @@ +#!/usr/bin/perl +# +# FILE: sha2test.pl +# AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ +# +# Copyright (c) 2001, Aaron D. Gifford +# 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. +# 3. Neither the name of the copyright holder nor the names of contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``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 THE AUTHOR OR CONTRIBUTOR(S) 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. +# +# $Id: sha2test.pl,v 1.1 2001/11/08 00:02:37 adg Exp adg $ +# + +sub usage { + my ($err) = shift(@_); + + print <] [ [ ...]] + +Options: + -256 Use SHA-256 hashes during testing + -384 Use SHA-384 hashes during testing + -512 Use SHA-512 hashes during testing + -ALL Use all three hashes during testing + -c256 Specify a command to execute to generate a + SHA-256 hash. Be sure to include a '%' + character which will be replaced by the + test vector data filename containing the + data to be hashed. This command implies + the -256 option. + -c384 Specify a command to execute to generate a + SHA-384 hash. See above. Implies -384. + -c512 Specify a command to execute to generate a + SHA-512 hash. See above. Implies -512. + -cALL Specify a command to execute that will + generate all three hashes at once and output + the data in hexadecimal. See above for + information about the . + This option implies the -ALL option, and + also overrides any other command options if + present. + +By default, this program expects to execute the command ./sha2 within the +current working directory to generate all hashes. If no test vector +information files are specified, this program expects to read a series of +files ending in ".info" within a subdirectory of the current working +directory called "testvectors". + +EOM + exit(-1); +} + +$c256 = $c384 = $c512 = $cALL = ""; +$hashes = 0; +@FILES = (); + +# Read all command-line options and files: +while ($opt = shift(@ARGV)) { + if ($opt =~ s/^\-//) { + if ($opt eq "256") { + $hashes |= 1; + } elsif ($opt eq "384") { + $hashes |= 2; + } elsif ($opt eq "512") { + $hashes |= 4; + } elsif ($opt =~ /^ALL$/i) { + $hashes = 7; + } elsif ($opt =~ /^c256$/i) { + $hashes |= 1; + $opt = $c256 = shift(@ARGV); + $opt =~ s/\s+.*$//; + if (!$c256 || $c256 !~ /\%/ || !-x $opt) { + usage("Missing or invalid command specification for option -c256: $opt\n"); + } + } elsif ($opt =~ /^c384$/i) { + $hashes |= 2; + $opt = $c384 = shift(@ARGV); + $opt =~ s/\s+.*$//; + if (!$c384 || $c384 !~ /\%/ || !-x $opt) { + usage("Missing or invalid command specification for option -c384: $opt\n"); + } + } elsif ($opt =~ /^c512$/i) { + $hashes |= 4; + $opt = $c512 = shift(@ARGV); + $opt =~ s/\s+.*$//; + if (!$c512 || $c512 !~ /\%/ || !-x $opt) { + usage("Missing or invalid command specification for option -c512: $opt\n"); + } + } elsif ($opt =~ /^cALL$/i) { + $hashes = 7; + $opt = $cALL = shift(@ARGV); + $opt =~ s/\s+.*$//; + if (!$cALL || $cALL !~ /\%/ || !-x $opt) { + usage("Missing or invalid command specification for option -cALL: $opt\n"); + } + } else { + usage("Unknown/invalid option '$opt'\n"); + } + } else { + usage("Invalid, nonexistent, or unreadable file '$opt': $!\n") if (!-f $opt); + push(@FILES, $opt); + } +} + +# Set up defaults: +if (!$cALL && !$c256 && !$c384 && !$c512) { + $cALL = "./sha2 -ALL %"; + usage("Required ./sha2 binary executable not found.\n") if (!-x "./sha2"); +} +$hashes = 7 if (!$hashes); + +# Do some sanity checks: +usage("No command was supplied to generate SHA-256 hashes.\n") if ($hashes & 1 == 1 && !$cALL && !$c256); +usage("No command was supplied to generate SHA-384 hashes.\n") if ($hashes & 2 == 2 && !$cALL && !$c384); +usage("No command was supplied to generate SHA-512 hashes.\n") if ($hashes & 4 == 4 && !$cALL && !$c512); + +# Default .info files: +if (scalar(@FILES) < 1) { + opendir(DIR, "testvectors") || usage("Unable to scan directory 'testvectors' for vector information files: $!\n"); + @FILES = grep(/\.info$/, readdir(DIR)); + closedir(DIR); + @FILES = map { s/^/testvectors\//; $_; } @FILES; + @FILES = sort(@FILES); +} + +# Now read in each test vector information file: +foreach $file (@FILES) { + $dir = $file; + if ($file !~ /\//) { + $dir = "./"; + } else { + $dir =~ s/\/[^\/]+$//; + $dir .= "/"; + } + open(FILE, "<" . $file) || + usage("Unable to open test vector information file '$file' for reading: $!\n"); + $vec = { desc => "", file => "", sha256 => "", sha384 => "", sha512 => "" }; + $data = $field = ""; + $line = 0; + while() { + $line++; + s/\s*[\r\n]+$//; + next if ($field && $field ne "DESCRIPTION" && !$_); + if (/^(DESCRIPTION|FILE|SHA256|SHA384|SHA512):$/) { + if ($field eq "DESCRIPTION") { + $vec->{desc} = $data; + } elsif ($field eq "FILE") { + $data = $dir . $data if ($data !~ /^\//); + $vec->{file} = $data; + } elsif ($field eq "SHA256") { + $vec->{sha256} = $data; + } elsif ($field eq "SHA384") { + $vec->{sha384} = $data; + } elsif ($field eq "SHA512") { + $vec->{sha512} = $data; + } + $data = ""; + $field = $1; + } elsif ($field eq "DESCRIPTION") { + s/^ //; + $data .= $_ . "\n"; + } elsif ($field =~ /^SHA\d\d\d$/) { + s/^\s+//; + if (!/^([a-f0-9]{32}|[a-f0-9]{64})$/) { + usage("Invalid SHA-256/384/512 test vector information " . + "file format at line $line of file '$file'\n"); + } + $data .= $_; + } elsif ($field eq "FILE") { + s/^ //; + $data .= $_; + } else { + usage("Invalid SHA-256/384/512 test vector information file " . + "format at line $line of file '$file'\n"); + } + } + if ($field eq "DESCRIPTION") { + $data = $dir . $data if ($data !~ /^\//); + $vec->{desc} = $data; + } elsif ($field eq "FILE") { + $vec->{file} = $data; + } elsif ($field eq "SHA256") { + $vec->{sha256} = $data; + } elsif ($field eq "SHA384") { + $vec->{sha384} = $data; + } elsif ($field eq "SHA512") { + $vec->{sha512} = $data; + } else { + usage("Invalid SHA-256/384/512 test vector information file " . + "format. Missing required fields in file '$file'\n"); + } + + # Sanity check all entries: + if (!$vec->{desc}) { + usage("Invalid SHA-256/384/512 test vector information file " . + "format. Missing required DESCRIPTION field in file '$file'\n"); + } + if (!$vec->{file}) { + usage("Invalid SHA-256/384/512 test vector information file " . + "format. Missing required FILE field in file '$file'\n"); + } + if (! -f $vec->{file}) { + usage("The test vector data file (field FILE) name " . + "'$vec->{file}' is not a readable file. Check the FILE filed in " . + "file '$file'.\n"); + } + if (!($vec->{sha256} || $vec->{sha384} || $vec->{sha512})) { + usage("Invalid SHA-256/384/512 test vector information file " . + "format. There must be at least one SHA256, SHA384, or SHA512 " . + "field specified in file '$file'.\n"); + } + if ($vec->{sha256} !~ /^(|[a-f0-9]{64})$/) { + usage("Invalid SHA-256/384/512 test vector information file " . + "format. The SHA256 field is invalid in file '$file'.\n"); + } + if ($vec->{sha384} !~ /^(|[a-f0-9]{96})$/) { + usage("Invalid SHA-256/384/512 test vector information file " . + "format. The SHA384 field is invalid in file '$file'.\n"); + } + if ($vec->{sha512} !~ /^(|[a-f0-9]{128})$/) { + usage("Invalid SHA-256/384/512 test vector information file " . + "format. The SHA512 field is invalid in file '$file'.\n"); + } + close(FILE); + if ($hashes & (($vec->{sha256} ? 1 : 0) | ($vec->{sha384} ? 2 : 0) | ($vec->{sha512} ? 4 : 0))) { + push(@VECTORS, $vec); + } +} + +usage("There were no test vectors for the specified hash(es) in any of the test vector information files you specified.\n") if (scalar(@VECTORS) < 1); + +$num = $errors = $error256 = $error384 = $error512 = $tests = $test256 = $test384 = $test512 = 0; +foreach $vec (@VECTORS) { + $num++; + print "TEST VECTOR #$num:\n"; + print "\t" . join("\n\t", split(/\n/, $vec->{desc})) . "\n"; + print "VECTOR DATA FILE:\n\t$vec->{file}\n"; + $sha256 = $sha384 = $sha512 = ""; + if ($cALL) { + $prog = $cALL; + $prog =~ s/\%/'$vec->{file}'/g; + @SHA = grep(/[a-fA-f0-9]{64,128}/, split(/\n/, `$prog`)); + ($sha256) = grep(/(^[a-fA-F0-9]{64}$|^[a-fA-F0-9]{64}[^a-fA-F0-9]|[^a-fA-F0-9][a-fA-F0-9]{64}$|[^a-fA-F0-9][a-fA-F0-9]{64}[^a-fA-F0-9])/, @SHA); + ($sha384) = grep(/(^[a-fA-F0-9]{96}$|^[a-fA-F0-9]{96}[^a-fA-F0-9]|[^a-fA-F0-9][a-fA-F0-9]{96}$|[^a-fA-F0-9][a-fA-F0-9]{96}[^a-fA-F0-9])/, @SHA); + ($sha512) = grep(/(^[a-fA-F0-9]{128}$|^[a-fA-F0-9]{128}[^a-fA-F0-9]|[^a-fA-F0-9][a-fA-F0-9]{128}$|[^a-fA-F0-9][a-fA-F0-9]{128}[^a-fA-F0-9])/, @SHA); + } else { + if ($c256) { + $prog = $c256; + $prog =~ s/\%/'$vec->{file}'/g; + @SHA = grep(/[a-fA-f0-9]{64,128}/, split(/\n/, `$prog`)); + ($sha256) = grep(/(^[a-fA-F0-9]{64}$|^[a-fA-F0-9]{64}[^a-fA-F0-9]|[^a-fA-F0-9][a-fA-F0-9]{64}$|[^a-fA-F0-9][a-fA-F0-9]{64}[^a-fA-F0-9])/, @SHA); + } + if ($c384) { + $prog = $c384; + $prog =~ s/\%/'$vec->{file}'/g; + @SHA = grep(/[a-fA-f0-9]{64,128}/, split(/\n/, `$prog`)); + ($sha384) = grep(/(^[a-fA-F0-9]{96}$|^[a-fA-F0-9]{96}[^a-fA-F0-9]|[^a-fA-F0-9][a-fA-F0-9]{96}$|[^a-fA-F0-9][a-fA-F0-9]{96}[^a-fA-F0-9])/, @SHA); + } + if ($c512) { + $prog = $c512; + $prog =~ s/\%/'$vec->{file}'/g; + @SHA = grep(/[a-fA-f0-9]{64,128}/, split(/\n/, `$prog`)); + ($sha512) = grep(/(^[a-fA-F0-9]{128}$|^[a-fA-F0-9]{128}[^a-fA-F0-9]|[^a-fA-F0-9][a-fA-F0-9]{128}$|[^a-fA-F0-9][a-fA-F0-9]{128}[^a-fA-F0-9])/, @SHA); + } + } + usage("Unable to generate any hashes for file '$vec->{file}'!\n") if (!$sha256 && !$sha384 && $sha512); + $sha256 =~ tr/A-F/a-f/; + $sha384 =~ tr/A-F/a-f/; + $sha512 =~ tr/A-F/a-f/; + $sha256 =~ s/^.*([a-f0-9]{64}).*$/$1/; + $sha384 =~ s/^.*([a-f0-9]{96}).*$/$1/; + $sha512 =~ s/^.*([a-f0-9]{128}).*$/$1/; + + if ($sha256 && $hashes & 1 == 1) { + if ($vec->{sha256} eq $sha256) { + print "SHA256 MATCHES:\n\t$sha256\n" + } else { + print "SHA256 DOES NOT MATCH:\n\tEXPECTED:\n\t\t$vec->{sha256}\n" . + "\tGOT:\n\t\t$sha256\n\n"; + $error256++; + } + $test256++; + } + if ($sha384 && $hashes & 2 == 2) { + if ($vec->{sha384} eq $sha384) { + print "SHA384 MATCHES:\n\t" . substr($sha384, 0, 64) . "\n\t" . + substr($sha384, -32) . "\n"; + } else { + print "SHA384 DOES NOT MATCH:\n\tEXPECTED:\n\t\t" . + substr($vec->{sha384}, 0, 64) . "\n\t\t" . + substr($vec->{sha384}, -32) . "\n\tGOT:\n\t\t" . + substr($sha384, 0, 64) . "\n\t\t" . substr($sha384, -32) . "\n\n"; + $error384++; + } + $test384++; + } + if ($sha512 && $hashes & 4 == 4) { + if ($vec->{sha512} eq $sha512) { + print "SHA512 MATCHES:\n\t" . substr($sha512, 0, 64) . "\n\t" . + substr($sha512, -64) . "\n"; + } else { + print "SHA512 DOES NOT MATCH:\n\tEXPECTED:\n\t\t" . + substr($vec->{sha512}, 0, 64) . "\n\t\t" . + substr($vec->{sha512}, -32) . "\n\tGOT:\n\t\t" . + substr($sha512, 0, 64) . "\n\t\t" . substr($sha512, -64) . "\n\n"; + $error512++; + } + $test512++; + } +} + +$errors = $error256 + $error384 + $error512; +$tests = $test256 + $test384 + $test512; +print "\n\n===== RESULTS ($num VECTOR DATA FILES HASHED) =====\n\n"; +print "HASH TYPE\tNO. OF TESTS\tPASSED\tFAILED\n"; +print "---------\t------------\t------\t------\n"; +if ($test256) { + $pass = $test256 - $error256; + print "SHA-256\t\t".substr(" $test256", -12)."\t".substr(" $pass", -6)."\t".substr(" $error256", -6)."\n"; +} +if ($test384) { + $pass = $test384 - $error384; + print "SHA-384\t\t".substr(" $test384", -12)."\t".substr(" $pass", -6)."\t".substr(" $error384", -6)."\n"; +} +if ($test512) { + $pass = $test512 - $error512; + print "SHA-512\t\t".substr(" $test512", -12)."\t".substr(" $pass", -6)."\t".substr(" $error512", -6)."\n"; +} +print "----------------------------------------------\n"; +$pass = $tests - $errors; +print "TOTAL: ".substr(" $tests", -12)."\t".substr(" $pass", -6)."\t".substr(" $errors", -6)."\n\n"; +print "NO ERRORS! ALL TESTS WERE SUCCESSFUL!\n\n" if (!$errors); + diff --git a/beast/intrusive/IntrusiveArray.h b/beast/intrusive/IntrusiveArray.h new file mode 100644 index 0000000000..53fbe0b057 --- /dev/null +++ b/beast/intrusive/IntrusiveArray.h @@ -0,0 +1,187 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_INTRUSIVE_INTRUSIVEARRAY_H_INCLUDED +#define BEAST_INTRUSIVE_INTRUSIVEARRAY_H_INCLUDED + +#include "../Config.h" + +#include +#include +#include +#include + +namespace beast { + +/** A run-time fixed size array that references outside storage. + The interface tries to follow std::vector as closely as possible within + the limitations of a fixed size and unowned storage. +*/ +template +class IntrusiveArray +{ +private: + T* m_begin; + T* m_end; + +public: + typedef T value_type; + typedef T* iterator; + typedef T const* const_iterator; + typedef T& reference; + typedef T const& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + // Calling methods on a default constructed + // array results in undefined behavior! + // + IntrusiveArray () + : m_begin (nullptr), m_end (nullptr) + { } + IntrusiveArray (T* begin, T* end) + : m_begin (begin), m_end (end) + { } + IntrusiveArray (IntrusiveArray const& other) + : m_begin (other.m_begin), m_end (other.m_end) + { } + IntrusiveArray (std::vector const& v) + : m_begin (&v.front()), m_end (&v.back()+1) + { } + IntrusiveArray (std::vector & v) + : m_begin (&v.front()), m_end (&v.back()+1) + { } + IntrusiveArray& operator= (IntrusiveArray const& other) + { + m_begin = other.m_begin; + m_end = other.m_end; + return *this; + } + + // iterators + iterator begin() { return m_begin; } + const_iterator begin() const { return m_begin; } + const_iterator cbegin() const { return m_begin; } + iterator end() { return m_end; } + const_iterator end() const { return m_end; } + const_iterator cend() const { return m_end; } + + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + const_reverse_iterator crbegin() const { return const_reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } + const_reverse_iterator crend() const { return const_reverse_iterator(begin()); } + + reference operator[](size_type i) + { + bassert (i < size()); + return m_begin[i]; + } + + const_reference operator[](size_type i) const + { + bassert (i < size()); + return m_begin[i]; + } + + reference at(size_type i) { rangecheck(i); return m_begin[i]; } + const_reference at(size_type i) const { rangecheck(i); return m_begin[i]; } + + reference front() { return m_begin[0]; } + reference back() { return m_end[-1]; } + const_reference front () const { return m_begin; } + const_reference back() const { return m_end[-1]; } + + size_type size() const { return std::distance (m_begin, m_end); } + bool empty() const { return m_begin == m_end; } + + T const* data() const { return m_begin; } + T* data() { return m_begin; } + T* c_array() { return m_begin; } + + void assign (T const& value) { fill (value); } + + void fill (T const& value) + { + std::fill_n (begin(), size(), value); + } + + void clear () + { + fill (T ()); + } + + void rangecheck (size_type i) + { + if (i >= size()) + throw std::out_of_range ("IntrusiveArray<>: index out of range"); + } +}; + +//------------------------------------------------------------------------------ + +template +bool operator== (IntrusiveArray const& lhs, IntrusiveArray const& rhs) +{ + if ((lhs.begin() == rhs.begin()) && (lhs.end() == rhs.end())) + return true; + if (lhs.size() != rhs.size()) + return false; + return std::equal (lhs.begin(), lhs.end(), rhs.begin()); +} + +template +bool operator!= (IntrusiveArray const& lhs, IntrusiveArray const& rhs) +{ + return !(lhs==rhs); +} + +template +bool operator< (IntrusiveArray const& lhs, IntrusiveArray const& rhs) +{ + if ((lhs.begin() == rhs.begin()) && (lhs.end() == rhs.end())) + return false; + return std::lexicographical_compare (lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); +} + +template +bool operator> (IntrusiveArray const& lhs, IntrusiveArray const& rhs) +{ + return rhs +bool operator<= (IntrusiveArray const& lhs, IntrusiveArray const& rhs) +{ + return !(rhs +bool operator>= (IntrusiveArray const& lhs, IntrusiveArray const& rhs) +{ + return !(lhs= (IPEndpoint const& lhs, IPEndpoint const& rhs); /** Output stream conversions. */ /** @{ */ -std::ostream& operator<< (std::ostream &os, IPEndpoint::V4 const& addr); -std::ostream& operator<< (std::ostream &os, IPEndpoint::V6 const& addr); -std::ostream& operator<< (std::ostream &os, IPEndpoint const& ep); +std::ostream& operator<< (std::ostream& os, IPEndpoint::V4 const& addr); +std::ostream& operator<< (std::ostream& os, IPEndpoint::V6 const& addr); +std::ostream& operator<< (std::ostream& os, IPEndpoint const& ep); /** @} */ /** Input stream conversions. */ /** @{ */ -std::istream& operator>> (std::istream &is, IPEndpoint::V4& addr); -std::istream& operator>> (std::istream &is, IPEndpoint& ep); +std::istream& operator>> (std::istream& is, IPEndpoint::V4& addr); +std::istream& operator>> (std::istream& is, IPEndpoint& ep); //std::istream& operator>> (std::istream &is, IPEndpoint::V6&); /** @} */ diff --git a/modules/beast_crypto/math/BinaryEncoding.cpp b/modules/beast_crypto/math/BinaryEncoding.cpp index c67e4396c7..198a6b7b86 100644 --- a/modules/beast_crypto/math/BinaryEncoding.cpp +++ b/modules/beast_crypto/math/BinaryEncoding.cpp @@ -127,7 +127,7 @@ public: uint8 const* src (v.cbegin()-1); char const* const tab (alphabet().c_str()); s.reserve (Bytes * 2); - for (std::size_t bytes (v.sizeInBytes);bytes--;) + for (std::size_t bytes (v.size);bytes--;) { uint8 const v (*++src); s.push_back (tab [v>>4]); @@ -280,7 +280,7 @@ public: { typedef UnsignedInteger UInt; UInt v0; - random().fillBitsRandomly (v0.begin(), UInt::sizeInBytes); + random().fillBitsRandomly (v0.begin(), UInt::size); std::string const good (HexEncoding::encode (v0)); UInt v1; @@ -351,7 +351,7 @@ public: for (int i = 0; i < 50; ++i) { UInt v1; - random().fillBitsRandomly (v1.begin(), UInt::sizeInBytes); + random().fillBitsRandomly (v1.begin(), UInt::size); std::string const s1 (BinaryEncoding::encode (v1, c)); UInt v2; diff --git a/modules/beast_crypto/math/UnsignedInteger.h b/modules/beast_crypto/math/UnsignedInteger.h index 024d5c2b24..df17ef6520 100644 --- a/modules/beast_crypto/math/UnsignedInteger.h +++ b/modules/beast_crypto/math/UnsignedInteger.h @@ -32,12 +32,8 @@ template class UnsignedInteger : public SafeBool > { public: - enum - { - /** Constant for determining the number of bytes. - */ - sizeInBytes = Bytes - }; + /** Constant for determining the number of bytes. */ + static std::size_t const size = Bytes; // The underlying integer type we use when converting to calculation format. typedef uint32 IntCalcType; @@ -46,17 +42,16 @@ public: typedef UnsignedIntegerCalc CalcType; // Standard container compatibility - typedef uint8 ValueType; - typedef ValueType* iterator; - typedef ValueType const* const_iterator; + typedef uint8 value_type; + typedef value_type* iterator; + typedef value_type const* const_iterator; /** Hardened hash function for use with HashMap. The seed is used to make the hash unpredictable. This prevents attackers from exploiting crafted inputs to produce degenerate containers. - @see HashMap */ - class HashFunction + class hasher { public: /** Construct a hash function @@ -64,23 +59,16 @@ public: will be generated from the system @param seedToUse An optional seed to use. */ - explicit HashFunction (HashValue seedToUse = Random::getSystemRandom ().nextInt ()) + explicit hasher (HashValue seedToUse = Random::getSystemRandom ().nextInt ()) : m_seed (seedToUse) { } /** Generates a simple hash from an UnsignedInteger. */ - HashValue generateHash (UnsignedInteger const& key) const - { - HashValue hash; - Murmur::Hash (key.cbegin (), key.sizeInBytes, m_seed, &hash); - return hash; - } - HashValue operator() (UnsignedInteger const& key) const { HashValue hash; - Murmur::Hash (key.cbegin (), key.sizeInBytes, m_seed, &hash); + Murmur::Hash (key.cbegin (), key.size, m_seed, &hash); return hash; } @@ -88,6 +76,16 @@ public: HashValue m_seed; }; + /** Determins if two UnsignedInteger objects are equal. */ + class equal + { + public: + bool operator() (UnsignedInteger const& lhs, UnsignedInteger const& rhs) const + { + return lhs.compare (rhs) == 0; + } + }; + //-------------------------------------------------------------------------- /** Construct the object. @@ -114,11 +112,12 @@ public: std::memcpy (begin(), buf, Bytes); } - template - explicit UnsignedInteger (T const* buf) + template + UnsignedInteger (InputIt first, InputIt last) { m_values [0] = 0; // clear any pad bytes - std::memcpy (begin(), buf, Bytes); + check_precondition (std::distance (first, last) == size); + std::copy (first, last, begin()); } /** @} */ @@ -133,20 +132,19 @@ public: /** Create from an integer type. @invariant IntegerType must be an unsigned integer type. */ - template - static UnsignedInteger createFromInteger (IntegerType value) + template + static UnsignedInteger createFromInteger (UnsignedIntegralType value) { - static_bassert (Bytes >= sizeof (IntegerType)); + static_bassert (Bytes >= sizeof (UnsignedIntegralType)); UnsignedInteger result; - value = toNetworkByteOrder (value); + value = toNetworkByteOrder (value); result.clear (); std::memcpy (result.end () - sizeof (value), &value, bmin (Bytes, sizeof (value))); return result; } - /** Construct with a filled value. - */ - static UnsignedInteger createFilled (ValueType value) + /** Construct with a filled value. */ + static UnsignedInteger createFilled (value_type value) { UnsignedInteger result; result.fill (value); @@ -154,7 +152,7 @@ public: } /** Fill with a particular byte value. */ - void fill (ValueType value) + void fill (value_type value) { IntCalcType c; memset (&c, value, sizeof (c)); @@ -283,15 +281,15 @@ public: private: static std::size_t const CalcCount = (Bytes + sizeof (IntCalcType) - 1) / sizeof (IntCalcType); - ValueType* get () + value_type* get () { - return (reinterpret_cast (&m_values [0])) + + return (reinterpret_cast (&m_values [0])) + ((sizeof(IntCalcType)-(Bytes&(sizeof(IntCalcType)-1)))&(sizeof(IntCalcType)-1)); } - ValueType const* get () const + value_type const* get () const { - return (reinterpret_cast (&m_values [0])) + + return (reinterpret_cast (&m_values [0])) + ((sizeof(IntCalcType)-(Bytes&(sizeof(IntCalcType)-1)))&(sizeof(IntCalcType)-1)); }