STD_SHA_256 is a C++ class implementing the SHA-256 secure hash algorithm (byte oriented implementation).
The algorithm is specified in the document "Secure Hash Standard (SHS)" FIPS PUB 180-2.
I have developed the STD_SHA_256 class with the aim of making it easy to read and to use, rather than efficient.
The Test_SHA_256 program partially tests the class using the three examples for the SHA-256 algorithm defined in FIPS PUB 180-2.
That's as far as I have gone with my testing :)
If you want to try a more extended informal testing on any SHA algorithm implementation, have a look at The Secure Hash Algorithm Validation System (SHAVS) and then at these SHA test vectors.
Downloadable files (right click on the links and select "Save Link As"):
- STD_SHA_256.h - class specification
- STD_SHA_256.cpp - class implementation
- Test_SHA_256.cpp - class test
Content of STD_SHA_256.h:
//############################################################################# //## File Name: STD_SHA_256.h ## //## File Version: 1.00 (19 Jul 2008) ## //## Author: Silvestro Fantacci ## //## Copyright: Public Domain ## //############################################################################# // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR "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 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. #if !defined (STD_SHA_256_INCLUDED) #define STD_SHA_256_INCLUDED #include <string> //============================================================================= class STD_SHA_256 //============================================================================= // This class implements a SHA-256 secure hash algorithm as specified in the // "Secure Hash Standard (SHS)" document FIPS PUB 180-2, August 2002. // The SHA-256 algorithm calculates a 32 byte (256 bit) number - called a // "message digest" - from an input message of any length from 0 to 2^64 - 1 // bits. // The algorithm implemented in this class is byte oriented, i.e. the input // message resolution is in bytes and its length can range from 0 to 2^61 - 1 // bytes. { public: //-------- Two Phase Calculation -------- // Phase 1 - Add the whole message, byte by byte // Phase 2 - Inspect the calculated digest // Note: calls to the Digest methods are taken to imply that the whole // message has been added. Hence a subsequent call to Add, if any, will // be interpreted as the restart of Phase 1 on a new message. STD_SHA_256 (); void Add (unsigned __int8 Byte); // Index in 0 .. 31 unsigned __int8 Digest (unsigned int Index); // Returns the digest's hexadecimal representation. // 64 charactes long, A to F uppercase. std::string Digest (); // To explicitly request the restart of Phase 1 on a new message. void Reset (); virtual ~STD_SHA_256 (); //-------- Oneshot Calculations -------- // Message_Length is in bytes static void Get_Digest (void * Message, unsigned int Message_Length, unsigned __int8 Digest [32]); // The digest's hexadecimal representation. // The string is 64 charactes long, with A to F uppercase. // E.g. Digest ("abc") == "BA7816BF8F01CFEA414140DE5DAE2223" // "B00361A396177A9CB410FF61F20015AD" static std::string Digest (std::string Message); private: static unsigned __int32 Rotated_Right (unsigned __int32 Word, unsigned int Times); static unsigned __int32 Shifted_Right (unsigned __int32 Word, unsigned int Times); static unsigned __int32 Upper_Sigma_0 (unsigned __int32 Word); static unsigned __int32 Upper_Sigma_1 (unsigned __int32 Word); static unsigned __int32 Lower_Sigma_0 (unsigned __int32 Word); static unsigned __int32 Lower_Sigma_1 (unsigned __int32 Word); static unsigned __int32 Ch (unsigned __int32 Word_1, unsigned __int32 Word_2, unsigned __int32 Word_3); static unsigned __int32 Maj (unsigned __int32 Word_1, unsigned __int32 Word_2, unsigned __int32 Word_3); void Padd (); void Process_Block (); // A message block of 64 * 8 = 512 bit unsigned __int8 my_Block [64]; unsigned __int32 my_Hash_Value [8]; unsigned __int64 my_Total_Bytes; bool my_Padding_is_Done; static const unsigned __int32 K [64]; }; #endif // !defined (STD_SHA_256_INCLUDED)
Content of STD_SHA_256.cpp:
//############################################################################# //## File Name: STD_SHA_256.cpp ## //## File Version: 1.00 (19 Jul 2008) ## //## Author: Silvestro Fantacci ## //## Copyright: Public Domain ## //############################################################################# // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR "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 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 "STD_SHA_256.h" const unsigned __int32 STD_SHA_256::K [64] = { 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 }; //----------------------------------------------------------------------------- STD_SHA_256::STD_SHA_256 () //----------------------------------------------------------------------------- { Reset (); } //----------------------------------------------------------------------------- void STD_SHA_256::Reset () //----------------------------------------------------------------------------- { my_Total_Bytes = 0; my_Padding_is_Done = false; my_Hash_Value [0] = 0x6A09E667; my_Hash_Value [1] = 0xBB67AE85; my_Hash_Value [2] = 0x3C6EF372; my_Hash_Value [3] = 0xA54FF53A; my_Hash_Value [4] = 0x510E527F; my_Hash_Value [5] = 0x9B05688C; my_Hash_Value [6] = 0x1F83D9AB; my_Hash_Value [7] = 0x5BE0CD19; }; //----------------------------------------------------------------------------- void STD_SHA_256::Add (unsigned __int8 Byte) //----------------------------------------------------------------------------- { if (my_Padding_is_Done) // A message has already been added and its digest calculated, // hence this is the first byte of a new message Reset (); my_Block [my_Total_Bytes % 64] = Byte; my_Total_Bytes++; if (my_Total_Bytes % 64 == 0) Process_Block (); } //----------------------------------------------------------------------------- unsigned __int32 STD_SHA_256::Rotated_Right (unsigned __int32 Word, unsigned int Times) //----------------------------------------------------------------------------- // Circular right shift (rotation) of Word by Times positions to the right. // Times >= 0 && Times < 32 { return (Word >> Times) | (Word << (32 - Times)); } //----------------------------------------------------------------------------- unsigned __int32 STD_SHA_256::Shifted_Right (unsigned __int32 Word, unsigned int Times) //----------------------------------------------------------------------------- { return Word >> Times; } //----------------------------------------------------------------------------- unsigned __int32 STD_SHA_256::Upper_Sigma_0 (unsigned __int32 Word) //----------------------------------------------------------------------------- { return Rotated_Right (Word, 2) ^ Rotated_Right (Word, 13) ^ Rotated_Right (Word, 22); } //----------------------------------------------------------------------------- unsigned __int32 STD_SHA_256::Upper_Sigma_1 (unsigned __int32 Word) //----------------------------------------------------------------------------- { return Rotated_Right (Word, 6) ^ Rotated_Right (Word, 11) ^ Rotated_Right (Word, 25); } //----------------------------------------------------------------------------- unsigned __int32 STD_SHA_256::Lower_Sigma_0 (unsigned __int32 Word) //----------------------------------------------------------------------------- { return Rotated_Right (Word, 7) ^ Rotated_Right (Word, 18) ^ Shifted_Right (Word, 3); } //----------------------------------------------------------------------------- unsigned __int32 STD_SHA_256::Lower_Sigma_1 (unsigned __int32 Word) //----------------------------------------------------------------------------- { return Rotated_Right (Word, 17) ^ Rotated_Right (Word, 19) ^ Shifted_Right (Word, 10); } //----------------------------------------------------------------------------- unsigned __int32 STD_SHA_256::Ch (unsigned __int32 Word_1, unsigned __int32 Word_2, unsigned __int32 Word_3) //----------------------------------------------------------------------------- { return (Word_1 & Word_2) ^ (~Word_1 & Word_3); } //----------------------------------------------------------------------------- unsigned __int32 STD_SHA_256::Maj (unsigned __int32 Word_1, unsigned __int32 Word_2, unsigned __int32 Word_3) //----------------------------------------------------------------------------- { return (Word_1 & Word_2) ^ (Word_1 & Word_3) ^ (Word_2 & Word_3); } //----------------------------------------------------------------------------- void STD_SHA_256::Padd () //----------------------------------------------------------------------------- { unsigned __int64 Total_Message_Bits = my_Total_Bytes * 8; Add (0x80); while (my_Total_Bytes % 64 != 56) Add (0); Add ((unsigned __int8) (Total_Message_Bits >> 54)); Add ((unsigned __int8) (Total_Message_Bits >> 48)); Add ((unsigned __int8) (Total_Message_Bits >> 40)); Add ((unsigned __int8) (Total_Message_Bits >> 32)); Add ((unsigned __int8) (Total_Message_Bits >> 24)); Add ((unsigned __int8) (Total_Message_Bits >> 16)); Add ((unsigned __int8) (Total_Message_Bits >> 8)); Add ((unsigned __int8) (Total_Message_Bits)); my_Padding_is_Done = true; } //----------------------------------------------------------------------------- void STD_SHA_256::Process_Block () //----------------------------------------------------------------------------- { unsigned int i; unsigned __int32 Schedule [64]; unsigned __int32 a, b, c, d, e, f, g, h; unsigned __int32 T1, T2; for (i = 0; i <= 15; i++) { Schedule [i] = my_Block [i * 4]; Schedule [i] <<= 8; Schedule [i] += my_Block [i * 4 + 1]; Schedule [i] <<= 8; Schedule [i] += my_Block [i * 4 + 2]; Schedule [i] <<= 8; Schedule [i] += my_Block [i * 4 + 3]; } for (i = 16; i <= 63; i++) Schedule [i] = Lower_Sigma_1 (Schedule [i - 2]) + Schedule [i - 7] + Lower_Sigma_0 (Schedule [i - 15]) + Schedule [i - 16]; a = my_Hash_Value [0]; b = my_Hash_Value [1]; c = my_Hash_Value [2]; d = my_Hash_Value [3]; e = my_Hash_Value [4]; f = my_Hash_Value [5]; g = my_Hash_Value [6]; h = my_Hash_Value [7]; for (i = 0; i <= 63; i++) { T1 = h + Upper_Sigma_1 (e) + Ch (e, f, g) + K [i] + Schedule [i]; T2 = Upper_Sigma_0 (a) + Maj (a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; } my_Hash_Value [0] += a; my_Hash_Value [1] += b; my_Hash_Value [2] += c; my_Hash_Value [3] += d; my_Hash_Value [4] += e; my_Hash_Value [5] += f; my_Hash_Value [6] += g; my_Hash_Value [7] += h; } //----------------------------------------------------------------------------- unsigned __int8 STD_SHA_256::Digest (unsigned int Index) //----------------------------------------------------------------------------- // Index in 0 .. 31 { unsigned int i = Index / 4; // 0 to 7 unsigned int s = (3 - Index % 4) * 8; // 0, 8, 16 or 24 if (! my_Padding_is_Done) Padd (); return (unsigned __int8) Shifted_Right (my_Hash_Value [i], s); } //----------------------------------------------------------------------------- std::string STD_SHA_256::Digest () //----------------------------------------------------------------------------- { std::string Hex_Digest = ""; unsigned int Nibble; for (unsigned int i = 0; i < 64; i++) { if (i % 2 == 0) Nibble = Digest (i / 2) >> 4; else Nibble = Digest (i / 2) & 0x0F; if (Nibble >= 10) Hex_Digest += 'A' + Nibble - 10; else Hex_Digest += '0' + Nibble; } return Hex_Digest; } //----------------------------------------------------------------------------- void STD_SHA_256::Get_Digest (void * Message, unsigned int Message_Length, unsigned __int8 Digest [32]) //----------------------------------------------------------------------------- { unsigned __int8 * Data = (unsigned __int8 *) Message; unsigned int i; STD_SHA_256 SHA; for (i = 0; i < Message_Length; i++) SHA.Add (Data [i]); for (i = 0; i < 32; i++) Digest [i] = SHA.Digest (i); } //----------------------------------------------------------------------------- std::string STD_SHA_256::Digest (std::string Message) //----------------------------------------------------------------------------- { STD_SHA_256 SHA; for (unsigned int i = 0; i < Message.size (); i++) SHA.Add (Message [i]); return SHA.Digest (); } //----------------------------------------------------------------------------- STD_SHA_256::~STD_SHA_256 () //----------------------------------------------------------------------------- { }
Content of Test_SHA_256.cpp:
//############################################################################# //## File Name: Test_SHA_256.cpp ## //## File Version: 1.00 (19 Jul 2008) ## //## Author: Silvestro Fantacci ## //## Copyright: Public Domain ## //############################################################################# // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR "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 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 <iostream> #include <string> #include "STD_SHA_256.h" using namespace std; //----------------------------------------------------------------------------- void main () //----------------------------------------------------------------------------- // The purpose of this program is to run a test on the STD_SHA_256 class, // based on the three examples for the SHA-256 algorithm in FIPS 180-2. { string Message; string Expected_Digest; string Calculated_Digest; bool Test_Passed = true; cout << "Running SHA-256 Tests 1, 2 & 3:" << endl; //-------- Test 1: One-Block Message -------- Message = "abc"; Expected_Digest = "BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD"; Calculated_Digest = STD_SHA_256::Digest (Message); if (Calculated_Digest == Expected_Digest) cout << "SHA-256 Test 1 Passed" << endl; else { cout << "SHA-256 Test 1 Failed" << endl; cout << "Test Message: \"" << Message.c_str () << "\"" << endl; cout << "Calculated Message Digest: " << Calculated_Digest.c_str () << endl; cout << "Expected Message Digest: " << Expected_Digest.c_str () << endl; } //-------- Test 2: Multi-Block Message -------- Message = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; Expected_Digest = "248D6A61D20638B8E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1"; Calculated_Digest = STD_SHA_256::Digest (Message); if (Calculated_Digest == Expected_Digest) cout << "SHA-256 Test 2 Passed" << endl; else { cout << "SHA-256 Test 2 Failed" << endl; cout << "Test Message: \"" << Message.c_str () << "\"" << endl; cout << "Calculated Message Digest: " << Calculated_Digest.c_str () << endl; cout << "Expected Message Digest: " << Expected_Digest.c_str () << endl; } //-------- Test 3: Long Message -------- Message = "<one million 'a'>"; Expected_Digest = "CDC76E5C9914FB9281A1C7E284D73E67F1809A48A497200E046D39CCC7112CD0"; STD_SHA_256 SHA; for (unsigned int i = 1; i <= 1000000; i++) SHA.Add ('a'); Calculated_Digest = SHA.Digest (); if (Calculated_Digest == Expected_Digest) cout << "SHA-256 Test 3 Passed" << endl; else { cout << "SHA-256 Test 3 Failed" << endl; cout << "Test Message: \"" << Message.c_str () << "\"" << endl; cout << "Calculated Message Digest: " << Calculated_Digest.c_str () << endl; cout << "Expected Message Digest: " << Expected_Digest.c_str () << endl; } }