
Эксперт
   
Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия
Репутация: 85 Всего: 196
|
md5.hpp: | Код | #ifndef MD5_HPP_ # define MD5_HPP_ /* rfc1321 */
//----------------------------------------------------------------------------- /** \brief C++ реализация подсчета хэша методом MD5 */ class HashMD5 { /// \brief состояние подсчета (числа A, B, C и D) union State { unsigned data[4]; struct { unsigned A, B, C, D; }; /// \brief шаблон вместо определения в исходной реализации на Си template<class T> inline void Process(unsigned &a, unsigned b, unsigned c, unsigned d, unsigned k, unsigned s, unsigned t, const T &func) { a += func(b,c,d) + k + t; a = ((a << s) | (a >> (32 - s))) + b; } /// \brief функция, используемая на первом раунде рассчета struct Round1 { unsigned operator()(unsigned x, unsigned y, unsigned z) const { return z ^ (x & (y ^ z)); } }; /// \brief функция, используемая на втором раунде рассчета struct Round2 { unsigned operator()(unsigned x, unsigned y, unsigned z) const { return y ^ (z & (x ^ y)); } }; /// \brief функция, используемая на третьем раунде рассчета struct Round3 { unsigned operator()(unsigned x, unsigned y, unsigned z) const { return x ^ y ^ z; } }; /// \brief функция, используемая на четвертом раунде рассчета struct Round4 { unsigned operator()(unsigned x, unsigned y, unsigned z) const { return y ^ (x | (~z)); } };
public: enum { DigestSize = 16 ///< количество байт в хэше };
/// \brief конструктор State() { reset(); }
/// \brief обновляет состояние блоком из 64 байт void update(const unsigned *buffer);
/// \brief возвращает текущее состояние const void* getDigest() const { return data; }
/// \brief сброс в исходное состояние void reset() { A = 0x67452301U; B = 0xefcdab89U; C = 0x98badcfeU; D = 0x10325476U; } };
State state; ///< состояние unsigned long long bits_count; ///< количество обсчитанных бит unsigned char *buffer; ///< содержит данные перед обсчетом unsigned char *hash; ///< временный буфер хэша, уничтожаемый методом update()
unsigned get_bytes_in_buffer() const { return (bits_count >> 3) & 0x3F; }
void create_hash(); void destroy_hash() { delete []hash; hash = 0; } protected: public: enum { DigestSize = State::DigestSize ///< количество байт в хэше };
/// \brief конструктор HashMD5() : hash(0) { buffer = new unsigned char[64]; reset(); } /// \brief деструктор ~HashMD5() { delete []hash; delete []buffer; } /** \brief сброс состояния в исходное * * После сброса состояния рассчет хеша начинается заного */ void reset(void) { bits_count = 0; state.reset(); destroy_hash(); }
/** \brief обновление состояния * @param buffer указатель на массив данных * @param size размер массива данных */ void update(const void *buffer, size_t size);
/** \brief рассчет конечного значения хеша и возврат его пользователю * @param buffer буфер, в который нужно поместить полученный хэш * @return buffer, если он не был равен 0, или указатель на внутренний буфер, который будет уничтожен последующим вызовом update() * @note данной функцией можно пользоваться для получения промежуточного хеша */ const void* get(void *buffer = 0) { if ( !hash ) create_hash(); if (buffer) std::memcpy(buffer, hash, DigestSize); else buffer = hash; return buffer; } }; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- #endif // MD5_HPP_ //-----------------------------------------------------------------------------
|
md5.cpp: | Код | #include <cstring> #include "md5.hpp"
//----------------------------------------------------------------------------- void HashMD5::State::update(const unsigned *data) { unsigned A = this->A; unsigned B = this->B; unsigned C = this->C; unsigned D = this->D;
Process( A, B, C, D, data[ 0], 7, 0xD76AA478, Round1() ); Process( D, A, B, C, data[ 1], 12, 0xE8C7B756, Round1() ); Process( C, D, A, B, data[ 2], 17, 0x242070DB, Round1() ); Process( B, C, D, A, data[ 3], 22, 0xC1BDCEEE, Round1() ); Process( A, B, C, D, data[ 4], 7, 0xF57C0FAF, Round1() ); Process( D, A, B, C, data[ 5], 12, 0x4787C62A, Round1() ); Process( C, D, A, B, data[ 6], 17, 0xA8304613, Round1() ); Process( B, C, D, A, data[ 7], 22, 0xFD469501, Round1() ); Process( A, B, C, D, data[ 8], 7, 0x698098D8, Round1() ); Process( D, A, B, C, data[ 9], 12, 0x8B44F7AF, Round1() ); Process( C, D, A, B, data[10], 17, 0xFFFF5BB1, Round1() ); Process( B, C, D, A, data[11], 22, 0x895CD7BE, Round1() ); Process( A, B, C, D, data[12], 7, 0x6B901122, Round1() ); Process( D, A, B, C, data[13], 12, 0xFD987193, Round1() ); Process( C, D, A, B, data[14], 17, 0xA679438E, Round1() ); Process( B, C, D, A, data[15], 22, 0x49B40821, Round1() );
Process( A, B, C, D, data[ 1], 5, 0xF61E2562, Round2() ); Process( D, A, B, C, data[ 6], 9, 0xC040B340, Round2() ); Process( C, D, A, B, data[11], 14, 0x265E5A51, Round2() ); Process( B, C, D, A, data[ 0], 20, 0xE9B6C7AA, Round2() ); Process( A, B, C, D, data[ 5], 5, 0xD62F105D, Round2() ); Process( D, A, B, C, data[10], 9, 0x02441453, Round2() ); Process( C, D, A, B, data[15], 14, 0xD8A1E681, Round2() ); Process( B, C, D, A, data[ 4], 20, 0xE7D3FBC8, Round2() ); Process( A, B, C, D, data[ 9], 5, 0x21E1CDE6, Round2() ); Process( D, A, B, C, data[14], 9, 0xC33707D6, Round2() ); Process( C, D, A, B, data[ 3], 14, 0xF4D50D87, Round2() ); Process( B, C, D, A, data[ 8], 20, 0x455A14ED, Round2() ); Process( A, B, C, D, data[13], 5, 0xA9E3E905, Round2() ); Process( D, A, B, C, data[ 2], 9, 0xFCEFA3F8, Round2() ); Process( C, D, A, B, data[ 7], 14, 0x676F02D9, Round2() ); Process( B, C, D, A, data[12], 20, 0x8D2A4C8A, Round2() );
Process( A, B, C, D, data[ 5], 4, 0xFFFA3942, Round3() ); Process( D, A, B, C, data[ 8], 11, 0x8771F681, Round3() ); Process( C, D, A, B, data[11], 16, 0x6D9D6122, Round3() ); Process( B, C, D, A, data[14], 23, 0xFDE5380C, Round3() ); Process( A, B, C, D, data[ 1], 4, 0xA4BEEA44, Round3() ); Process( D, A, B, C, data[ 4], 11, 0x4BDECFA9, Round3() ); Process( C, D, A, B, data[ 7], 16, 0xF6BB4B60, Round3() ); Process( B, C, D, A, data[10], 23, 0xBEBFBC70, Round3() ); Process( A, B, C, D, data[13], 4, 0x289B7EC6, Round3() ); Process( D, A, B, C, data[ 0], 11, 0xEAA127FA, Round3() ); Process( C, D, A, B, data[ 3], 16, 0xD4EF3085, Round3() ); Process( B, C, D, A, data[ 6], 23, 0x04881D05, Round3() ); Process( A, B, C, D, data[ 9], 4, 0xD9D4D039, Round3() ); Process( D, A, B, C, data[12], 11, 0xE6DB99E5, Round3() ); Process( C, D, A, B, data[15], 16, 0x1FA27CF8, Round3() ); Process( B, C, D, A, data[ 2], 23, 0xC4AC5665, Round3() );
Process( A, B, C, D, data[ 0], 6, 0xF4292244, Round4() ); Process( D, A, B, C, data[ 7], 10, 0x432AFF97, Round4() ); Process( C, D, A, B, data[14], 15, 0xAB9423A7, Round4() ); Process( B, C, D, A, data[ 5], 21, 0xFC93A039, Round4() ); Process( A, B, C, D, data[12], 6, 0x655B59C3, Round4() ); Process( D, A, B, C, data[ 3], 10, 0x8F0CCC92, Round4() ); Process( C, D, A, B, data[10], 15, 0xFFEFF47D, Round4() ); Process( B, C, D, A, data[ 1], 21, 0x85845DD1, Round4() ); Process( A, B, C, D, data[ 8], 6, 0x6FA87E4F, Round4() ); Process( D, A, B, C, data[15], 10, 0xFE2CE6E0, Round4() ); Process( C, D, A, B, data[ 6], 15, 0xA3014314, Round4() ); Process( B, C, D, A, data[13], 21, 0x4E0811A1, Round4() ); Process( A, B, C, D, data[ 4], 6, 0xF7537E82, Round4() ); Process( D, A, B, C, data[11], 10, 0xBD3AF235, Round4() ); Process( C, D, A, B, data[ 2], 15, 0x2AD7D2BB, Round4() ); Process( B, C, D, A, data[ 9], 21, 0xEB86D391, Round4() );
this->A += A; this->B += B; this->C += C; this->D += D; } //----------------------------------------------------------------------------- void HashMD5::update(const void *data, size_t size) { destroy_hash(); while(size) { size_t count = 64 - get_bytes_in_buffer(); if (count > size) count = size; std::memcpy(buffer + get_bytes_in_buffer(), data, count);
bits_count += (count << 3); data = reinterpret_cast<const char*>(data) + count; size -= count;
if ( !get_bytes_in_buffer() ) //буфер полон state.update( reinterpret_cast<const unsigned*>(buffer) ); } } //----------------------------------------------------------------------------- void HashMD5::create_hash() { if (!hash) hash = new unsigned char[State::DigestSize];
static const unsigned char padding[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; const unsigned bytes_in_buffer = get_bytes_in_buffer(); const unsigned count = ( (bytes_in_buffer < 56) ? 56 : 120 ) - bytes_in_buffer; unsigned char *buf = new unsigned char[bytes_in_buffer + count + 8]; std::memcpy(buf, buffer, bytes_in_buffer); std::memcpy(buf + bytes_in_buffer, padding, count); std::memcpy(buf + bytes_in_buffer + count, &bits_count, 8); State final( state ); final.update( reinterpret_cast<const unsigned*>(buf) ); if ( (count + bytes_in_buffer + 8) > 64) final.update( reinterpret_cast<const unsigned*>(buf + 64) ); std::memcpy(hash, final.getDigest(), DigestSize ); delete []buf; } //----------------------------------------------------------------------------- |
Пользоваться очень просто: | Код | HashMD5 hash; ... hash.reset(); hash.update(buffer, size); ... const char *buffer = (const char*)hash.get(); for(i = 0; i < 64; ++i) std::cout << std::hex << std::setw(2) << std::setfill('0') << int(buffer[i]); std::cout << std::endl; |
Это сообщение отредактировал(а) bsa - 31.10.2008, 01:46
|