浅谈OAuth2.0认证
现在的网站越来越多的用到第三方登陆,现在提供第三方登陆api接口的网站包括新浪微博,腾讯,网易,开心,人人但是就本人的观点来看里面最安全的第三方应该说是人人提供的接口了,因为本人在调用人人提供的api接口时费了很大的劲,因为他需要签名认证
但是使用OAuth2.0的标准是都一样的
1、通过OAuth2/authorize接口获取code
2、通过OAuth2/access_token获取accesstoken,因为有些api中都含有唯一确定用户的信息包括uid,因为每次调用其他的接口时还要需要到access_token,所以access_token是非常重要的,但是他有过期时间一般10到15天,有的接口中有freshtoken
上面一般接口调用都非常简单下面来贴段人人获取签名认证的代码,来帮助有需要的人使用
View Code
1 public class GetSig 2 { 3 #region 加密编码 4 // MD5 加密 5 public static string MD5Encrpt(string plainText) 6 { 7 return MD5CryptoServiceProvider.GetMd5String(plainText); 8 } 9 10 // utf-8编码 11 public static string Utf8Encode(string plainText) 12 { 13 if (plainText == null) plainText = " "; 14 byte[] b = System.Text.Encoding.UTF8.GetBytes(plainText); 15 string retString = System.Text.Encoding.UTF8.GetString(b, 0, b.Length); 16 return retString; 17 } 18 #endregion 19 #region 计算sig签名的方法 20 /// <summary> 21 /// 计算签名 22 /// 此方法传入的是所有签名需要的参数 23 /// </summary> 24 /// <param name="paras">传入需要的参数</param> 25 /// <returns></returns> 26 public static string CalSig(List<APIParameter> paras) 27 { 28 //List<APIParameter> paras = new List<APIParameter>(); 29 //paras.Add(new APIParameter("v", "1.0")); 30 //paras.Add(new APIParameter("api_key", "ec9e57913c5b42b282ab7b743559e1b0")); 31 //paras.Add(new APIParameter("method", "users.getLoggedInUser")); 32 //paras.Add(new APIParameter("call_id", "1232095295656")); 33 //paras.Add(new APIParameter("session_key", "L6Xe8dXVGISZ17LJy7GzZaeYGpeGfeNdqEPLNUtCJfxPCxCRLWT83x+s/Ur94PqP-700001044")); 34 paras.Sort(new ParameterComparer()); 35 StringBuilder sbList = new StringBuilder(); 36 foreach (APIParameter para in paras) 37 { 38 sbList.AppendFormat("{0}={1}", para.Name, para.Value); 39 } 40 var appSettings = new AppSettings(); 41 var AppSecret = appSettings.GetString("renren.AppSecret"); 42 sbList.Append(AppSecret); 43 string a = MD5Encrpt(sbList.ToString()); 44 return a; 45 } 46 47 /// <summary> 48 /// 不区分大小写,获得querysring中的值 49 /// </summary> 50 /// <param name="url"></param> 51 /// <param name="key"></param> 52 /// <returns></returns> 53 public static string GetQueryString(Uri url, string key) 54 { 55 string retVal = ""; 56 string query = ""; 57 string abUrl = url.Fragment; 58 59 if (abUrl != "") 60 { 61 abUrl = Uri.UnescapeDataString(abUrl); 62 query = abUrl.Replace("#", ""); 63 } 64 else 65 { 66 abUrl = url.AbsoluteUri; 67 abUrl = Uri.UnescapeDataString(abUrl); 68 query = abUrl.Substring(abUrl.IndexOf("?") + 1); 69 query = query.Replace("?", ""); 70 } 71 72 string[] querys = query.Split('&'); 73 foreach (string qu in querys) 74 { 75 string[] vals = qu.Split('='); 76 if (vals[0].ToString().ToLower() == key.ToLower()) 77 { 78 retVal = vals[1].ToString(); 79 break; 80 } 81 } 82 return retVal; 83 } 84 85 #endregion 86 87 } 88 public class APIParameter 89 { 90 private string name = null; 91 private string value = null; 92 93 public APIParameter(string name, string value) 94 { 95 this.name = name; 96 this.value = value; 97 } 98 99 public string Name 100 { 101 get { return name; } 102 } 103 104 public string Value 105 { 106 get { return value; } 107 } 108 } 109 110 /// <summary> 111 /// Comparer class used to perform the sorting of the query parameters 112 /// </summary> 113 public class ParameterComparer : IComparer<APIParameter> 114 { 115 public int Compare(APIParameter x, APIParameter y) 116 { 117 if (x.Name == y.Name) 118 { 119 return string.Compare(x.Value, y.Value); 120 } 121 else 122 { 123 return string.Compare(x.Name, y.Name); 124 } 125 } 126 } 127 128 129 public class MD5CryptoServiceProvider : MD5 130 { 131 public MD5CryptoServiceProvider() 132 : base() 133 { 134 } 135 } 136 /// <summary> 137 /// Summary description for MD5. 138 /// </summary> 139 public class MD5 : IDisposable 140 { 141 static public MD5 Create(string hashName) 142 { 143 if (hashName == "MD5") 144 return new MD5(); 145 else 146 throw new NotSupportedException(); 147 } 148 149 static public String GetMd5String(String source) 150 { 151 MD5 md = MD5CryptoServiceProvider.Create(); 152 byte[] hash; 153 154 //Create a new instance of ASCIIEncoding to 155 //convert the string into an array of Unicode bytes. 156 UTF8Encoding enc = new UTF8Encoding(); 157 // ASCIIEncoding enc = new ASCIIEncoding(); 158 159 //Convert the string into an array of bytes. 160 byte[] buffer = enc.GetBytes(source); 161 162 //Create the hash value from the array of bytes. 163 hash = md.ComputeHash(buffer); 164 165 StringBuilder sb = new StringBuilder(); 166 foreach (byte b in hash) 167 sb.Append(b.ToString("x2")); 168 return sb.ToString(); 169 } 170 171 static public MD5 Create() 172 { 173 return new MD5(); 174 } 175 176 #region base implementation of the MD5 177 #region constants 178 private const byte S11 = 7; 179 private const byte S12 = 12; 180 private const byte S13 = 17; 181 private const byte S14 = 22; 182 private const byte S21 = 5; 183 private const byte S22 = 9; 184 private const byte S23 = 14; 185 private const byte S24 = 20; 186 private const byte S31 = 4; 187 private const byte S32 = 11; 188 private const byte S33 = 16; 189 private const byte S34 = 23; 190 private const byte S41 = 6; 191 private const byte S42 = 10; 192 private const byte S43 = 15; 193 private const byte S44 = 21; 194 static private byte[] PADDING = new byte[] { 195 0x80, 0, 0, 0, 0, 0, 196 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 197 0, 0, 0, 0, 0, 0, 0, 198 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 199 0, 0, 0, 0, 0, 0, 0, 200 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 201 }; 202 #endregion 203 204 #region F, G, H and I are basic MD5 functions. 205 static private uint F(uint x, uint y, uint z) 206 { 207 return (((x) & (y)) | ((~x) & (z))); 208 } 209 static private uint G(uint x, uint y, uint z) 210 { 211 return (((x) & (z)) | ((y) & (~z))); 212 } 213 static private uint H(uint x, uint y, uint z) 214 { 215 return ((x) ^ (y) ^ (z)); 216 } 217 static private uint I(uint x, uint y, uint z) 218 { 219 return ((y) ^ ((x) | (~z))); 220 } 221 #endregion 222 223 #region rotates x left n bits. 224 /// <summary> 225 /// rotates x left n bits. 226 /// </summary> 227 /// <param name="x"></param> 228 /// <param name="n"></param> 229 /// <returns></returns> 230 static private uint ROTATE_LEFT(uint x, byte n) 231 { 232 return (((x) << (n)) | ((x) >> (32 - (n)))); 233 } 234 #endregion 235 236 #region FF, GG, HH, and II transformations 237 /// FF, GG, HH, and II transformations 238 /// for rounds 1, 2, 3, and 4. 239 /// Rotation is separate from addition to prevent recomputation. 240 static private void FF(ref uint a, uint b, uint c, uint d, uint x, byte s, uint ac) 241 { 242 (a) += F((b), (c), (d)) + (x) + (uint)(ac); 243 (a) = ROTATE_LEFT((a), (s)); 244 (a) += (b); 245 } 246 static private void GG(ref uint a, uint b, uint c, uint d, uint x, byte s, uint ac) 247 { 248 (a) += G((b), (c), (d)) + (x) + (uint)(ac); 249 (a) = ROTATE_LEFT((a), (s)); 250 (a) += (b); 251 } 252 static private void HH(ref uint a, uint b, uint c, uint d, uint x, byte s, uint ac) 253 { 254 (a) += H((b), (c), (d)) + (x) + (uint)(ac); 255 (a) = ROTATE_LEFT((a), (s)); 256 (a) += (b); 257 } 258 static private void II(ref uint a, uint b, uint c, uint d, uint x, byte s, uint ac) 259 { 260 (a) += I((b), (c), (d)) + (x) + (uint)(ac); 261 (a) = ROTATE_LEFT((a), (s)); 262 (a) += (b); 263 } 264 #endregion 265 266 #region context info 267 /// <summary> 268 /// state (ABCD) 269 /// </summary> 270 uint[] state = new uint[4]; 271 272 /// <summary> 273 /// number of bits, modulo 2^64 (lsb first) 274 /// </summary> 275 uint[] count = new uint[2]; 276 277 /// <summary> 278 /// input buffer 279 /// </summary> 280 byte[] buffer = new byte[64]; 281 #endregion 282 283 internal MD5() 284 { 285 Initialize(); 286 } 287 288 /// <summary> 289 /// MD5 initialization. Begins an MD5 operation, writing a new context. 290 /// </summary> 291 /// <remarks> 292 /// The RFC named it "MD5Init" 293 /// </remarks> 294 public virtual void Initialize() 295 { 296 count[0] = count[1] = 0; 297 298 // Load magic initialization constants. 299 state[0] = 0x67452301; 300 state[1] = 0xefcdab89; 301 state[2] = 0x98badcfe; 302 state[3] = 0x10325476; 303 } 304 305 /// <summary> 306 /// MD5 block update operation. Continues an MD5 message-digest 307 /// operation, processing another message block, and updating the 308 /// context. 309 /// </summary> 310 /// <param name="input"></param> 311 /// <param name="offset"></param> 312 /// <param name="count"></param> 313 /// <remarks>The RFC Named it MD5Update</remarks> 314 protected virtual void HashCore(byte[] input, int offset, int count) 315 { 316 int i; 317 int index; 318 int partLen; 319 320 // Compute number of bytes mod 64 321 index = (int)((this.count[0] >> 3) & 0x3F); 322 323 // Update number of bits 324 if ((this.count[0] += (uint)((uint)count << 3)) < ((uint)count << 3)) 325 this.count[1]++; 326 this.count[1] += ((uint)count >> 29); 327 328 partLen = 64 - index; 329 330 // Transform as many times as possible. 331 if (count >= partLen) 332 { 333 Buffer.BlockCopy(input, offset, this.buffer, index, partLen); 334 Transform(this.buffer, 0); 335 336 for (i = partLen; i + 63 < count; i += 64) 337 Transform(input, offset + i); 338 339 index = 0; 340 } 341 else 342 i = 0; 343 344 // Buffer remaining input 345 Buffer.BlockCopy(input, offset + i, this.buffer, index, count - i); 346 } 347 348 /// <summary> 349 /// MD5 finalization. Ends an MD5 message-digest operation, writing the 350 /// the message digest and zeroizing the context. 351 /// </summary> 352 /// <returns>message digest</returns> 353 /// <remarks>The RFC named it MD5Final</remarks> 354 protected virtual byte[] HashFinal() 355 { 356 byte[] digest = new byte[16]; 357 byte[] bits = new byte[8]; 358 int index, padLen; 359 360 // Save number of bits 361 Encode(bits, 0, this.count, 0, 8); 362 363 // Pad out to 56 mod 64. 364 index = (int)((uint)(this.count[0] >> 3) & 0x3f); 365 padLen = (index < 56) ? (56 - index) : (120 - index); 366 HashCore(PADDING, 0, padLen); 367 368 // Append length (before padding) 369 HashCore(bits, 0, 8); 370 371 // Store state in digest 372 Encode(digest, 0, state, 0, 16); 373 374 // Zeroize sensitive information. 375 count[0] = count[1] = 0; 376 state[0] = 0; 377 state[1] = 0; 378 state[2] = 0; 379 state[3] = 0; 380 381 // initialize again, to be ready to use 382 Initialize(); 383 384 return digest; 385 } 386 387 /// <summary> 388 /// MD5 basic transformation. Transforms state based on 64 bytes block. 389 /// </summary> 390 /// <param name="block"></param> 391 /// <param name="offset"></param> 392 private void Transform(byte[] block, int offset) 393 { 394 uint a = state[0], b = state[1], c = state[2], d = state[3]; 395 uint[] x = new uint[16]; 396 Decode(x, 0, block, offset, 64); 397 398 // Round 1 399 FF(ref a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ 400 FF(ref d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ 401 FF(ref c, d, a, b, x[2], S13, 0x242070db); /* 3 */ 402 FF(ref b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ 403 FF(ref a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ 404 FF(ref d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ 405 FF(ref c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ 406 FF(ref b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ 407 FF(ref a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ 408 FF(ref d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ 409 FF(ref c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ 410 FF(ref b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ 411 FF(ref a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ 412 FF(ref d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ 413 FF(ref c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ 414 FF(ref b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ 415 416 // Round 2 417 GG(ref a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ 418 GG(ref d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ 419 GG(ref c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ 420 GG(ref b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ 421 GG(ref a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ 422 GG(ref d, a, b, c, x[10], S22, 0x2441453); /* 22 */ 423 GG(ref c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ 424 GG(ref b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ 425 GG(ref a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ 426 GG(ref d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ 427 GG(ref c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ 428 GG(ref b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ 429 GG(ref a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ 430 GG(ref d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ 431 GG(ref c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ 432 GG(ref b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ 433 434 // Round 3 435 HH(ref a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ 436 HH(ref d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ 437 HH(ref c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ 438 HH(ref b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ 439 HH(ref a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ 440 HH(ref d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ 441 HH(ref c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ 442 HH(ref b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ 443 HH(ref a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ 444 HH(ref d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ 445 HH(ref c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ 446 HH(ref b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ 447 HH(ref a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ 448 HH(ref d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ 449 HH(ref c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ 450 HH(ref b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ 451 452 // Round 4 453 II(ref a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ 454 II(ref d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ 455 II(ref c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ 456 II(ref b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ 457 II(ref a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ 458 II(ref d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ 459 II(ref c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ 460 II(ref b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ 461 II(ref a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ 462 II(ref d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ 463 II(ref c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ 464 II(ref b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ 465 II(ref a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ 466 II(ref d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ 467 II(ref c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ 468 II(ref b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ 469 470 state[0] += a; 471 state[1] += b; 472 state[2] += c; 473 state[3] += d; 474 475 // Zeroize sensitive information. 476 for (int i = 0; i < x.Length; i++) 477 x[i] = 0; 478 } 479 480 /// <summary> 481 /// Encodes input (uint) into output (byte). Assumes len is 482 /// multiple of 4. 483 /// </summary> 484 /// <param name="output"></param> 485 /// <param name="outputOffset"></param> 486 /// <param name="input"></param> 487 /// <param name="inputOffset"></param> 488 /// <param name="count"></param> 489 private static void Encode(byte[] output, int outputOffset, uint[] input, int inputOffset, int count) 490 { 491 int i, j; 492 int end = outputOffset + count; 493 for (i = inputOffset, j = outputOffset; j < end; i++, j += 4) 494 { 495 output[j] = (byte)(input[i] & 0xff); 496 output[j + 1] = (byte)((input[i] >> 8) & 0xff); 497 output[j + 2] = (byte)((input[i] >> 16) & 0xff); 498 output[j + 3] = (byte)((input[i] >> 24) & 0xff); 499 } 500 } 501 502 /// <summary> 503 /// Decodes input (byte) into output (uint). Assumes len is 504 /// a multiple of 4. 505 /// </summary> 506 /// <param name="output"></param> 507 /// <param name="outputOffset"></param> 508 /// <param name="input"></param> 509 /// <param name="inputOffset"></param> 510 /// <param name="count"></param> 511 static private void Decode(uint[] output, int outputOffset, byte[] input, int inputOffset, int count) 512 { 513 int i, j; 514 int end = inputOffset + count; 515 for (i = outputOffset, j = inputOffset; j < end; i++, j += 4) 516 output[i] = ((uint)input[j]) | (((uint)input[j + 1]) << 8) | (((uint)input[j + 2]) << 16) | (((uint)input[j + 3]) << 517 24); 518 } 519 #endregion 520 521 #region expose the same interface as the regular MD5 object 522 523 protected byte[] HashValue; 524 protected int State; 525 public virtual bool CanReuseTransform 526 { 527 get 528 { 529 return true; 530 } 531 } 532 533 public virtual bool CanTransformMultipleBlocks 534 { 535 get 536 { 537 return true; 538 } 539 } 540 public virtual byte[] Hash 541 { 542 get 543 { 544 if (this.State != 0) 545 throw new InvalidOperationException(); 546 return (byte[])HashValue.Clone(); 547 } 548 } 549 public virtual int HashSize 550 { 551 get 552 { 553 return HashSizeValue; 554 } 555 } 556 protected int HashSizeValue = 128; 557 558 public virtual int InputBlockSize 559 { 560 get 561 { 562 return 1; 563 } 564 } 565 public virtual int OutputBlockSize 566 { 567 get 568 { 569 return 1; 570 } 571 } 572 573 public void Clear() 574 { 575 Dispose(true); 576 } 577 578 public byte[] ComputeHash(byte[] buffer) 579 { 580 return ComputeHash(buffer, 0, buffer.Length); 581 } 582 public byte[] ComputeHash(byte[] buffer, int offset, int count) 583 { 584 Initialize(); 585 HashCore(buffer, offset, count); 586 HashValue = HashFinal(); 587 return (byte[])HashValue.Clone(); 588 } 589 590 public byte[] ComputeHash(Stream inputStream) 591 { 592 Initialize(); 593 int count = 0; 594 byte[] buffer = new byte[4096]; 595 while (0 < (count = inputStream.Read(buffer, 0, 4096))) 596 { 597 HashCore(buffer, 0, count); 598 } 599 HashValue = HashFinal(); 600 return (byte[])HashValue.Clone(); 601 } 602 603 public int TransformBlock( 604 byte[] inputBuffer, 605 int inputOffset, 606 int inputCount, 607 byte[] outputBuffer, 608 int outputOffset 609 ) 610 { 611 if (inputBuffer == null) 612 { 613 throw new ArgumentNullException("inputBuffer"); 614 } 615 if (inputOffset < 0) 616 { 617 throw new ArgumentOutOfRangeException("inputOffset"); 618 } 619 if ((inputCount < 0) || (inputCount > inputBuffer.Length)) 620 { 621 throw new ArgumentException("inputCount"); 622 } 623 if ((inputBuffer.Length - inputCount) < inputOffset) 624 { 625 throw new ArgumentOutOfRangeException("inputOffset"); 626 } 627 if (this.State == 0) 628 { 629 Initialize(); 630 this.State = 1; 631 } 632 633 HashCore(inputBuffer, inputOffset, inputCount); 634 if ((inputBuffer != outputBuffer) || (inputOffset != outputOffset)) 635 { 636 Buffer.BlockCopy(inputBuffer, inputOffset, outputBuffer, outputOffset, inputCount); 637 } 638 return inputCount; 639 } 640 public byte[] TransformFinalBlock( 641 byte[] inputBuffer, 642 int inputOffset, 643 int inputCount 644 ) 645 { 646 if (inputBuffer == null) 647 { 648 throw new ArgumentNullException("inputBuffer"); 649 } 650 if (inputOffset < 0) 651 { 652 throw new ArgumentOutOfRangeException("inputOffset"); 653 } 654 if ((inputCount < 0) || (inputCount > inputBuffer.Length)) 655 { 656 throw new ArgumentException("inputCount"); 657 } 658 if ((inputBuffer.Length - inputCount) < inputOffset) 659 { 660 throw new ArgumentOutOfRangeException("inputOffset"); 661 } 662 if (this.State == 0) 663 { 664 Initialize(); 665 } 666 HashCore(inputBuffer, inputOffset, inputCount); 667 HashValue = HashFinal(); 668 byte[] buffer = new byte[inputCount]; 669 Buffer.BlockCopy(inputBuffer, inputOffset, buffer, 0, inputCount); 670 this.State = 0; 671 return buffer; 672 } 673 #endregion 674 675 protected virtual void Dispose(bool disposing) 676 { 677 if (!disposing) 678 Initialize(); 679 } 680 public void Dispose() 681 { 682 Dispose(true); 683 } 684 }