|
| 1 | +///------------------------------------------------------------------------- |
| 2 | +/// Author: Quetzal Rivera Email: quetzaldev122@outlook.com |
| 3 | +/// Bitcoin Donation Address: 3FUskDSShN4kh71NARrsbbWJmsXtWXkrC3 |
| 4 | +/// Name: Sha256 algorithm Create Date: 25-12-2017 |
| 5 | +/// Description: The cryptographic hash function SHA-256 algorithm |
| 6 | +/// implemented in C# language |
| 7 | +/// Revision History: |
| 8 | +/// Name: Creation Date: 25-12-2017 Descripcion: - |
| 9 | +///------------------------------------------------------------------------- |
| 10 | +using System; |
| 11 | +using System.Linq; |
| 12 | + |
| 13 | +namespace PRUEBA |
| 14 | +{ |
| 15 | + /// <summary> |
| 16 | + /// Sha256 Class. |
| 17 | + /// </summary> |
| 18 | + class Sha256 |
| 19 | + { |
| 20 | + /// <summary>Sha256 instance</summary> |
| 21 | + /// You call a new Sha256 instance with: |
| 22 | + /// <c> Sha256 name = new Sha256(); </c> |
| 23 | + public Sha256() { } |
| 24 | + |
| 25 | + /// <summary>Hash Function of message.</summary> |
| 26 | + /// <param name="message">Input message to hash</param> |
| 27 | + /// <returns>Hash of the message</returns> |
| 28 | + public byte[] HashComputation(byte[] message) |
| 29 | + { |
| 30 | + /// Step 1: Padding |
| 31 | + /// To ensure that the message has lenght multiple of 512 bits: |
| 32 | + /// ► First, a bit 1 is appended, |
| 33 | + /// ► next. k bits 0 e appended, with k being the smallest positive integer |
| 34 | + /// such that: message + 1 + k + L) mod 512, where L is the initial lenght message. |
| 35 | + /// ► finally, the lengh L is represented with exactly 64 bits, and these bits are added at |
| 36 | + /// the end of the message. |
| 37 | + /// The message shall always be padded, even if the initial lenght is already a multiple of 512. |
| 38 | + Byte[] L = BitConverter.GetBytes(Convert.ToUInt64(message.Length * 8)).Reverse().ToArray(); |
| 39 | + // 1 byte = 8 bits | mod(%) | When A is multiple of B: A % B = 0 |
| 40 | + int k = 0; |
| 41 | + while ((message.Length * 8 + 8 + k + 64) % 512 != 0) { k += 8; } |
| 42 | + byte[] paddedmessage = new byte[(message.Length * 8 + 8 + k + 64) / 8]; |
| 43 | + |
| 44 | + message.CopyTo(paddedmessage, 0); |
| 45 | + paddedmessage[message.Length] = 0x80; // 0x80 = b10000000 = the bit 1 |
| 46 | + for (int i = 1; i < (1 + (k / 8)); i++) |
| 47 | + paddedmessage[message.Length + i] = 0x00; // 0x00 = b00000000 |
| 48 | + L.CopyTo(paddedmessage, message.Length + 1 + (k / 8)); |
| 49 | + |
| 50 | + /// M[i] blocks are formed with paddedmessage. |
| 51 | + /// Each block constains 512 bits of paddedmessage. |
| 52 | + // 64 bytes = 512 bits |
| 53 | + int N = paddedmessage.Length / 64; |
| 54 | + byte[][] M = new byte[N][]; |
| 55 | + for (int i = 0; i < N; i++) |
| 56 | + { |
| 57 | + byte[] temp = new byte[64]; |
| 58 | + for (int j = 0; j < 64; j++) |
| 59 | + temp[j] = paddedmessage[(i * 64) + j]; |
| 60 | + M[i] = temp; |
| 61 | + } |
| 62 | + |
| 63 | + /// Step 2: Hash Computation |
| 64 | + /// ► First, eight variables are set to ther initial values, given by the first 32 bits of the |
| 65 | + /// fractional part of the square roots of the first 8 prime numbers. |
| 66 | + /// ► Next, the blocks M[i] are processed one at a time. |
| 67 | + uint[] H = new uint[8]; |
| 68 | + H[0] = 0x6a09e667; H[1] = 0xbb67ae85; H[2] = 0x3c6ef372; H[3] = 0xa54ff53a; |
| 69 | + H[4] = 0x510e527f; H[5] = 0x9b05688c; H[6] = 0x1f83d9ab; H[7] = 0x5be0cd19; |
| 70 | + |
| 71 | + for(int t = 0; t < N; t++) |
| 72 | + { |
| 73 | + /// For each block M, 64 words W[i] are constructed as follows: |
| 74 | + /// ► the first 16 are obteined by splitting M in 32-bit blocks |
| 75 | + /// M = W[1] || W[2] || ... || W[15] || W[16] |
| 76 | + /// ► the remaining 48 are obteined withe formula: |
| 77 | + /// W[i] = S1(W[i - 2]) + W[i - 7] + S0(W[i - 15]) + W[i - 16] |
| 78 | + uint[] W = new uint[64]; |
| 79 | + for (int i = 0, j = 0; i < 16; ++i, j += 4) |
| 80 | + W[i] = (uint)((M[t][j] << 24) | (M[t][j + 1] << 16) | (M[t][j + 2] << 8) | (M[t][j + 3])); |
| 81 | + for (uint i = 16; i < 64; i++) |
| 82 | + W[i] = S1(W[i - 2]) + W[i - 7] + S0(W[i - 15]) + W[i - 16]; |
| 83 | + |
| 84 | + uint |
| 85 | + a = H[0], |
| 86 | + b = H[1], |
| 87 | + c = H[2], |
| 88 | + d = H[3], |
| 89 | + e = H[4], |
| 90 | + f = H[5], |
| 91 | + g = H[6], |
| 92 | + h = H[7], |
| 93 | + T1, |
| 94 | + T2; |
| 95 | + |
| 96 | + for(int i = 0; i < 64; i++) |
| 97 | + { |
| 98 | + T1 = h + Z1(e) + Ch(e, f, g) + K[i] + W[i]; |
| 99 | + T2 = Z0(a) + Maj(a, b, c); |
| 100 | + h = g; |
| 101 | + g = f; |
| 102 | + f = e; |
| 103 | + e = d + T1; |
| 104 | + d = c; |
| 105 | + c = b; |
| 106 | + b = a; |
| 107 | + a = T1 + T2; |
| 108 | + } |
| 109 | + |
| 110 | + H[0] = H[0] + a; |
| 111 | + H[1] = H[1] + b; |
| 112 | + H[2] = H[2] + c; |
| 113 | + H[3] = H[3] + d; |
| 114 | + H[4] = H[4] + e; |
| 115 | + H[5] = H[5] + f; |
| 116 | + H[6] = H[6] + g; |
| 117 | + H[7] = H[7] + h; |
| 118 | + } |
| 119 | + /// The has of the message is the concatenation of the new variables H[i] |
| 120 | + /// after the las block has been processed. |
| 121 | + byte[] Hash = new byte[32]; |
| 122 | + for (int i = 0; i < 8; i++) |
| 123 | + (BitConverter.GetBytes(H[i]).Reverse().ToArray()).CopyTo(Hash, i * 4); |
| 124 | + |
| 125 | + return Hash; // Return the final hash of 32 bytes (256 bits) |
| 126 | + } |
| 127 | + |
| 128 | + // Functions and constans |
| 129 | + /// <summary>Circular right shift of n bits of the binary word a.</summary> |
| 130 | + /// <param name="a">32-bits word </param> |
| 131 | + /// <param name="n">Bits for rotate shift </param> |
| 132 | + /// <returns>A new 32-bits word</returns> |
| 133 | + static uint RotR(uint a, byte n) => (((a) >> (n)) | ((a) << (32 - (n)))); |
| 134 | + /// <summary>Right shift of n bits of the binary word a.</summary> |
| 135 | + /// <param name="a">32-bits word </param> |
| 136 | + /// <param name="n"> Bits for rotate shift </param> |
| 137 | + /// <returns></returns> |
| 138 | + static uint ShR(uint a, byte n) => (a >> n); |
| 139 | + |
| 140 | + private static uint Ch(uint x, uint y, uint z) => (((x) & (y)) ^ ((~x) & (z))); |
| 141 | + private static uint Maj(uint x, uint y, uint z) => (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))); |
| 142 | + private static uint Z0(uint x) => (RotR(x, 2) ^ RotR(x, 13) ^ RotR(x, 22)); |
| 143 | + private static uint Z1(uint x) => (RotR(x, 6) ^ RotR(x, 11) ^ RotR(x, 25)); |
| 144 | + private static uint S0(uint x) => (RotR(x, 7) ^ RotR(x, 18) ^ ShR(x, 3)); |
| 145 | + private static uint S1(uint x) => (RotR(x, 17) ^ RotR(x, 19) ^ ShR(x, 10)); |
| 146 | + /// <summary> |
| 147 | + /// The 64 binary words K[i], given by the 32 first bits of the fractional parts |
| 148 | + /// of the cube root of the first 64 prime numbers. |
| 149 | + /// </summary> |
| 150 | + private static uint[] K = { 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, |
| 151 | + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, |
| 152 | + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, |
| 153 | + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, |
| 154 | + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, |
| 155 | + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, |
| 156 | + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, |
| 157 | + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2}; |
| 158 | + } |
| 159 | +} |
0 commit comments