SHA-256

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"):

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;
    }
}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License