00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include <ncbi_pch.hpp>
00034 #include <util/md5.hpp>
00035 #include <util/util_exception.hpp>
00036
00037
00038 BEGIN_NCBI_SCOPE
00039
00040
00041
00042 inline
00043 static void s_ByteReverse(unsigned char* buf, size_t longs)
00044 {
00045 Uint4 t;
00046 do {
00047 t = (Uint4) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
00048 ((unsigned) buf[1] << 8 | buf[0]);
00049 *(reinterpret_cast<Uint4*>(buf)) = t;
00050 buf += 4;
00051 } while (--longs);
00052 }
00053
00054
00055
00056
00057 CMD5::CMD5(void)
00058 : m_Bits(0), m_Finalized(false)
00059 {
00060 m_Buf[0] = 0x67452301;
00061 m_Buf[1] = 0xefcdab89;
00062 m_Buf[2] = 0x98badcfe;
00063 m_Buf[3] = 0x10325476;
00064 }
00065
00066
00067
00068 void CMD5::Update(const char* buf, size_t length)
00069 {
00070 if ( m_Finalized ) {
00071 NCBI_THROW(CUtilException, eWrongCommand,
00072 "attempt to update a finalized MD5 instance");
00073 }
00074
00075
00076 unsigned int tmp = (unsigned int)((m_Bits >> 3) % sizeof(m_In));
00077
00078
00079 m_Bits += length << 3;
00080
00081
00082 if ( tmp ) {
00083 unsigned char* p = m_In + tmp;
00084
00085 tmp = kBlockSize - tmp;
00086 if (length < tmp) {
00087 memcpy(p, buf, length);
00088 return;
00089 }
00090 memcpy(p, buf, tmp);
00091 #ifdef WORDS_BIGENDIAN
00092 s_ByteReverse(m_In, 16);
00093 #endif
00094 Transform();
00095 buf += tmp;
00096 length -= tmp;
00097 }
00098
00099
00100 while (length >= kBlockSize) {
00101 memcpy(m_In, buf, kBlockSize);
00102 #ifdef WORDS_BIGENDIAN
00103 s_ByteReverse(m_In, 16);
00104 #endif
00105 Transform();
00106 buf += kBlockSize;
00107 length -= kBlockSize;
00108 }
00109
00110
00111 memcpy(m_In, buf, length);
00112 }
00113
00114
00115
00116
00117 void CMD5::Finalize(unsigned char digest[16])
00118 {
00119 if ( m_Finalized ) {
00120 memcpy(digest, m_Buf, 16);
00121 return;
00122 }
00123
00124
00125 int count = (int)((m_Bits >> 3) % kBlockSize);
00126
00127
00128
00129 unsigned char *p = m_In + count;
00130 *p++ = 0x80;
00131
00132
00133 count = kBlockSize - 1 - count;
00134
00135
00136 if (count < 8) {
00137
00138 memset(p, 0, count);
00139 #ifdef WORDS_BIGENDIAN
00140 s_ByteReverse(m_In, 16);
00141 #endif
00142 Transform();
00143
00144
00145 memset(m_In, 0, kBlockSize - 8);
00146 } else {
00147
00148 memset(p, 0, count - 8);
00149 #ifdef WORDS_BIGENDIAN
00150 s_ByteReverse(m_In, 14);
00151 #endif
00152 }
00153
00154
00155 reinterpret_cast<Uint4*>(m_In)[14] = static_cast<Uint4>(m_Bits);
00156 reinterpret_cast<Uint4*>(m_In)[15] = static_cast<Uint4>(m_Bits >> 32);
00157
00158 Transform();
00159 #ifdef WORDS_BIGENDIAN
00160 s_ByteReverse(reinterpret_cast<unsigned char*>(m_Buf), 4);
00161 #endif
00162 memcpy(digest, m_Buf, 16);
00163 memset(m_In, 0, kBlockSize);
00164 }
00165
00166
00167 string CMD5::GetHexSum(unsigned char digest[16])
00168 {
00169 CNcbiOstrstream oss;
00170 for (size_t i = 0; i < 16; ++i) {
00171 oss << hex << setw(2) << setfill('0') << (int)digest[i];
00172 }
00173 return CNcbiOstrstreamToString(oss);
00174 }
00175
00176
00177
00178
00179
00180 #define F1(x, y, z) (z ^ (x & (y ^ z)))
00181 #define F2(x, y, z) F1(z, x, y)
00182 #define F3(x, y, z) (x ^ y ^ z)
00183 #define F4(x, y, z) (y ^ (x | ~z))
00184
00185
00186 #define MD5STEP(f, w, x, y, z, data, s) \
00187 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
00188
00189
00190
00191
00192 void CMD5::Transform(void)
00193 {
00194 Uint4 a, b, c, d;
00195 Uint4* inw = reinterpret_cast<Uint4*>(m_In);
00196
00197 a = m_Buf[0];
00198 b = m_Buf[1];
00199 c = m_Buf[2];
00200 d = m_Buf[3];
00201
00202 MD5STEP(F1, a, b, c, d, inw[0] + 0xd76aa478, 7);
00203 MD5STEP(F1, d, a, b, c, inw[1] + 0xe8c7b756, 12);
00204 MD5STEP(F1, c, d, a, b, inw[2] + 0x242070db, 17);
00205 MD5STEP(F1, b, c, d, a, inw[3] + 0xc1bdceee, 22);
00206 MD5STEP(F1, a, b, c, d, inw[4] + 0xf57c0faf, 7);
00207 MD5STEP(F1, d, a, b, c, inw[5] + 0x4787c62a, 12);
00208 MD5STEP(F1, c, d, a, b, inw[6] + 0xa8304613, 17);
00209 MD5STEP(F1, b, c, d, a, inw[7] + 0xfd469501, 22);
00210 MD5STEP(F1, a, b, c, d, inw[8] + 0x698098d8, 7);
00211 MD5STEP(F1, d, a, b, c, inw[9] + 0x8b44f7af, 12);
00212 MD5STEP(F1, c, d, a, b, inw[10] + 0xffff5bb1, 17);
00213 MD5STEP(F1, b, c, d, a, inw[11] + 0x895cd7be, 22);
00214 MD5STEP(F1, a, b, c, d, inw[12] + 0x6b901122, 7);
00215 MD5STEP(F1, d, a, b, c, inw[13] + 0xfd987193, 12);
00216 MD5STEP(F1, c, d, a, b, inw[14] + 0xa679438e, 17);
00217 MD5STEP(F1, b, c, d, a, inw[15] + 0x49b40821, 22);
00218
00219 MD5STEP(F2, a, b, c, d, inw[1] + 0xf61e2562, 5);
00220 MD5STEP(F2, d, a, b, c, inw[6] + 0xc040b340, 9);
00221 MD5STEP(F2, c, d, a, b, inw[11] + 0x265e5a51, 14);
00222 MD5STEP(F2, b, c, d, a, inw[0] + 0xe9b6c7aa, 20);
00223 MD5STEP(F2, a, b, c, d, inw[5] + 0xd62f105d, 5);
00224 MD5STEP(F2, d, a, b, c, inw[10] + 0x02441453, 9);
00225 MD5STEP(F2, c, d, a, b, inw[15] + 0xd8a1e681, 14);
00226 MD5STEP(F2, b, c, d, a, inw[4] + 0xe7d3fbc8, 20);
00227 MD5STEP(F2, a, b, c, d, inw[9] + 0x21e1cde6, 5);
00228 MD5STEP(F2, d, a, b, c, inw[14] + 0xc33707d6, 9);
00229 MD5STEP(F2, c, d, a, b, inw[3] + 0xf4d50d87, 14);
00230 MD5STEP(F2, b, c, d, a, inw[8] + 0x455a14ed, 20);
00231 MD5STEP(F2, a, b, c, d, inw[13] + 0xa9e3e905, 5);
00232 MD5STEP(F2, d, a, b, c, inw[2] + 0xfcefa3f8, 9);
00233 MD5STEP(F2, c, d, a, b, inw[7] + 0x676f02d9, 14);
00234 MD5STEP(F2, b, c, d, a, inw[12] + 0x8d2a4c8a, 20);
00235
00236 MD5STEP(F3, a, b, c, d, inw[5] + 0xfffa3942, 4);
00237 MD5STEP(F3, d, a, b, c, inw[8] + 0x8771f681, 11);
00238 MD5STEP(F3, c, d, a, b, inw[11] + 0x6d9d6122, 16);
00239 MD5STEP(F3, b, c, d, a, inw[14] + 0xfde5380c, 23);
00240 MD5STEP(F3, a, b, c, d, inw[1] + 0xa4beea44, 4);
00241 MD5STEP(F3, d, a, b, c, inw[4] + 0x4bdecfa9, 11);
00242 MD5STEP(F3, c, d, a, b, inw[7] + 0xf6bb4b60, 16);
00243 MD5STEP(F3, b, c, d, a, inw[10] + 0xbebfbc70, 23);
00244 MD5STEP(F3, a, b, c, d, inw[13] + 0x289b7ec6, 4);
00245 MD5STEP(F3, d, a, b, c, inw[0] + 0xeaa127fa, 11);
00246 MD5STEP(F3, c, d, a, b, inw[3] + 0xd4ef3085, 16);
00247 MD5STEP(F3, b, c, d, a, inw[6] + 0x04881d05, 23);
00248 MD5STEP(F3, a, b, c, d, inw[9] + 0xd9d4d039, 4);
00249 MD5STEP(F3, d, a, b, c, inw[12] + 0xe6db99e5, 11);
00250 MD5STEP(F3, c, d, a, b, inw[15] + 0x1fa27cf8, 16);
00251 MD5STEP(F3, b, c, d, a, inw[2] + 0xc4ac5665, 23);
00252
00253 MD5STEP(F4, a, b, c, d, inw[0] + 0xf4292244, 6);
00254 MD5STEP(F4, d, a, b, c, inw[7] + 0x432aff97, 10);
00255 MD5STEP(F4, c, d, a, b, inw[14] + 0xab9423a7, 15);
00256 MD5STEP(F4, b, c, d, a, inw[5] + 0xfc93a039, 21);
00257 MD5STEP(F4, a, b, c, d, inw[12] + 0x655b59c3, 6);
00258 MD5STEP(F4, d, a, b, c, inw[3] + 0x8f0ccc92, 10);
00259 MD5STEP(F4, c, d, a, b, inw[10] + 0xffeff47d, 15);
00260 MD5STEP(F4, b, c, d, a, inw[1] + 0x85845dd1, 21);
00261 MD5STEP(F4, a, b, c, d, inw[8] + 0x6fa87e4f, 6);
00262 MD5STEP(F4, d, a, b, c, inw[15] + 0xfe2ce6e0, 10);
00263 MD5STEP(F4, c, d, a, b, inw[6] + 0xa3014314, 15);
00264 MD5STEP(F4, b, c, d, a, inw[13] + 0x4e0811a1, 21);
00265 MD5STEP(F4, a, b, c, d, inw[4] + 0xf7537e82, 6);
00266 MD5STEP(F4, d, a, b, c, inw[11] + 0xbd3af235, 10);
00267 MD5STEP(F4, c, d, a, b, inw[2] + 0x2ad7d2bb, 15);
00268 MD5STEP(F4, b, c, d, a, inw[9] + 0xeb86d391, 21);
00269
00270 m_Buf[0] += a;
00271 m_Buf[1] += b;
00272 m_Buf[2] += c;
00273 m_Buf[3] += d;
00274 }
00275
00276
00277 END_NCBI_SCOPE
00278
00279