static Word32 f(int t, Word32 x, Word32 y, Word32 z) { // This function is used in Sha-1 // should have 0 <= t <= 79 if (t >= 0 && t <= 19) { return(Ch(x, y, z)); } else if (t >= 20 && t <= 39) { return(Parity(x, y, z)); } else if (t >= 40 && t <= 59) { return(Maj(x, y, z)); } else if (t >= 60 && t <= 79) { return(Parity(x, y, z)); } else { throw new ArgumentException("ERROR: t is out of bounds"); } }
static byte[] Sha256Algorithm(byte[] plaintext, Word32[] H0, int numberBits) { Block512[] blocks = ConvertPaddedTextToBlock512Array(PadPlainText512(plaintext)); // Define the hash variables and set their initial values. Word32[] H = H0; for (int i = 0; i < blocks.Length; i++) { Word32[] W = CreateMessageScheduleSha256(blocks[i]); // Set the working variables a,...,h to the current hash values. Word32 a = H[0]; Word32 b = H[1]; Word32 c = H[2]; Word32 d = H[3]; Word32 e = H[4]; Word32 f = H[5]; Word32 g = H[6]; Word32 h = H[7]; for (int t = 0; t < 64; t++) { Word32 T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[t] + W[t]; Word32 T2 = Sigma0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; } // Update the current value of the hash H after processing block i. H[0] += a; H[1] += b; H[2] += c; H[3] += d; H[4] += e; H[5] += f; H[6] += g; H[7] += h; } // Concatenate all the Word32 Hash Values byte[] hash = ShaUtilities.Word32ArrayToByteArray(H); // The number of bytes in the final output hash int numberBytes = numberBits / 8; byte[] truncatedHash = new byte[numberBytes]; Array.Copy(hash, truncatedHash, numberBytes); return(truncatedHash); }
public static Word32 ByteArrayToWord32(byte[] B, int startIndex) { // We assume: 0 <= startIndex < B. Length, and startIndex + 4 <= B.Length Word32 c = 256; Word32 output = 0; for (int i = startIndex; i < startIndex + 4; i++) { output = output * c + (Word32)B[i]; } return(output); }
public static Word32[] ByteArrayToWord32Array(byte[] B) { // We assume B is not null, is not empty and number elements is divisible by 4 int numberBytes = B.Length; int n = numberBytes / 4; // 4 bytes for each Word32 Word32[] word32Array = new Word32[n]; for (int i = 0; i < n; i++) { word32Array[i] = ByteArrayToWord32(B, 4 * i); } return(word32Array); }
static byte[] Sha1Algorithm(byte[] plaintext) { Block512[] blocks = ConvertPaddedTextToBlock512Array(PadPlainText512(plaintext)); // Define the hash variable and set its initial values. Word32[] H = new Word32[5]; H0Sha1.CopyTo(H, 0); for (int i = 0; i < blocks.Length; i++) { Word32[] W = CreateMessageScheduleSha1(blocks[i]); // Set the working variables a,...,e to the current hash values. Word32 a = H[0]; Word32 b = H[1]; Word32 c = H[2]; Word32 d = H[3]; Word32 e = H[4]; for (int t = 0; t < 80; t++) { Word32 T = RotL(5, a) + f(t, b, c, d) + e + K1[t] + W[t]; e = d; d = c; c = RotL(30, b); b = a; a = T; } // Update the current value of the hash H after processing block i. H[0] += a; H[1] += b; H[2] += c; H[3] += d; H[4] += e; } // Concatenating the final 5 hash words H[0],...,H[4] gives the digest. // Since each H[i] is 4 bytes, the digest is 5 * 4 = 20 bytes = 160 bits. return(ShaUtilities.Word32ArrayToByteArray(H)); }
static Word32[] CreateMessageScheduleSha1(Block512 block) { // The message schedule. Word32[] W = new Word32[80]; // Prepare the message schedule W. // The first 16 words in W are the same as the words of the block. // The remaining 80-16 = 64 words in W are functions of the previously defined words. for (int t = 0; t < 80; t++) { if (t < 16) { W[t] = block.words[t]; } else { W[t] = RotL(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); } } return(W); }
static Word32[] CreateMessageScheduleSha256(Block512 block) { // The message schedule. Word32[] W = new Word32[64]; // Prepare the message schedule W. // The first 16 words in W are the same as the words of the block. // The remaining 64-16 = 48 words in W are functions of the previously defined words. for (int t = 0; t < 64; t++) { if (t < 16) { W[t] = block.words[t]; } else { W[t] = sigma1_256(W[t - 2]) + W[t - 7] + sigma0_256(W[t - 15]) + W[t - 16]; } } return(W); }
// Returns an array of 4 bytes. public static byte[] Word32ToByteArray(Word32 x) { byte[] b = BitConverter.GetBytes(x); Array.Reverse(b); return(b); }
static Word32 sigma1_256(Word32 x) { return(RotR(17, x) ^ RotR(19, x) ^ ShR(10, x)); }
static Word32 sigma0_256(Word32 x) { return(RotR(7, x) ^ RotR(18, x) ^ ShR(3, x)); }
static Word32 Sigma1_256(Word32 x) { return(RotR(6, x) ^ RotR(11, x) ^ RotR(25, x)); }
static Word32 Sigma0_256(Word32 x) { return(RotR(2, x) ^ RotR(13, x) ^ RotR(22, x)); }
static Word32 Maj(Word32 x, Word32 y, Word32 z) { return((x & y) ^ (x & z) ^ (y & z)); }
static Word32 Ch(Word32 x, Word32 y, Word32 z) { return((x & y) ^ (~x & z)); }
static Word32 RotL(int n, Word32 x) { // should have 0 <= n < 32 return((x << n) | (x >> 32 - n)); }
// Most of these functions have a Word32 version and a Word64 version. // Sometimes they are the same (Ch, Maj,..) but sometimes different (Sigma0_256, Sigma0_512). // We do not need a RotL or Parity function for Word64 since they are only used in Sha-1. static Word32 ShR(int n, Word32 x) { // should have 0 <= n < 32 return(x >> n); }
static Word32 Parity(Word32 x, Word32 y, Word32 z) { return(x ^ y ^ z); }
public static string Word32ToHexString(Word32 x) { return(ByteArrayToHexString(Word32ToByteArray(x))); }