Merge pull request #216 from ilkerde/master
[mono.git] / mcs / class / corlib / System.Security.Cryptography / SHA256Managed.cs
index 09d77022527c0fdfb8ef47e67297427a11f8cc1f..9f4c2b85ad8dfd1d9c3557ce1e95bda4fb1abc8c 100644 (file)
@@ -1,98 +1,82 @@
 //
-// System.Security.Cryptography SHA256Managed Class implementation
+// System.Security.Cryptography.SHA256Managed.cs
 //
 // Author:
 //   Matthew S. Ford (Matthew.S.Ford@Rose-Hulman.Edu)
 //
 // (C) 2001 
-// (C) 2004 Novell (http://www.novell.com)
+// Copyright (C) 2004, 2005 Novell, Inc (http://www.novell.com)
 //
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Runtime.InteropServices;
 
 namespace System.Security.Cryptography {
        
+       [ComVisible (true)]
        public class SHA256Managed : SHA256 {
 
                private const int BLOCK_SIZE_BYTES =  64;
-               private const int HASH_SIZE_BYTES  =  32;
                private uint[] _H;
-               private uint[] K;
-               private uint count;
+               private ulong count;
                private byte[] _ProcessingBuffer;   // Used to start data when passed less than a block worth.
                private int _ProcessingBufferCount; // Counts how much data we have stored that still needs processed.
+               private uint[] buff;
        
                public SHA256Managed () 
                {
                        _H = new uint [8];
                        _ProcessingBuffer = new byte [BLOCK_SIZE_BYTES];
+                       buff = new uint[64];
                        Initialize ();
                }
 
-               private uint Ch (uint u, uint v, uint w) 
-               {
-                       return (u&v) ^ (~u&w);
-               }
-
-               private uint Maj (uint u, uint v, uint w) 
-               {
-                       return (u&v) ^ (u&w) ^ (v&w);
-               }
-
-               private uint Ro0 (uint x) 
-               {
-                       return ((x >> 7) | (x << 25))
-                               ^ ((x >> 18) | (x << 14))
-                               ^ (x >> 3);
-               }
-
-               private uint Ro1 (uint x) 
-               {
-                       return ((x >> 17) | (x << 15))
-                               ^ ((x >> 19) | (x << 13))
-                               ^ (x >> 10);
-               }
-
-               private uint Sig0 (uint x) 
-               {
-                       return ((x >> 2) | (x << 30))
-                               ^ ((x >> 13) | (x << 19))
-                               ^ ((x >> 22) | (x << 10));
-               }
-
-               private uint Sig1 (uint x) 
-               {
-                       return ((x >> 6) | (x << 26))
-                               ^ ((x >> 11) | (x << 21))
-                               ^ ((x >> 25) | (x << 7));
-               }
-
-               protected override void HashCore (byte[] rgb, int start, int size) 
+               protected override void HashCore (byte[] rgb, int ibStart, int cbSize) 
                {
                        int i;
                        State = 1;
 
                        if (_ProcessingBufferCount != 0) {
-                               if (size < (BLOCK_SIZE_BYTES - _ProcessingBufferCount)) {
-                                       System.Buffer.BlockCopy (rgb, start, _ProcessingBuffer, _ProcessingBufferCount, size);
-                                       _ProcessingBufferCount += size;
+                               if (cbSize < (BLOCK_SIZE_BYTES - _ProcessingBufferCount)) {
+                                       System.Buffer.BlockCopy (rgb, ibStart, _ProcessingBuffer, _ProcessingBufferCount, cbSize);
+                                       _ProcessingBufferCount += cbSize;
                                        return;
                                }
                                else {
                                        i = (BLOCK_SIZE_BYTES - _ProcessingBufferCount);
-                                       System.Buffer.BlockCopy (rgb, start, _ProcessingBuffer, _ProcessingBufferCount, i);
+                                       System.Buffer.BlockCopy (rgb, ibStart, _ProcessingBuffer, _ProcessingBufferCount, i);
                                        ProcessBlock (_ProcessingBuffer, 0);
                                        _ProcessingBufferCount = 0;
-                                       start += i;
-                                       size -= i;
+                                       ibStart += i;
+                                       cbSize -= i;
                                }
                        }
 
-                       for (i=0; i<size-size%BLOCK_SIZE_BYTES; i += BLOCK_SIZE_BYTES) {
-                               ProcessBlock (rgb, start+i);
+                       for (i = 0; i < cbSize - cbSize % BLOCK_SIZE_BYTES; i += BLOCK_SIZE_BYTES) {
+                               ProcessBlock (rgb, ibStart + i);
                        }
 
-                       if (size%BLOCK_SIZE_BYTES != 0) {
-                               System.Buffer.BlockCopy (rgb, size-size%BLOCK_SIZE_BYTES+start, _ProcessingBuffer, 0, size%BLOCK_SIZE_BYTES);
-                               _ProcessingBufferCount = size%BLOCK_SIZE_BYTES;
+                       if (cbSize % BLOCK_SIZE_BYTES != 0) {
+                               System.Buffer.BlockCopy (rgb, cbSize - cbSize % BLOCK_SIZE_BYTES + ibStart, _ProcessingBuffer, 0, cbSize % BLOCK_SIZE_BYTES);
+                               _ProcessingBufferCount = cbSize % BLOCK_SIZE_BYTES;
                        }
                }
        
@@ -133,22 +117,26 @@ namespace System.Security.Cryptography {
                        uint a, b, c, d, e, f, g, h;
                        uint t1, t2;
                        int i;
-                       uint[] buff;
+                       uint[] K1 = SHAConstants.K1;
+                       uint[] buff = this.buff;
                
                        count += BLOCK_SIZE_BYTES;
-               
-                       buff = new uint[64];
 
                        for (i=0; i<16; i++) {
-                               buff[i] = ((uint)(inputBuffer[inputOffset+4*i]) << 24)
-                                       | ((uint)(inputBuffer[inputOffset+4*i+1]) << 16)
-                                       | ((uint)(inputBuffer[inputOffset+4*i+2]) <<  8)
-                                       | ((uint)(inputBuffer[inputOffset+4*i+3]));
+                               buff[i] = (uint)(((inputBuffer[inputOffset + 4 * i]) << 24)
+                                       | ((inputBuffer[inputOffset + 4 * i + 1]) << 16)
+                                       | ((inputBuffer[inputOffset + 4 * i + 2]) << 8)
+                                       | ((inputBuffer[inputOffset + 4 * i + 3])));
                        }
 
                
                        for (i=16; i<64; i++) {
-                               buff[i] = Ro1(buff[i-2]) + buff[i-7] + Ro0(buff[i-15]) + buff[i-16];
+                               t1 = buff[i - 15];
+                               t1 = (((t1 >> 7) | (t1 << 25)) ^ ((t1 >> 18) | (t1 << 14)) ^ (t1 >> 3));
+
+                               t2 = buff[i - 2];
+                               t2 = (((t2 >> 17) | (t2 << 15)) ^ ((t2 >> 19) | (t2 << 13)) ^ (t2 >> 10));
+                               buff[i] = t2 + buff[i - 7] + t1 + buff[i - 16];
                        }
 
                        a = _H[0];
@@ -161,8 +149,10 @@ namespace System.Security.Cryptography {
                        h = _H[7];
 
                        for (i=0; i<64; i++) {
-                               t1 = h + Sig1(e) + Ch(e,f,g) + SHAConstants.K1 [i] + buff[i];
-                               t2 = Sig0(a) + Maj(a,b,c);
+                               t1 = h + (((e >> 6) | (e << 26)) ^ ((e >> 11) | (e << 21)) ^ ((e >> 25) | (e << 7))) + ((e & f) ^ (~e & g)) + K1[i] + buff[i];
+
+                               t2 = (((a >> 2) | (a << 30)) ^ ((a >> 13) | (a << 19)) ^ ((a >> 22) | (a << 10)));
+                               t2 = t2 + ((a & b) ^ (a & c) ^ (b & c));
                                h = g;
                                g = f;
                                f = e;
@@ -185,46 +175,44 @@ namespace System.Security.Cryptography {
        
                private void ProcessFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount) 
                {
-                       byte[] fooBuffer;
-                       int paddingSize;
-                       int i;
-                       uint size;
-
-                       paddingSize = (int)(56 - (inputCount + count) % BLOCK_SIZE_BYTES);
+                       ulong total = count + (ulong)inputCount;
+                       int paddingSize = (56 - (int)(total % BLOCK_SIZE_BYTES));
 
                        if (paddingSize < 1)
                                paddingSize += BLOCK_SIZE_BYTES;
 
-                       fooBuffer = new byte[inputCount+paddingSize+8];
+                       byte[] fooBuffer = new byte[inputCount+paddingSize+8];
 
-                       for (i=0; i<inputCount; i++) {
+                       for (int i=0; i<inputCount; i++) {
                                fooBuffer[i] = inputBuffer[i+inputOffset];
                        }
 
                        fooBuffer[inputCount] = 0x80;
-                       for (i=inputCount+1; i<inputCount+paddingSize; i++) {
+                       for (int i=inputCount+1; i<inputCount+paddingSize; i++) {
                                fooBuffer[i] = 0x00;
                        }
 
-                       size = (uint)(count+inputCount);
-                       size *= 8;
-
-                       fooBuffer[inputCount+paddingSize]   = 0x00;
-                       fooBuffer[inputCount+paddingSize+1] = 0x00;
-                       fooBuffer[inputCount+paddingSize+2] = 0x00;
-                       fooBuffer[inputCount+paddingSize+3] = 0x00;
-
-                       fooBuffer[inputCount+paddingSize+4] = (byte)((size) >> 24);
-                       fooBuffer[inputCount+paddingSize+5] = (byte)((size) >> 16);
-                       fooBuffer[inputCount+paddingSize+6] = (byte)((size) >>  8);
-                       fooBuffer[inputCount+paddingSize+7] = (byte)((size) >>  0);
-
-                       ProcessBlock(fooBuffer, 0);
+                       // I deal in bytes. The algorithm deals in bits.
+                       ulong size = total << 3;
+                       AddLength (size, fooBuffer, inputCount+paddingSize);
+                       ProcessBlock (fooBuffer, 0);
 
                        if (inputCount+paddingSize+8 == 128) {
                                ProcessBlock(fooBuffer, 64);
                        }
                }
+
+               internal void AddLength (ulong length, byte[] buffer, int position)
+               {
+                       buffer [position++] = (byte)(length >> 56);
+                       buffer [position++] = (byte)(length >> 48);
+                       buffer [position++] = (byte)(length >> 40);
+                       buffer [position++] = (byte)(length >> 32);
+                       buffer [position++] = (byte)(length >> 24);
+                       buffer [position++] = (byte)(length >> 16);
+                       buffer [position++] = (byte)(length >>  8);
+                       buffer [position]   = (byte)(length);
+               }
        }
 }