2 // System.Security.Cryptography.SHA1CryptoServiceProvider.cs
5 // Matthew S. Ford (Matthew.S.Ford@Rose-Hulman.Edu)
6 // Sebastien Pouliot (sebastien@ximian.com)
8 // Copyright 2001 by Matthew S. Ford.
9 // Copyright (C) 2004, 2005, 2008 Novell, Inc (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 // The MS Framework includes two (almost) identical class for SHA1.
33 // SHA1Managed is a 100% managed implementation.
34 // SHA1CryptoServiceProvider (this file) is a wrapper on CryptoAPI.
35 // Mono must provide those two class for binary compatibility.
36 // In our case both class are wrappers around a managed internal class SHA1Internal.
38 using System
.Runtime
.InteropServices
;
40 namespace System
.Security
.Cryptography
{
42 internal class SHA1Internal
{
44 private const int BLOCK_SIZE_BYTES
= 64;
45 private uint[] _H
; // these are my chaining variables
47 private byte[] _ProcessingBuffer
; // Used to start data when passed less than a block worth.
48 private int _ProcessingBufferCount
; // Counts how much data we have stored that still needs processed.
51 public SHA1Internal ()
54 _ProcessingBuffer
= new byte[BLOCK_SIZE_BYTES
];
60 public void HashCore (byte[] rgb
, int ibStart
, int cbSize
)
64 if (_ProcessingBufferCount
!= 0) {
65 if (cbSize
< (BLOCK_SIZE_BYTES
- _ProcessingBufferCount
)) {
66 System
.Buffer
.BlockCopy (rgb
, ibStart
, _ProcessingBuffer
, _ProcessingBufferCount
, cbSize
);
67 _ProcessingBufferCount
+= cbSize
;
71 i
= (BLOCK_SIZE_BYTES
- _ProcessingBufferCount
);
72 System
.Buffer
.BlockCopy (rgb
, ibStart
, _ProcessingBuffer
, _ProcessingBufferCount
, i
);
73 ProcessBlock (_ProcessingBuffer
, 0);
74 _ProcessingBufferCount
= 0;
80 for (i
= 0; i
< cbSize
- cbSize
% BLOCK_SIZE_BYTES
; i
+= BLOCK_SIZE_BYTES
) {
81 ProcessBlock (rgb
, (uint)(ibStart
+ i
));
84 if (cbSize
% BLOCK_SIZE_BYTES
!= 0) {
85 System
.Buffer
.BlockCopy (rgb
, cbSize
- cbSize
% BLOCK_SIZE_BYTES
+ ibStart
, _ProcessingBuffer
, 0, cbSize
% BLOCK_SIZE_BYTES
);
86 _ProcessingBufferCount
= cbSize
% BLOCK_SIZE_BYTES
;
90 public byte[] HashFinal ()
92 byte[] hash
= new byte[20];
94 ProcessFinalBlock (_ProcessingBuffer
, 0, _ProcessingBufferCount
);
96 for (int i
=0; i
<5; i
++) {
97 for (int j
=0; j
<4; j
++) {
98 hash
[i
*4+j
] = (byte)(_H
[i
] >> (8*(3-j
)));
105 public void Initialize ()
108 _ProcessingBufferCount
= 0;
117 private void ProcessBlock(byte[] inputBuffer
, uint inputOffset
)
121 count
+= BLOCK_SIZE_BYTES
;
123 // abc removal would not work on the fields
125 uint[] buff
= this.buff
;
126 InitialiseBuff(buff
, inputBuffer
, inputOffset
);
135 // This function was unrolled because it seems to be doubling our performance with current compiler/VM.
136 // Possibly roll up if this changes.
138 // ---- Round 1 --------
142 e
+= ((a
<< 5) | (a
>> 27)) + (((c ^ d
) & b
) ^ d
) + 0x5A827999 + buff
[i
];
143 b
= (b
<< 30) | (b
>> 2);
145 d
+= ((e
<< 5) | (e
>> 27)) + (((b ^ c
) & a
) ^ c
) + 0x5A827999 + buff
[i
+1];
146 a
= (a
<< 30) | (a
>> 2);
148 c
+= ((d
<< 5) | (d
>> 27)) + (((a ^ b
) & e
) ^ b
) + 0x5A827999 + buff
[i
+2];
149 e
= (e
<< 30) | (e
>> 2);
151 b
+= ((c
<< 5) | (c
>> 27)) + (((e ^ a
) & d
) ^ a
) + 0x5A827999 + buff
[i
+3];
152 d
= (d
<< 30) | (d
>> 2);
154 a
+= ((b
<< 5) | (b
>> 27)) + (((d ^ e
) & c
) ^ e
) + 0x5A827999 + buff
[i
+4];
155 c
= (c
<< 30) | (c
>> 2);
159 // ---- Round 2 --------
162 e
+= ((a
<< 5) | (a
>> 27)) + (b ^ c ^ d
) + 0x6ED9EBA1 + buff
[i
];
163 b
= (b
<< 30) | (b
>> 2);
165 d
+= ((e
<< 5) | (e
>> 27)) + (a ^ b ^ c
) + 0x6ED9EBA1 + buff
[i
+ 1];
166 a
= (a
<< 30) | (a
>> 2);
168 c
+= ((d
<< 5) | (d
>> 27)) + (e ^ a ^ b
) + 0x6ED9EBA1 + buff
[i
+ 2];
169 e
= (e
<< 30) | (e
>> 2);
171 b
+= ((c
<< 5) | (c
>> 27)) + (d ^ e ^ a
) + 0x6ED9EBA1 + buff
[i
+ 3];
172 d
= (d
<< 30) | (d
>> 2);
174 a
+= ((b
<< 5) | (b
>> 27)) + (c ^ d ^ e
) + 0x6ED9EBA1 + buff
[i
+ 4];
175 c
= (c
<< 30) | (c
>> 2);
179 // ---- Round 3 --------
182 e
+= ((a
<< 5) | (a
>> 27)) + ((b
& c
) | (b
& d
) | (c
& d
)) + 0x8F1BBCDC + buff
[i
];
183 b
= (b
<< 30) | (b
>> 2);
185 d
+= ((e
<< 5) | (e
>> 27)) + ((a
& b
) | (a
& c
) | (b
& c
)) + 0x8F1BBCDC + buff
[i
+ 1];
186 a
= (a
<< 30) | (a
>> 2);
188 c
+= ((d
<< 5) | (d
>> 27)) + ((e
& a
) | (e
& b
) | (a
& b
)) + 0x8F1BBCDC + buff
[i
+ 2];
189 e
= (e
<< 30) | (e
>> 2);
191 b
+= ((c
<< 5) | (c
>> 27)) + ((d
& e
) | (d
& a
) | (e
& a
)) + 0x8F1BBCDC + buff
[i
+ 3];
192 d
= (d
<< 30) | (d
>> 2);
194 a
+= ((b
<< 5) | (b
>> 27)) + ((c
& d
) | (c
& e
) | (d
& e
)) + 0x8F1BBCDC + buff
[i
+ 4];
195 c
= (c
<< 30) | (c
>> 2);
199 // ---- Round 4 --------
202 e
+= ((a
<< 5) | (a
>> 27)) + (b ^ c ^ d
) + 0xCA62C1D6 + buff
[i
];
203 b
= (b
<< 30) | (b
>> 2);
205 d
+= ((e
<< 5) | (e
>> 27)) + (a ^ b ^ c
) + 0xCA62C1D6 + buff
[i
+ 1];
206 a
= (a
<< 30) | (a
>> 2);
208 c
+= ((d
<< 5) | (d
>> 27)) + (e ^ a ^ b
) + 0xCA62C1D6 + buff
[i
+ 2];
209 e
= (e
<< 30) | (e
>> 2);
211 b
+= ((c
<< 5) | (c
>> 27)) + (d ^ e ^ a
) + 0xCA62C1D6 + buff
[i
+ 3];
212 d
= (d
<< 30) | (d
>> 2);
214 a
+= ((b
<< 5) | (b
>> 27)) + (c ^ d ^ e
) + 0xCA62C1D6 + buff
[i
+ 4];
215 c
= (c
<< 30) | (c
>> 2);
226 private static void InitialiseBuff(uint[] buff
, byte[] input
, uint inputOffset
)
228 buff
[0] = (uint)((input
[inputOffset
+ 0] << 24) | (input
[inputOffset
+ 1] << 16) | (input
[inputOffset
+ 2] << 8) | (input
[inputOffset
+ 3]));
229 buff
[1] = (uint)((input
[inputOffset
+ 4] << 24) | (input
[inputOffset
+ 5] << 16) | (input
[inputOffset
+ 6] << 8) | (input
[inputOffset
+ 7]));
230 buff
[2] = (uint)((input
[inputOffset
+ 8] << 24) | (input
[inputOffset
+ 9] << 16) | (input
[inputOffset
+ 10] << 8) | (input
[inputOffset
+ 11]));
231 buff
[3] = (uint)((input
[inputOffset
+ 12] << 24) | (input
[inputOffset
+ 13] << 16) | (input
[inputOffset
+ 14] << 8) | (input
[inputOffset
+ 15]));
232 buff
[4] = (uint)((input
[inputOffset
+ 16] << 24) | (input
[inputOffset
+ 17] << 16) | (input
[inputOffset
+ 18] << 8) | (input
[inputOffset
+ 19]));
233 buff
[5] = (uint)((input
[inputOffset
+ 20] << 24) | (input
[inputOffset
+ 21] << 16) | (input
[inputOffset
+ 22] << 8) | (input
[inputOffset
+ 23]));
234 buff
[6] = (uint)((input
[inputOffset
+ 24] << 24) | (input
[inputOffset
+ 25] << 16) | (input
[inputOffset
+ 26] << 8) | (input
[inputOffset
+ 27]));
235 buff
[7] = (uint)((input
[inputOffset
+ 28] << 24) | (input
[inputOffset
+ 29] << 16) | (input
[inputOffset
+ 30] << 8) | (input
[inputOffset
+ 31]));
236 buff
[8] = (uint)((input
[inputOffset
+ 32] << 24) | (input
[inputOffset
+ 33] << 16) | (input
[inputOffset
+ 34] << 8) | (input
[inputOffset
+ 35]));
237 buff
[9] = (uint)((input
[inputOffset
+ 36] << 24) | (input
[inputOffset
+ 37] << 16) | (input
[inputOffset
+ 38] << 8) | (input
[inputOffset
+ 39]));
238 buff
[10] = (uint)((input
[inputOffset
+ 40] << 24) | (input
[inputOffset
+ 41] << 16) | (input
[inputOffset
+ 42] << 8) | (input
[inputOffset
+ 43]));
239 buff
[11] = (uint)((input
[inputOffset
+ 44] << 24) | (input
[inputOffset
+ 45] << 16) | (input
[inputOffset
+ 46] << 8) | (input
[inputOffset
+ 47]));
240 buff
[12] = (uint)((input
[inputOffset
+ 48] << 24) | (input
[inputOffset
+ 49] << 16) | (input
[inputOffset
+ 50] << 8) | (input
[inputOffset
+ 51]));
241 buff
[13] = (uint)((input
[inputOffset
+ 52] << 24) | (input
[inputOffset
+ 53] << 16) | (input
[inputOffset
+ 54] << 8) | (input
[inputOffset
+ 55]));
242 buff
[14] = (uint)((input
[inputOffset
+ 56] << 24) | (input
[inputOffset
+ 57] << 16) | (input
[inputOffset
+ 58] << 8) | (input
[inputOffset
+ 59]));
243 buff
[15] = (uint)((input
[inputOffset
+ 60] << 24) | (input
[inputOffset
+ 61] << 16) | (input
[inputOffset
+ 62] << 8) | (input
[inputOffset
+ 63]));
246 private static void FillBuff(uint[] buff
)
249 for (int i
= 16; i
< 80; i
+= 8)
251 val
= buff
[i
- 3] ^ buff
[i
- 8] ^ buff
[i
- 14] ^ buff
[i
- 16];
252 buff
[i
] = (val
<< 1) | (val
>> 31);
254 val
= buff
[i
- 2] ^ buff
[i
- 7] ^ buff
[i
- 13] ^ buff
[i
- 15];
255 buff
[i
+ 1] = (val
<< 1) | (val
>> 31);
257 val
= buff
[i
- 1] ^ buff
[i
- 6] ^ buff
[i
- 12] ^ buff
[i
- 14];
258 buff
[i
+ 2] = (val
<< 1) | (val
>> 31);
260 val
= buff
[i
+ 0] ^ buff
[i
- 5] ^ buff
[i
- 11] ^ buff
[i
- 13];
261 buff
[i
+ 3] = (val
<< 1) | (val
>> 31);
263 val
= buff
[i
+ 1] ^ buff
[i
- 4] ^ buff
[i
- 10] ^ buff
[i
- 12];
264 buff
[i
+ 4] = (val
<< 1) | (val
>> 31);
266 val
= buff
[i
+ 2] ^ buff
[i
- 3] ^ buff
[i
- 9] ^ buff
[i
- 11];
267 buff
[i
+ 5] = (val
<< 1) | (val
>> 31);
269 val
= buff
[i
+ 3] ^ buff
[i
- 2] ^ buff
[i
- 8] ^ buff
[i
- 10];
270 buff
[i
+ 6] = (val
<< 1) | (val
>> 31);
272 val
= buff
[i
+ 4] ^ buff
[i
- 1] ^ buff
[i
- 7] ^ buff
[i
- 9];
273 buff
[i
+ 7] = (val
<< 1) | (val
>> 31);
277 private void ProcessFinalBlock (byte[] inputBuffer
, int inputOffset
, int inputCount
)
279 ulong total
= count
+ (ulong)inputCount
;
280 int paddingSize
= (56 - (int)(total
% BLOCK_SIZE_BYTES
));
283 paddingSize
+= BLOCK_SIZE_BYTES
;
285 int length
= inputCount
+paddingSize
+8;
286 byte[] fooBuffer
= (length
== 64) ? _ProcessingBuffer
: new byte[length
];
288 for (int i
=0; i
<inputCount
; i
++) {
289 fooBuffer
[i
] = inputBuffer
[i
+inputOffset
];
292 fooBuffer
[inputCount
] = 0x80;
293 for (int i
=inputCount
+1; i
<inputCount
+paddingSize
; i
++) {
297 // I deal in bytes. The algorithm deals in bits.
298 ulong size
= total
<< 3;
299 AddLength (size
, fooBuffer
, inputCount
+paddingSize
);
300 ProcessBlock (fooBuffer
, 0);
303 ProcessBlock (fooBuffer
, 64);
306 internal void AddLength (ulong length
, byte[] buffer
, int position
)
308 buffer
[position
++] = (byte)(length
>> 56);
309 buffer
[position
++] = (byte)(length
>> 48);
310 buffer
[position
++] = (byte)(length
>> 40);
311 buffer
[position
++] = (byte)(length
>> 32);
312 buffer
[position
++] = (byte)(length
>> 24);
313 buffer
[position
++] = (byte)(length
>> 16);
314 buffer
[position
++] = (byte)(length
>> 8);
315 buffer
[position
] = (byte)(length
);
322 public sealed class SHA1CryptoServiceProvider
: SHA1
{
324 private SHA1Internal sha
;
326 public SHA1CryptoServiceProvider ()
328 sha
= new SHA1Internal ();
331 ~
SHA1CryptoServiceProvider ()
336 protected override void Dispose (bool disposing
)
338 // nothing new to do (managed implementation)
339 base.Dispose (disposing
);
342 protected override void HashCore (byte[] rgb
, int ibStart
, int cbSize
)
345 sha
.HashCore (rgb
, ibStart
, cbSize
);
348 protected override byte[] HashFinal ()
351 return sha
.HashFinal ();
354 public override void Initialize ()