SHA-256(Source Code in C#) – Part I

SHA-256 (Secure Hash Algorithm), is one of the cryptographic hash function, commonly used in Blockchain. It generates an almost-unique 256-bit (32-byte) signature for a text. 

SHA-256 is successor hash functions to SHA-1. it is one of the strongest hash functions available and has not yet been compromised in any way.  

Here is source code written in C#. I will try to give more details in next Part II    

using System;
using System.Text;

namespace SecureHashingProject
{
    public class SecureHashingAlgorithm2
    {
        private static readonly uint[] K = {
            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
        };

        //initial hash value
        private static readonly uint[] H =
        {
            0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
        };


        static void Main()
        {
            var msg = Console.ReadLine();
            if (string.IsNullOrEmpty(msg))
            {
                Console.WriteLine("No data to generate hash");
                return;
            }

            var msgBytes = new byte[64];
            var bitLength = new uint[2];
            uint length = 0;
            var hash = new byte[32];
            var hashStr = string.Empty;
            var data = Encoding.Default.GetBytes(msg);

            for (uint i = 0; i < msg.Length; ++i)
            {
                msgBytes[length] = data[i];
                length++;

                if (length != 64) continue;

                ComputingHash(ref msgBytes);
                InitBitBlock(ref bitLength[0], ref length, 512);
                length = 0;
            }

            GenerateSha256(ref msgBytes, ref bitLength, ref length, hash);

            for (var i = 0; i < 32; i++)
                hashStr += $"{hash[i]:X2}";

            Console.WriteLine(hashStr);
            Console.ReadLine();
        }

        private static void ComputingHash(ref byte[] data)
        {
            uint i, j;
            var m = new uint[64];

            //prepare message schedule 'm'
            for (i = 0, j = 0; i < 16; ++i, j += 4)
                m[i] = (uint)((data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | data[j + 3]);

            for (; i < 64; ++i)
                m[i] = Σ4(m[i - 2]) + m[i - 7] + Σ3(m[i - 15]) + m[i - 16];

            //Initialise working variables a, b, c, d, e, f, g, h with previous hash value
            var a = H[0];
            var b = H[1];
            var c = H[2];
            var d = H[3];
            var e = H[4];
            var f = H[5];
            var g = H[6];
            var h = H[7];

            //main loop
            for (i = 0; i < 64; ++i)
            {
                var t1 = h + Σ1(e) + Choice(e, f, g) + K[i] + m[i];
                var t2 = Σ0(a) + Majority(a, b, c);
                h = g;
                g = f;
                f = e;
                e = d + t1;
                d = c;
                c = b;
                b = a;
                a = t1 + t2;
            }

            //compute the new intermediate hash value
            H[0] += a;
            H[1] += b;
            H[2] += c;
            H[3] += d;
            H[4] += e;
            H[5] += f;
            H[6] += g;
            H[7] += h;
        }

        private static void GenerateSha256(ref byte[] msgBytes, ref uint[] bitLength, ref uint length, byte[] hash)
        {
            var i = length;

            if (length < 56)
            {
                msgBytes[i++] = 0x80; // add trailing '1' bit (+ 0's padding) to string

                while (i < 56)
                    msgBytes[i++] = 0x00;
            }
            else
            {
                msgBytes[i++] = 0x80; // add trailing '1' bit (+ 0's padding) to string

                while (i < 64)
                    msgBytes[i++] = 0x00;

                ComputingHash(ref msgBytes);
            }

            InitBitBlock(ref bitLength[0], ref bitLength[1], length * 8);
            msgBytes[63] = (byte)bitLength[0];
            msgBytes[62] = (byte)(bitLength[0] >> 8);
            msgBytes[61] = (byte)(bitLength[0] >> 16);
            msgBytes[60] = (byte)(bitLength[0] >> 24);
            msgBytes[59] = (byte)bitLength[1];
            msgBytes[58] = (byte)(bitLength[1] >> 8);
            msgBytes[57] = (byte)(bitLength[1] >> 16);
            msgBytes[56] = (byte)(bitLength[1] >> 24);
            ComputingHash(ref msgBytes);

            for (i = 0; i < 4; ++i)
            {
                hash[i] = (byte)((H[0] >> (int)(24 - i * 8)) & 0x000000ff);
                hash[i + 4] = (byte)((H[1] >> (int)(24 - i * 8)) & 0x000000ff);
                hash[i + 8] = (byte)((H[2] >> (int)(24 - i * 8)) & 0x000000ff);
                hash[i + 12] = (byte)((H[3] >> (int)(24 - i * 8)) & 0x000000ff);
                hash[i + 16] = (byte)((H[4] >> (int)(24 - i * 8)) & 0x000000ff);
                hash[i + 20] = (byte)((H[5] >> (int)(24 - i * 8)) & 0x000000ff);
                hash[i + 24] = (byte)((H[6] >> (int)(24 - i * 8)) & 0x000000ff);
                hash[i + 28] = (byte)((H[7] >> (int)(24 - i * 8)) & 0x000000ff);
            }
        }
        private static uint Choice(uint x, uint y, uint z)
        {
            return (x & y) ^ (~x & z);
        }

        private static uint Majority(uint x, uint y, uint z)
        {
            return (x & y) ^ (x & z) ^ (y & z);
        }

        private static uint Σ0(uint x)
        {
            return RotateRight(x, 2) ^ RotateRight(x, 13) ^ RotateRight(x, 22);
        }

        private static uint Σ1(uint x)
        {
            return RotateRight(x, 6) ^ RotateRight(x, 11) ^ RotateRight(x, 25);
        }

        private static uint Σ3(uint x)
        {
            return RotateRight(x, 7) ^ RotateRight(x, 18) ^ (x >> 3);
        }

        private static uint Σ4(uint x)
        {
            return RotateRight(x, 17) ^ RotateRight(x, 19) ^ (x >> 10);
        }

        private static void InitBitBlock(ref uint a, ref uint b, uint c)
        {
            if (a > 0xffffffff - c) ++b; a += c;
        }

        private static uint RotateRight(uint a, byte b) //Rotates right (circular right shift) value a by b positions
        {
            return (a >> b) | (a << (32 - b));
        }
    }
}

2 Replies to “SHA-256(Source Code in C#) – Part I”

Leave a Reply

Your email address will not be published. Required fields are marked *