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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)); | |
} | |
} | |
} |
Comments
Post a Comment