using System; using System.Collections.ObjectModel; namespace SUISS.Core.Crypto { public class Sha256 { private static uint ROTL(uint x, byte n) { return x << (int)n | x >> (int)(32 - n); } private static uint ROTR(uint x, byte n) { return x >> (int)n | x << (int)(32 - n); } private static uint Ch(uint x, uint y, uint z) { return (x & y) ^ (~x & z); } private static uint Maj(uint x, uint y, uint z) { return (x & y) ^ (x & z) ^ (y & z); } private static uint Sigma0(uint x) { return Sha256.ROTR(x, 2) ^ Sha256.ROTR(x, 13) ^ Sha256.ROTR(x, 22); } private static uint Sigma1(uint x) { return Sha256.ROTR(x, 6) ^ Sha256.ROTR(x, 11) ^ Sha256.ROTR(x, 25); } private static uint sigma0(uint x) { return Sha256.ROTR(x, 7) ^ Sha256.ROTR(x, 18) ^ x >> 3; } private static uint sigma1(uint x) { return Sha256.ROTR(x, 17) ^ Sha256.ROTR(x, 19) ^ x >> 10; } private void processBlock(uint[] M) { uint[] array = new uint[64]; for (int i = 0; i < 16; i++) { array[i] = M[i]; } for (int j = 16; j < 64; j++) { array[j] = Sha256.sigma1(array[j - 2]) + array[j - 7] + Sha256.sigma0(array[j - 15]) + array[j - 16]; } uint num = this.H[0]; uint num2 = this.H[1]; uint num3 = this.H[2]; uint num4 = this.H[3]; uint num5 = this.H[4]; uint num6 = this.H[5]; uint num7 = this.H[6]; uint num8 = this.H[7]; for (int k = 0; k < 64; k++) { uint num9 = num8 + Sha256.Sigma1(num5) + Sha256.Ch(num5, num6, num7) + Sha256.K[k] + array[k]; uint num10 = Sha256.Sigma0(num) + Sha256.Maj(num, num2, num3); num8 = num7; num7 = num6; num6 = num5; num5 = num4 + num9; num4 = num3; num3 = num2; num2 = num; num = num9 + num10; } this.H[0] = num + this.H[0]; this.H[1] = num2 + this.H[1]; this.H[2] = num3 + this.H[2]; this.H[3] = num4 + this.H[3]; this.H[4] = num5 + this.H[4]; this.H[5] = num6 + this.H[5]; this.H[6] = num7 + this.H[6]; this.H[7] = num8 + this.H[7]; } public void AddData(byte[] data, uint offset, uint len) { if (this.closed) { throw new InvalidOperationException("Adding data to a closed hasher."); } if (len == 0u) { return; } this.bits_processed += (ulong)(len * 8u); while (len > 0u) { uint num; if (len < 64u) { if (this.pending_block_off + len > 64u) { num = 64u - this.pending_block_off; } else { num = len; } } else { num = 64u - this.pending_block_off; } Array.Copy(data, (long)((ulong)offset), this.pending_block, (long)((ulong)this.pending_block_off), (long)((ulong)num)); len -= num; offset += num; this.pending_block_off += num; if (this.pending_block_off == 64u) { Sha256.toUintArray(this.pending_block, this.uint_buffer); this.processBlock(this.uint_buffer); this.pending_block_off = 0u; } } } public ReadOnlyCollection GetHash() { return Sha256.toByteArray(this.GetHashUInt32()); } public ReadOnlyCollection GetHashUInt32() { if (!this.closed) { ulong num = this.bits_processed; this.AddData(new byte[] { 128 }, 0u, 1u); uint num2 = 64u - this.pending_block_off; if (num2 < 8u) { num2 += 64u; } byte[] array = new byte[num2]; for (uint num3 = 1u; num3 <= 8u; num3 += 1u) { array[(int)(checked((IntPtr)(unchecked((long)array.Length - (long)((ulong)num3)))))] = (byte)num; num >>= 8; } this.AddData(array, 0u, (uint)array.Length); this.closed = true; } return Array.AsReadOnly(this.H); } private static void toUintArray(byte[] src, uint[] dest) { uint num = 0u; uint num2 = 0u; while ((ulong)num < (ulong)((long)dest.Length)) { dest[(int)((UIntPtr)num)] = (uint)((int)src[(int)((UIntPtr)num2)] << 24 | (int)src[(int)((UIntPtr)(num2 + 1u))] << 16 | (int)src[(int)((UIntPtr)(num2 + 2u))] << 8 | (int)src[(int)((UIntPtr)(num2 + 3u))]); num += 1u; num2 += 4u; } } private static ReadOnlyCollection toByteArray(ReadOnlyCollection src) { byte[] array = new byte[src.Count * 4]; int num = 0; for (int i = 0; i < src.Count; i++) { array[num++] = (byte)(src[i] >> 24); array[num++] = (byte)(src[i] >> 16); array[num++] = (byte)(src[i] >> 8); array[num++] = (byte)src[i]; } return Array.AsReadOnly(array); } public static ReadOnlyCollection HashBytes(params object[] args) { Sha256 sha = new Sha256(); foreach (object obj in args) { if (obj is byte[]) { byte[] array = obj as byte[]; sha.AddData(array, 0u, (uint)array.Length); } else { if (!(obj is ReadOnlyCollection)) { throw new ArgumentException(); } ReadOnlyCollection readOnlyCollection = obj as ReadOnlyCollection; byte[] array2 = new byte[readOnlyCollection.Count]; readOnlyCollection.CopyTo(array2, 0); sha.AddData(array2, 0u, (uint)array2.Length); } } return sha.GetHash(); } public static byte[] HashToBytes(params object[] args) { ReadOnlyCollection readOnlyCollection = Sha256.HashBytes(args); byte[] array = new byte[readOnlyCollection.Count]; readOnlyCollection.CopyTo(array, 0); return array; } private static readonly uint[] K = new uint[] { 1116352408u, 1899447441u, 3049323471u, 3921009573u, 961987163u, 1508970993u, 2453635748u, 2870763221u, 3624381080u, 310598401u, 607225278u, 1426881987u, 1925078388u, 2162078206u, 2614888103u, 3248222580u, 3835390401u, 4022224774u, 264347078u, 604807628u, 770255983u, 1249150122u, 1555081692u, 1996064986u, 2554220882u, 2821834349u, 2952996808u, 3210313671u, 3336571891u, 3584528711u, 113926993u, 338241895u, 666307205u, 773529912u, 1294757372u, 1396182291u, 1695183700u, 1986661051u, 2177026350u, 2456956037u, 2730485921u, 2820302411u, 3259730800u, 3345764771u, 3516065817u, 3600352804u, 4094571909u, 275423344u, 430227734u, 506948616u, 659060556u, 883997877u, 958139571u, 1322822218u, 1537002063u, 1747873779u, 1955562222u, 2024104815u, 2227730452u, 2361852424u, 2428436474u, 2756734187u, 3204031479u, 3329325298u }; private uint[] H = new uint[] { 1779033703u, 3144134277u, 1013904242u, 2773480762u, 1359893119u, 2600822924u, 528734635u, 1541459225u }; private byte[] pending_block = new byte[64]; private uint pending_block_off; private uint[] uint_buffer = new uint[16]; private ulong bits_processed; private bool closed; } }