2 // System.Security.Cryptography SHA256Managed Class implementation
5 // Matthew S. Ford (Matthew.S.Ford@Rose-Hulman.Edu)
11 using System.Security.Cryptography;
13 namespace System.Security.Cryptography {
16 /// C# implementation of the SHA1 cryptographic hash function.
17 /// LAMESPEC?: Basically the same thing as SHA1Managed except for how its implemented.
19 public class SHA256Managed : SHA256 {
20 private const int BLOCK_SIZE_BYTES = 64;
21 private const int HASH_SIZE_BYTES = 32;
22 private const int HASH_SIZE_BITS = 256;
23 [CLSCompliant(false)] private uint[] _H;
24 [CLSCompliant(false)] private uint[] K;
25 [CLSCompliant(false)] private uint count;
26 private byte[] _ProcessingBuffer; // Used to start data when passed less than a block worth.
27 private int _ProcessingBufferCount; // Counts how much data we have stored that still needs processed.
30 /// Creates a new SHA256Managed class.
32 public SHA256Managed ()
35 HashSizeValue = HASH_SIZE_BITS;
36 _ProcessingBuffer = new byte[BLOCK_SIZE_BYTES];
39 K[0] = 0x428A2F98; K[1] = 0x71374491; K[2] = 0xB5C0FBCF; K[3] = 0xE9B5DBA5;
40 K[4] = 0x3956C25B; K[5] = 0x59F111F1; K[6] = 0x923F82A4; K[7] = 0xAB1C5ED5;
41 K[8] = 0xD807AA98; K[9] = 0x12835B01; K[10] = 0x243185BE; K[11] = 0x550C7DC3;
42 K[12] = 0x72BE5D74; K[13] = 0x80DEB1FE; K[14] = 0x9BDC06A7; K[15] = 0xC19BF174;
43 K[16] = 0xE49B69C1; K[17] = 0xEFBE4786; K[18] = 0x0FC19DC6; K[19] = 0x240CA1CC;
44 K[20] = 0x2DE92C6F; K[21] = 0x4A7484AA; K[22] = 0x5CB0A9DC; K[23] = 0x76F988DA;
45 K[24] = 0x983E5152; K[25] = 0xA831C66D; K[26] = 0xB00327C8; K[27] = 0xBF597FC7;
46 K[28] = 0xC6E00BF3; K[29] = 0xD5A79147; K[30] = 0x06CA6351; K[31] = 0x14292967;
47 K[32] = 0x27B70A85; K[33] = 0x2E1B2138; K[34] = 0x4D2C6DFC; K[35] = 0x53380D13;
48 K[36] = 0x650A7354; K[37] = 0x766A0ABB; K[38] = 0x81C2C92E; K[39] = 0x92722C85;
49 K[40] = 0xA2BFE8A1; K[41] = 0xA81A664B; K[42] = 0xC24B8B70; K[43] = 0xC76C51A3;
50 K[44] = 0xD192E819; K[45] = 0xD6990624; K[46] = 0xF40E3585; K[47] = 0x106AA070;
51 K[48] = 0x19A4C116; K[49] = 0x1E376C08; K[50] = 0x2748774C; K[51] = 0x34B0BCB5;
52 K[52] = 0x391C0CB3; K[53] = 0x4ED8AA4A; K[54] = 0x5B9CCA4F; K[55] = 0x682E6FF3;
53 K[56] = 0x748F82EE; K[57] = 0x78A5636F; K[58] = 0x84C87814; K[59] = 0x8CC70208;
54 K[60] = 0x90BEFFFA; K[61] = 0xA4506CEB; K[62] = 0xBEF9A3F7; K[63] = 0xC67178F2;
61 /// Internal function handling a subset of the algorithm.
63 private uint Ch (uint u, uint v, uint w)
65 return (u&v) ^ (~u&w);
69 /// Internal function handling a subset of the algorithm.
71 private uint Maj (uint u, uint v, uint w)
73 return (u&v) ^ (u&w) ^ (v&w);
77 /// Internal function handling a subset of the algorithm.
79 private uint Ro0 (uint x)
81 return ((x >> 7) | (x << 25))
82 ^ ((x >> 18) | (x << 14))
87 /// Internal function handling a subset of the algorithm.
89 private uint Ro1 (uint x)
91 return ((x >> 17) | (x << 15))
92 ^ ((x >> 19) | (x << 13))
97 /// Internal function handling a subset of the algorithm.
99 private uint Sig0 (uint x)
101 return ((x >> 2) | (x << 30))
102 ^ ((x >> 13) | (x << 19))
103 ^ ((x >> 22) | (x << 10));
107 /// Internal function handling a subset of the algorithm.
109 private uint Sig1 (uint x)
111 return ((x >> 6) | (x << 26))
112 ^ ((x >> 11) | (x << 21))
113 ^ ((x >> 25) | (x << 7));
117 /// Drives the hashing function.
119 /// <param name="rgb">Byte array containing the data to hash.</param>
120 /// <param name="start">Where in the input buffer to start.</param>
121 /// <param name="size">Size in bytes of the data in the buffer to hash.</param>
122 protected override void HashCore (byte[] rgb, int start, int size)
127 if (_ProcessingBufferCount != 0) {
128 if (size < (BLOCK_SIZE_BYTES - _ProcessingBufferCount)) {
129 System.Buffer.BlockCopy (rgb, start, _ProcessingBuffer, _ProcessingBufferCount, size);
130 _ProcessingBufferCount += size;
134 i = (BLOCK_SIZE_BYTES - _ProcessingBufferCount);
135 System.Buffer.BlockCopy (rgb, start, _ProcessingBuffer, _ProcessingBufferCount, i);
136 ProcessBlock (_ProcessingBuffer, 0);
137 _ProcessingBufferCount = 0;
143 for (i=0; i<size-size%BLOCK_SIZE_BYTES; i += BLOCK_SIZE_BYTES) {
144 ProcessBlock (rgb, start+i);
147 if (size%BLOCK_SIZE_BYTES != 0) {
148 System.Buffer.BlockCopy (rgb, size-size%BLOCK_SIZE_BYTES+start, _ProcessingBuffer, 0, size%BLOCK_SIZE_BYTES);
149 _ProcessingBufferCount = size%BLOCK_SIZE_BYTES;
154 /// This finalizes the hash. Takes the data from the chaining variables and returns it.
156 protected override byte[] HashFinal ()
158 byte[] hash = new byte[32];
161 ProcessFinalBlock(_ProcessingBuffer, 0, _ProcessingBufferCount);
163 for (i=0; i<8; i++) {
164 for (j=0; j<4; j++) {
165 hash[i*4+j] = (byte)(_H[i] >> (24-j*8));
174 /// Resets the class after use. Called automatically after hashing is done.
176 public override void Initialize ()
179 _ProcessingBufferCount = 0;
192 /// This is the meat of the hash function. It is what processes each block one at a time.
194 /// <param name="inputBuffer">Byte array to process data from.</param>
195 /// <param name="inputOffset">Where in the byte array to start processing.</param>
196 private void ProcessBlock (byte[] inputBuffer, int inputOffset)
198 uint a, b, c, d, e, f, g, h;
203 count += BLOCK_SIZE_BYTES;
207 for (i=0; i<16; i++) {
208 buff[i] = ((uint)(inputBuffer[inputOffset+4*i]) << 24)
209 | ((uint)(inputBuffer[inputOffset+4*i+1]) << 16)
210 | ((uint)(inputBuffer[inputOffset+4*i+2]) << 8)
211 | ((uint)(inputBuffer[inputOffset+4*i+3]));
215 for (i=16; i<64; i++) {
216 buff[i] = Ro1(buff[i-2]) + buff[i-7] + Ro0(buff[i-15]) + buff[i-16];
228 for (i=0; i<64; i++) {
229 t1 = h + Sig1(e) + Ch(e,f,g) + K[i] + buff[i];
230 t2 = Sig0(a) + Maj(a,b,c);
252 /// Pads and then processes the final block.
255 /// <param name="inputBuffer">Buffer to grab data from.</param>
256 /// <param name="inputOffset">Position in buffer in bytes to get data from.</param>
257 /// <param name="inputCount">How much data in bytes in the buffer to use.</param>
258 private void ProcessFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
265 paddingSize = (int)(56 - (inputCount + count) % BLOCK_SIZE_BYTES);
268 paddingSize += BLOCK_SIZE_BYTES;
270 fooBuffer = new byte[inputCount+paddingSize+8];
272 for (i=0; i<inputCount; i++) {
273 fooBuffer[i] = inputBuffer[i+inputOffset];
276 fooBuffer[inputCount] = 0x80;
277 for (i=inputCount+1; i<inputCount+paddingSize; i++) {
281 size = (uint)(count+inputCount);
284 fooBuffer[inputCount+paddingSize] = 0x00;
285 fooBuffer[inputCount+paddingSize+1] = 0x00;
286 fooBuffer[inputCount+paddingSize+2] = 0x00;
287 fooBuffer[inputCount+paddingSize+3] = 0x00;
289 fooBuffer[inputCount+paddingSize+4] = (byte)((size) >> 24);
290 fooBuffer[inputCount+paddingSize+5] = (byte)((size) >> 16);
291 fooBuffer[inputCount+paddingSize+6] = (byte)((size) >> 8);
292 fooBuffer[inputCount+paddingSize+7] = (byte)((size) >> 0);
294 ProcessBlock(fooBuffer, 0);
296 if (inputCount+paddingSize+8 == 128) {
297 ProcessBlock(fooBuffer, 64);