现在的位置: 首页 > 综合 > 正文

MD5加密及HMAC-MD5加密(VC源代码)

2018年04月06日 ⁄ 综合 ⁄ 共 13747字 ⁄ 字号 评论关闭

开发语言:C/C++

实现功能:

  • MD5加密及HMAC-MD5加密

下载地址:

HMAC-MD5.zip

更新历史:

V1.1 2010年05月08日

  • 增加输出BASE64编码字符串接口。

V1.0 2010年04月15日

  • 完成正式版本。

接口函数:

MD5_Hash

HMAC_MD5_Hash

MD5_BASE64

HMAC_MD5_BASE64

源文件:

HMAC_MD5_API.h

  1. /* ---------------------------------------------------------- 
  2. 文件名称:HMAC_MD5_API.h 
  3.  
  4. 作者:秦建辉 
  5.  
  6. MSN:splashcn@msn.com 
  7.  
  8. 当前版本:V1.1 
  9.  
  10. 历史版本: 
  11.     V1.1    2010年05月08日 
  12.             增加输出BASE64编码字符串接口。 
  13.  
  14.     V1.0    2010年04月15日 
  15.             完成正式版本。 
  16.  
  17. 功能描述: 
  18.     MD5和HMAC-MD5加密 
  19.  
  20. 接口函数: 
  21.     MD5_Hash 
  22.     HMAC_MD5_Hash 
  23.     MD5_BASE64 
  24.     HMAC_MD5_BASE64 
  25.  ------------------------------------------------------------ */  
  26. #pragma once  
  27.   
  28. #include <windows.h>  
  29.   
  30. //-------------------导出函数-------------  
  31. #ifdef __cplusplus  
  32. extern "C"{  
  33. #endif  
  34.   
  35. /* 
  36. 功能:计算输入数据的MD5哈希值 
  37. 入口参数: 
  38.     inputBuffer:输入数据 
  39.     inputCount:输入数据长度(字节数) 
  40.     outputBuffer:输入数据的哈希值 
  41. 返回值: 
  42.     哈希值的有效长度(字节数) 
  43. */  
  44. INT MD5_Hash( const BYTE* inputBuffer, UINT inputCount, BYTE* outputBuffer );  
  45.   
  46. /* 
  47. 功能:计算输入数据的HMAC-MD5哈希值 
  48. 入口参数: 
  49.     inputBuffer:输入数据 
  50.     inputCount:输入数据长度(字节数) 
  51.     userKey:用户密钥 
  52.     UserKeyLen:用户密钥长度 
  53.     outputBuffer:输入数据的哈希值 
  54. 返回值: 
  55.     哈希值的有效长度(字节数) 
  56. */  
  57. INT HMAC_MD5_Hash( const BYTE* inputBuffer, UINT inputCount, const BYTE* userKey, UINT UserKeyLen, BYTE* outputBuffer );  
  58.   
  59. /* 
  60. 功能:计算输入数据的MD5哈希值,并转换为BASE64编码字符串输出。 
  61. 入口参数: 
  62.     inputBuffer:输入数据 
  63.     inputCount:输入数据长度(字节数) 
  64.     outputBuffer:MD5哈希值的BASE64编码字符串 
  65. 返回值: 
  66.     BASE64编码字符串长度(字符数),不包括字符串结束符 
  67. */  
  68. INT MD5_BASE64( const BYTE* inputBuffer, UINT inputCount, TCHAR* outputBuffer );  
  69.   
  70. /* 
  71. 功能:计算输入数据的HMAC-MD5哈希值,并转换为BASE64编码字符串输出。 
  72. 入口参数: 
  73.     inputBuffer:输入数据 
  74.     inputCount:输入数据长度(字节数) 
  75.     userKey:用户密钥 
  76.     UserKeyLen:用户密钥长度 
  77.     outputBuffer:HMAC-MD5哈希值的BASE64编码字符串 
  78. 返回值: 
  79.     BASE64编码字符串长度(字符数),不包括字符串结束符 
  80. */  
  81. INT HMAC_MD5_BASE64( const BYTE* inputBuffer, UINT inputCount, const BYTE* userKey, UINT UserKeyLen, TCHAR* outputBuffer );  
  82.   
  83. #ifdef __cplusplus  
  84. }  
  85. #endif  

HMAC_MD5_DATA.h:

  1. #pragma once  
  2.   
  3. typedef struct  
  4. {  
  5.     DWORD   p[4];  
  6.     DWORD   q[4][16];  
  7. } TYPE_MD5DATA;  
  8.   
  9. /* ------------------------------------------------ 
  10.          MD5关键参数,修改即可形成不同的变体 
  11.    ------------------------------------------------ */  
  12. const TYPE_MD5DATA MD5_ARGUMENTS = {  
  13.     // 初始状态  
  14.     {0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476},  
  15.   
  16.     // 变换操作偏移量表  
  17.     {0xD76AA478,0xE8C7B756,0x242070DB,0xC1BDCEEE,  
  18.      0xF57C0FAF,0x4787C62A,0xA8304613,0xFD469501,  
  19.      0x698098D8,0x8B44F7AF,0xFFFF5BB1,0x895CD7BE,  
  20.      0x6B901122,0xFD987193,0xA679438E,0x49B40821,  
  21.   
  22.      0xF61E2562,0xC040B340,0x265E5A51,0xE9B6C7AA,  
  23.      0xD62F105D,0x02441453,0xD8A1E681,0xE7D3FBC8,  
  24.      0x21E1CDE6,0xC33707D6,0xF4D50D87,0x455A14ED,  
  25.      0xA9E3E905,0xFCEFA3F8,0x676F02D9,0x8D2A4C8A,  
  26.   
  27.      0xFFFA3942,0x8771F681,0x6D9D6122,0xFDE5380C,  
  28.      0xA4BEEA44,0x4BDECFA9,0xF6BB4B60,0xBEBFBC70,  
  29.      0x289B7EC6,0xEAA127FA,0xD4EF3085,0x04881D05,  
  30.      0xD9D4D039,0xE6DB99E5,0x1FA27CF8,0xC4AC5665,  
  31.   
  32.      0xF4292244,0x432AFF97,0xAB9423A7,0xFC93A039,  
  33.      0x655B59C3,0x8F0CCC92,0xFFEFF47D,0x85845DD1,  
  34.      0x6FA87E4F,0xFE2CE6E0,0xA3014314,0x4E0811A1,  
  35.      0xF7537E82,0xBD3AF235,0x2AD7D2BB,0xEB86D391}  
  36. };  
  37.   
  38. // 变换操作移位表  
  39. const BYTE MDShiftTable[][4] = {{7,12,17,22},{5,9,14,20},{4,11,16,23},{6,10,15,21}};  
  40.   
  41. // 填充数据  
  42. const BYTE MDPadding[] = {  
  43.     0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  
  44.        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  
  45.        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  
  46.        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  
  47. };  
  48.   
  49. // MD5基本位操作函数  
  50. #define F(x, y, z)  (((x) & (y)) | ((~x) & (z)))  
  51. #define G(x, y, z)  (((x) & (z)) | ((y) & (~z)))  
  52. #define H(x, y, z)  ((x) ^ (y) ^ (z))  
  53. #define I(x, y, z)  ((y) ^ ((x) | (~z)))  
  54.   
  55. // 位循环左移位操作  
  56. #define ROL(x, n)   (((x) << (n)) | ((x) >> (32-(n))))  
  57.   
  58. // ---------变换操作----------  
  59. // 第一轮变换基本操作  
  60. #define FF(a, b, c, d, x, s, t) { /  
  61.     (a) += F((b), (c), (d)) + (x) + (t); /  
  62.     (a) = ROL((a), (s)); /  
  63.     (a) += (b); /  
  64. }  
  65.   
  66. // 第二轮变换基本操作  
  67. #define GG(a, b, c, d, x, s, t) { /  
  68.     (a) += G((b), (c), (d)) + (x) + (t); /  
  69.     (a) = ROL((a), (s)); /  
  70.     (a) += (b); /  
  71. }  
  72.   
  73. // 第三轮变换基本操作  
  74. #define HH(a, b, c, d, x, s, t) { /  
  75.     (a) += H((b), (c), (d)) + (x) + (t); /  
  76.     (a) = ROL((a), (s)); /  
  77.     (a) += (b); /  
  78. }  
  79.   
  80. // 第四轮变换基本操作  
  81. #define II(a, b, c, d, x, s, t) { /  
  82.     (a) += I((b), (c), (d)) + (x) + (t); /  
  83.     (a) = ROL((a), (s)); /  
  84.     (a) += (b); /  
  85. }  

HMAC_MD5_API.cpp:

  1. #include "HMAC_MD5_API.h"  
  2. #include "HMAC_MD5_DATA.h"  
  3. #include "..//BASE64//BASE64_API.h"  
  4.   
  5. // 定义数据结构  
  6. typedef struct _MD5CTX {  
  7.     DWORD   aState[4];      // 记录数据的变化状态  
  8.     DWORD   aCount[2];      // 记录数据的原始长度(以bit为单位)  
  9.     BYTE    aBuffer[64];    // 原始数据  
  10. } MD5CTX;  
  11.   
  12. // 初始化  
  13. void MD5_Init( MD5CTX* pstruContext )  
  14. {  
  15.     const DWORD *MDOriginState;  
  16.   
  17.     MDOriginState = MD5_ARGUMENTS.p;  
  18.     pstruContext->aState[0] = MDOriginState[0];  
  19.     pstruContext->aState[1] = MDOriginState[1];  
  20.     pstruContext->aState[2] = MDOriginState[2];  
  21.     pstruContext->aState[3] = MDOriginState[3];  
  22.     pstruContext->aCount[0] = pstruContext->aCount[1] = 0;  
  23. }  
  24.   
  25. // MD5基本变换操作  
  26. void MD5_Transform( DWORD* pState, DWORD* px )  
  27. {  
  28.     const DWORD (*MDOffTable)[16];  
  29.     DWORD a,b,c,d;  
  30.   
  31.     MDOffTable = MD5_ARGUMENTS.q;  
  32.     a = pState[0], b = pState[1], c = pState[2], d = pState[3];  
  33.   
  34.     // 第一轮变换  
  35.     FF(a, b, c, d, px[ 0], MDShiftTable[0][0], MDOffTable[0][ 0]);  
  36.     FF(d, a, b, c, px[ 1], MDShiftTable[0][1], MDOffTable[0][ 1]);  
  37.     FF(c, d, a, b, px[ 2], MDShiftTable[0][2], MDOffTable[0][ 2]);  
  38.     FF(b, c, d, a, px[ 3], MDShiftTable[0][3], MDOffTable[0][ 3]);  
  39.     FF(a, b, c, d, px[ 4], MDShiftTable[0][0], MDOffTable[0][ 4]);  
  40.     FF(d, a, b, c, px[ 5], MDShiftTable[0][1], MDOffTable[0][ 5]);  
  41.     FF(c, d, a, b, px[ 6], MDShiftTable[0][2], MDOffTable[0][ 6]);  
  42.     FF(b, c, d, a, px[ 7], MDShiftTable[0][3], MDOffTable[0][ 7]);  
  43.     FF(a, b, c, d, px[ 8], MDShiftTable[0][0], MDOffTable[0][ 8]);  
  44.     FF(d, a, b, c, px[ 9], MDShiftTable[0][1], MDOffTable[0][ 9]);  
  45.     FF(c, d, a, b, px[10], MDShiftTable[0][2], MDOffTable[0][10]);  
  46.     FF(b, c, d, a, px[11], MDShiftTable[0][3], MDOffTable[0][11]);  
  47.     FF(a, b, c, d, px[12], MDShiftTable[0][0], MDOffTable[0][12]);  
  48.     FF(d, a, b, c, px[13], MDShiftTable[0][1], MDOffTable[0][13]);  
  49.     FF(c, d, a, b, px[14], MDShiftTable[0][2], MDOffTable[0][14]);  
  50.     FF(b, c, d, a, px[15], MDShiftTable[0][3], MDOffTable[0][15]);  
  51.   
  52.     // 第二轮变换  
  53.     GG(a, b, c, d, px[ 1], MDShiftTable[1][0], MDOffTable[1][ 0]);  
  54.     GG(d, a, b, c, px[ 6], MDShiftTable[1][1], MDOffTable[1][ 1]);  
  55.     GG(c, d, a, b, px[11], MDShiftTable[1][2], MDOffTable[1][ 2]);  
  56.     GG(b, c, d, a, px[ 0], MDShiftTable[1][3], MDOffTable[1][ 3]);  
  57.     GG(a, b, c, d, px[ 5], MDShiftTable[1][0], MDOffTable[1][ 4]);  
  58.     GG(d, a, b, c, px[10], MDShiftTable[1][1], MDOffTable[1][ 5]);  
  59.     GG(c, d, a, b, px[15], MDShiftTable[1][2], MDOffTable[1][ 6]);  
  60.     GG(b, c, d, a, px[ 4], MDShiftTable[1][3], MDOffTable[1][ 7]);  
  61.     GG(a, b, c, d, px[ 9], MDShiftTable[1][0], MDOffTable[1][ 8]);  
  62.     GG(d, a, b, c, px[14], MDShiftTable[1][1], MDOffTable[1][ 9]);  
  63.     GG(c, d, a, b, px[ 3], MDShiftTable[1][2], MDOffTable[1][10]);  
  64.     GG(b, c, d, a, px[ 8], MDShiftTable[1][3], MDOffTable[1][11]);  
  65.     GG(a, b, c, d, px[13], MDShiftTable[1][0], MDOffTable[1][12]);  
  66.     GG(d, a, b, c, px[ 2], MDShiftTable[1][1], MDOffTable[1][13]);  
  67.     GG(c, d, a, b, px[ 7], MDShiftTable[1][2], MDOffTable[1][14]);  
  68.     GG(b, c, d, a, px[12], MDShiftTable[1][3], MDOffTable[1][15]);  
  69.                           
  70.     // 第三轮变换      
  71.     HH(a, b, c, d, px[ 5], MDShiftTable[2][0], MDOffTable[2][ 0]);  
  72.     HH(d, a, b, c, px[ 8], MDShiftTable[2][1], MDOffTable[2][ 1]);  
  73.     HH(c, d, a, b, px[11], MDShiftTable[2][2], MDOffTable[2][ 2]);  
  74.     HH(b, c, d, a, px[14], MDShiftTable[2][3], MDOffTable[2][ 3]);  
  75.     HH(a, b, c, d, px[ 1], MDShiftTable[2][0], MDOffTable[2][ 4]);  
  76.     HH(d, a, b, c, px[ 4], MDShiftTable[2][1], MDOffTable[2][ 5]);  
  77.     HH(c, d, a, b, px[ 7], MDShiftTable[2][2], MDOffTable[2][ 6]);  
  78.     HH(b, c, d, a, px[10], MDShiftTable[2][3], MDOffTable[2][ 7]);  
  79.     HH(a, b, c, d, px[13], MDShiftTable[2][0], MDOffTable[2][ 8]);  
  80.     HH(d, a, b, c, px[ 0], MDShiftTable[2][1], MDOffTable[2][ 9]);  
  81.     HH(c, d, a, b, px[ 3], MDShiftTable[2][2], MDOffTable[2][10]);  
  82.     HH(b, c, d, a, px[ 6], MDShiftTable[2][3], MDOffTable[2][11]);  
  83.     HH(a, b, c, d, px[ 9], MDShiftTable[2][0], MDOffTable[2][12]);  
  84.     HH(d, a, b, c, px[12], MDShiftTable[2][1], MDOffTable[2][13]);  
  85.     HH(c, d, a, b, px[15], MDShiftTable[2][2], MDOffTable[2][14]);  
  86.     HH(b, c, d, a, px[ 2], MDShiftTable[2][3], MDOffTable[2][15]);  
  87.                           
  88.     // 第四轮变换      
  89.     II(a, b, c, d, px[ 0], MDShiftTable[3][0], MDOffTable[3][ 0]);  
  90.     II(d, a, b, c, px[ 7], MDShiftTable[3][1], MDOffTable[3][ 1]);  
  91.     II(c, d, a, b, px[14], MDShiftTable[3][2], MDOffTable[3][ 2]);  
  92.     II(b, c, d, a, px[ 5], MDShiftTable[3][3], MDOffTable[3][ 3]);  
  93.     II(a, b, c, d, px[12], MDShiftTable[3][0], MDOffTable[3][ 4]);  
  94.     II(d, a, b, c, px[ 3], MDShiftTable[3][1], MDOffTable[3][ 5]);  
  95.     II(c, d, a, b, px[10], MDShiftTable[3][2], MDOffTable[3][ 6]);  
  96.     II(b, c, d, a, px[ 1], MDShiftTable[3][3], MDOffTable[3][ 7]);  
  97.     II(a, b, c, d, px[ 8], MDShiftTable[3][0], MDOffTable[3][ 8]);  
  98.     II(d, a, b, c, px[15], MDShiftTable[3][1], MDOffTable[3][ 9]);  
  99.     II(c, d, a, b, px[ 6], MDShiftTable[3][2], MDOffTable[3][10]);  
  100.     II(b, c, d, a, px[13], MDShiftTable[3][3], MDOffTable[3][11]);  
  101.     II(a, b, c, d, px[ 4], MDShiftTable[3][0], MDOffTable[3][12]);  
  102.     II(d, a, b, c, px[11], MDShiftTable[3][1], MDOffTable[3][13]);  
  103.     II(c, d, a, b, px[ 2], MDShiftTable[3][2], MDOffTable[3][14]);  
  104.     II(b, c, d, a, px[ 9], MDShiftTable[3][3], MDOffTable[3][15]);    
  105.   
  106.     pState[0] += a;  
  107.     pState[1] += b;  
  108.     pState[2] += c;  
  109.     pState[3] += d;  
  110. }  
  111.   
  112. // MD5块更新操作  
  113. void MD5_Update( MD5CTX* pstruContext, const BYTE* pInput, DWORD dwInputLen )  
  114. {  
  115.     DWORD i, dwIndex, dwPartLen, dwBitsNum;  
  116.   
  117.     // 计算 mod 64 的字节数  
  118.     dwIndex = (pstruContext->aCount[0] >> 3) & 0x3F;  
  119.   
  120.     // 更新数据位数  
  121.     dwBitsNum = dwInputLen << 3;  
  122.     pstruContext->aCount[0] += dwBitsNum;  
  123.       
  124.     if(pstruContext->aCount[0] < dwBitsNum)  
  125.     {  
  126.         pstruContext->aCount[1]++;  
  127.     }  
  128.   
  129.     pstruContext->aCount[1] += dwInputLen >> 29;  
  130.   
  131.     dwPartLen = 64 - dwIndex;  
  132.     if(dwInputLen >= dwPartLen)  
  133.     {  
  134.         memcpy( pstruContext->aBuffer+dwIndex, pInput, dwPartLen );  
  135.         MD5_Transform( pstruContext->aState, (DWORD*)pstruContext->aBuffer );  
  136.   
  137.         for(i = dwPartLen; i + 63 < dwInputLen; i += 64 )  
  138.         {  
  139.             MD5_Transform( pstruContext->aState, (DWORD*)(pInput + i) );  
  140.         }  
  141.   
  142.         dwIndex = 0;  
  143.     }  
  144.     else  
  145.     {  
  146.         i = 0;  
  147.     }  
  148.   
  149.     memcpy( pstruContext->aBuffer + dwIndex, pInput + i, dwInputLen - i );  
  150. }  
  151.   
  152. // 处理最后的数据块  
  153. void MD5_Final( MD5CTX* pstruContext )  
  154. {  
  155.     DWORD dwIndex, dwPadLen;  
  156.     BYTE pBits[8];  
  157.       
  158.     memcpy( pBits, pstruContext->aCount, 8 );  
  159.       
  160.     // 计算 mod 64 的字节数  
  161.     dwIndex = (pstruContext->aCount[0] >> 3) & 0x3F;  
  162.   
  163.     // 使长度满足K*64+56个字节  
  164.     dwPadLen = (dwIndex < 56) ? (56-dwIndex) : (120-dwIndex);  
  165.     MD5_Update( pstruContext, MDPadding, dwPadLen );  
  166.     MD5_Update( pstruContext, pBits, 8 );  
  167. }  
  168.   
  169. INT MD5_Hash( const BYTE* inputBuffer, UINT inputCount, BYTE* outputBuffer )  
  170. {  
  171.     MD5CTX struContext;  
  172.       
  173.     if( inputBuffer == NULL )  
  174.     {  
  175.         inputCount = 0;  
  176.     }  
  177.   
  178.     // 进行MD5变换  
  179.     MD5_Init( &struContext );       // 初始化  
  180.     MD5_Update( &struContext, inputBuffer, inputCount );    // MD5数据块更新操作  
  181.     MD5_Final( &struContext );  // 获得最终结果  
  182.   
  183.     // 获取哈希值  
  184.     if( outputBuffer != NULL )  
  185.     {  
  186.         memcpy( outputBuffer, struContext.aState, 16 );  
  187.     }     
  188.   
  189.     return 16;  
  190. }  
  191.   
  192. INT HMAC_MD5_Hash( const BYTE* inputBuffer, UINT inputCount, const BYTE* userKey, UINT UserKeyLen, BYTE* outputBuffer )  
  193. {     
  194.     BYTE hmacKey[64] = {0};  
  195.     BYTE k_ipad[64];  
  196.     BYTE k_opad[64];  
  197.     MD5CTX struContext;  
  198.   
  199.     if( inputBuffer == NULL )  
  200.     {  
  201.         inputCount = 0;  
  202.     }  
  203.   
  204.     if( userKey == NULL )  
  205.     {  
  206.         UserKeyLen = 0;  
  207.     }  
  208.   
  209.     // 保证密钥长度不超过64字节  
  210.     if( UserKeyLen > 64 )  
  211.     {  
  212.          MD5_Hash( userKey, UserKeyLen, hmacKey );  
  213.     }  
  214.     else  
  215.     {  
  216.         memcpy( hmacKey, userKey, UserKeyLen );  
  217.     }  
  218.   
  219.     forUINT i = 0; i < 64; i++ )  
  220.     {  
  221.         k_ipad[i] = hmacKey[i] ^ 0x36;  
  222.         k_opad[i] = hmacKey[i] ^ 0x5C;  
  223.     }  
  224.   
  225.     // 内圈MD5运算  
  226.     MD5_Init( &struContext );       // 初始化  
  227.     MD5_Update( &struContext, k_ipad, 64 ); // MD5数据块更新操作  
  228.     MD5_Update( &struContext, inputBuffer, inputCount );    // MD5数据块更新操作  
  229.     MD5_Final( &struContext );  // 获得最终结果  
  230.     memcpy( hmacKey, struContext.aState, 16 );  
  231.   
  232.     // 外圈MD5运算  
  233.     MD5_Init( &struContext );       // 初始化  
  234.     MD5_Update( &struContext, k_opad, 64 ); // MD5数据块更新操作  
  235.     MD5_Update( &struContext, hmacKey, 16 );    // MD5数据块更新操作  
  236.     MD5_Final( &struContext );  // 获得最终结果  
  237.   
  238.     // 获取哈希值  
  239.     if( outputBuffer != NULL )  
  240.     {  
  241.         memcpy( outputBuffer, struContext.aState, 16 );  
  242.     }     
  243.   
  244.     return 16;  
  245. }  
  246.   
  247. INT MD5_BASE64( const BYTE* inputBuffer, UINT inputCount, TCHAR* outputBuffer )  
  248. {  
  249.     BYTE hash[16];  
  250.     INT iByteNum;  
  251.   
  252.     // 计算输入串MD5的哈希值  
  253.     iByteNum = MD5_Hash( inputBuffer, inputCount, hash );  
  254.   
  255.     // 将哈希值转换成BASE64编码  
  256.     return BASE64_Encode( hash, iByteNum, outputBuffer );  
  257. }  
  258.   
  259. INT HMAC_MD5_BASE64( const BYTE* inputBuffer, UINT inputCount, const BYTE* userKey, UINT UserKeyLen, TCHAR* outputBuffer )  
  260. {  
  261.     BYTE hash[16];  
  262.     INT iByteNum;  
  263.   
  264.     // 计算输入串HMAC-MD5的哈希值  
  265.     iByteNum = HMAC_MD5_Hash( inputBuffer, inputCount, userKey, UserKeyLen, hash );  
  266.   
  267.     // 将哈希值转换成BASE64编码  
  268.     return BASE64_Encode( hash, iByteNum, outputBuffer );  
  269. }  

抱歉!评论已关闭.