34 using digest_state = Md5::digest_state ;
35 using small_t = Md5::small_t ;
36 using big_t = Md5::big_t ;
58 explicit digest(
const std::string & s ) ;
63 explicit digest( std::string_view ) ;
68 explicit digest( digest_state ) ;
75 digest_state
state()
const ;
79 void add(
const block & ) ;
83 using aux_fn_t = big_t (*)(big_t, big_t, big_t) ;
84 enum class Permutation { ABCD , DABC , CDAB , BCDA } ;
85 using P = Permutation ;
88 explicit digest(
const block & ) ;
89 void add(
const digest & ) ;
91 void calculate(
const block & ) ;
92 static big_t T( small_t i ) ;
93 static big_t rot32( small_t places , big_t n ) ;
94 void operator()(
const block & , aux_fn_t , Permutation , small_t , small_t , small_t ) ;
95 static big_t op(
const block & , aux_fn_t , big_t , big_t , big_t , big_t , small_t , small_t , small_t ) ;
96 void round1(
const block & ) ;
97 void round2(
const block & ) ;
98 void round3(
const block & ) ;
99 void round4(
const block & ) ;
100 static big_t F( big_t x , big_t y , big_t z ) ;
101 static big_t
G( big_t x , big_t y , big_t z ) ;
102 static big_t H( big_t x , big_t y , big_t z ) ;
103 static big_t I( big_t x , big_t y , big_t z ) ;
109class G::Md5Imp::format
112 static std::string encode(
const digest_state & ) ;
116 static std::string encode(
const digest_state & , big_t n ) ;
120 static digest_state decode(
const std::string & , small_t & ) ;
132class G::Md5Imp::block
135 block(
const char * data_p , std::size_t data_n , small_t block_offset , big_t end_value ) ;
150 static big_t end( small_t data_length ) ;
156 static small_t blocks( small_t data_length ) ;
162 big_t X( small_t )
const ;
167 block(
const block & ) = delete ;
168 block( block && ) = delete ;
169 block & operator=(
const block & ) = delete ;
170 block & operator=( block && ) = delete ;
173 small_t x( small_t )
const ;
174 static small_t rounded( small_t n ) ;
185G::Md5Imp::digest::digest() :
191G::Md5Imp::digest::digest(
const std::string & s ) :
195 small_t nblocks = block::blocks( s.size() ) ;
196 for( small_t i = 0U ; i < nblocks ; ++i )
198 block blk( s.data() , s.size() , i , block::end(s.size()) ) ;
203G::Md5Imp::digest::digest( std::string_view sv ) :
207 small_t nblocks = block::blocks( sv.size() ) ;
208 for( small_t i = 0U ; i < nblocks ; ++i )
210 block blk( sv.data() , sv.size() , i , block::end(sv.size()) ) ;
215G::Md5Imp::digest::digest( digest_state d_in ) :
224void G::Md5Imp::digest::init()
232G::Md5Imp::digest::digest_state G::Md5Imp::digest::state()
const
235 small_t thirty_two = 32U ;
236 small_t sizeof_thirty_two_bits = 4U ;
237 if(
sizeof(mask) > sizeof_thirty_two_bits )
240 mask <<= thirty_two ;
242 digest_state result = { a & ~mask , b & ~mask , c & ~mask , d & ~mask } ;
246void G::Md5Imp::digest::add(
const block & blk )
248 digest old( *
this ) ;
256void G::Md5Imp::digest::add(
const digest & other )
264void G::Md5Imp::digest::round1(
const block & m )
267 r(m,F,P::ABCD, 0, 7, 1); r(m,F,P::DABC, 1,12, 2); r(m,F,P::CDAB, 2,17, 3); r(m,F,P::BCDA, 3,22, 4);
268 r(m,F,P::ABCD, 4, 7, 5); r(m,F,P::DABC, 5,12, 6); r(m,F,P::CDAB, 6,17, 7); r(m,F,P::BCDA, 7,22, 8);
269 r(m,F,P::ABCD, 8, 7, 9); r(m,F,P::DABC, 9,12,10); r(m,F,P::CDAB,10,17,11); r(m,F,P::BCDA,11,22,12);
270 r(m,F,P::ABCD,12, 7,13); r(m,F,P::DABC,13,12,14); r(m,F,P::CDAB,14,17,15); r(m,F,P::BCDA,15,22,16);
273void G::Md5Imp::digest::round2(
const block & m )
276 r(m,
G,P::ABCD, 1, 5,17); r(m,
G,P::DABC, 6, 9,18); r(m,
G,P::CDAB,11,14,19); r(m,
G,P::BCDA, 0,20,20);
277 r(m,
G,P::ABCD, 5, 5,21); r(m,
G,P::DABC,10, 9,22); r(m,
G,P::CDAB,15,14,23); r(m,
G,P::BCDA, 4,20,24);
278 r(m,
G,P::ABCD, 9, 5,25); r(m,
G,P::DABC,14, 9,26); r(m,
G,P::CDAB, 3,14,27); r(m,
G,P::BCDA, 8,20,28);
279 r(m,
G,P::ABCD,13, 5,29); r(m,
G,P::DABC, 2, 9,30); r(m,
G,P::CDAB, 7,14,31); r(m,
G,P::BCDA,12,20,32);
282void G::Md5Imp::digest::round3(
const block & m )
285 r(m,H,P::ABCD, 5, 4,33); r(m,H,P::DABC, 8,11,34); r(m,H,P::CDAB,11,16,35); r(m,H,P::BCDA,14,23,36);
286 r(m,H,P::ABCD, 1, 4,37); r(m,H,P::DABC, 4,11,38); r(m,H,P::CDAB, 7,16,39); r(m,H,P::BCDA,10,23,40);
287 r(m,H,P::ABCD,13, 4,41); r(m,H,P::DABC, 0,11,42); r(m,H,P::CDAB, 3,16,43); r(m,H,P::BCDA, 6,23,44);
288 r(m,H,P::ABCD, 9, 4,45); r(m,H,P::DABC,12,11,46); r(m,H,P::CDAB,15,16,47); r(m,H,P::BCDA, 2,23,48);
291void G::Md5Imp::digest::round4(
const block & m )
294 r(m,I,P::ABCD, 0, 6,49); r(m,I,P::DABC, 7,10,50); r(m,I,P::CDAB,14,15,51); r(m,I,P::BCDA, 5,21,52);
295 r(m,I,P::ABCD,12, 6,53); r(m,I,P::DABC, 3,10,54); r(m,I,P::CDAB,10,15,55); r(m,I,P::BCDA, 1,21,56);
296 r(m,I,P::ABCD, 8, 6,57); r(m,I,P::DABC,15,10,58); r(m,I,P::CDAB, 6,15,59); r(m,I,P::BCDA,13,21,60);
297 r(m,I,P::ABCD, 4, 6,61); r(m,I,P::DABC,11,10,62); r(m,I,P::CDAB, 2,15,63); r(m,I,P::BCDA, 9,21,64);
300void G::Md5Imp::digest::operator()(
const block & m , aux_fn_t aux , Permutation p ,
301 small_t k , small_t s , small_t i )
303 if( p == P::ABCD ) a = op( m , aux , a , b , c , d , k , s , i ) ;
304 if( p == P::DABC ) d = op( m , aux , d , a , b , c , k , s , i ) ;
305 if( p == P::CDAB ) c = op( m , aux , c , d , a , b , k , s , i ) ;
306 if( p == P::BCDA ) b = op( m , aux , b , c , d , a , k , s , i ) ;
309G::Md5Imp::big_t G::Md5Imp::digest::op(
const block & m , aux_fn_t aux , big_t a , big_t b , big_t c , big_t d ,
310 small_t k , small_t s , small_t i )
312 return b + rot32( s , ( a + (*aux)( b , c , d ) + m.X(k) + T(i) ) ) ;
315G::Md5Imp::big_t G::Md5Imp::digest::rot32( small_t places , big_t n )
318 big_t overflow_mask = ( big_t(1U) << places ) - big_t(1U) ;
319 big_t overflow = ( n >> ( small_t(32U) - places ) ) ;
320 return ( n << places ) | ( overflow & overflow_mask ) ;
323G::Md5Imp::big_t G::Md5Imp::digest::F( big_t x , big_t y , big_t z )
325 return ( x & y ) | ( ~x & z ) ;
328G::Md5Imp::big_t G::Md5Imp::digest::G( big_t x , big_t y , big_t z )
330 return ( x & z ) | ( y & ~z ) ;
333G::Md5Imp::big_t G::Md5Imp::digest::H( big_t x , big_t y , big_t z )
338G::Md5Imp::big_t G::Md5Imp::digest::I( big_t x , big_t y , big_t z )
340 return y ^ ( x | ~z ) ;
343G::Md5Imp::big_t G::Md5Imp::digest::T( small_t i )
347 static constexpr std::array<big_t,64U> t_map {{
412 G_ASSERT( i > 0 && i <= t_map.size() ) ;
413 return t_map.at(i-1U) ;
418std::string G::Md5Imp::format::encode(
const digest_state & state )
420 const std::array<big_t,4U> state_array {{ state.a , state.b , state.c , state.d }} ;
421 return HashState<16,big_t,small_t>::encode( state_array.data() ) ;
424std::string G::Md5Imp::format::encode(
const digest_state & state , big_t n )
426 const std::array<big_t,4U> state_array {{ state.a , state.b , state.c , state.d }} ;
427 return HashState<16,big_t,small_t>::encode( state_array.data() , n ) ;
432 std::array<big_t,4U> state_array {{ 0 , 0 , 0 , 0 }} ;
434 digest_state result = { 0 , 0 , 0 , 0 } ;
435 result.a = state_array[0] ;
436 result.b = state_array[1] ;
437 result.c = state_array[2] ;
438 result.d = state_array[3] ;
444G::Md5Imp::block::block(
const char * data_p , std::size_t data_n , small_t block_in , big_t end_value ) :
448 m_end_value(end_value)
452G::Md5Imp::big_t G::Md5Imp::block::end( small_t length )
454 big_t result = length ;
459G::Md5Imp::small_t G::Md5Imp::block::rounded( small_t raw_byte_count )
461 small_t n = raw_byte_count + 64U ;
462 return n - ( ( raw_byte_count + 8U ) % 64U ) ;
465G::Md5Imp::small_t G::Md5Imp::block::blocks( small_t raw_byte_count )
467 small_t byte_count = rounded(raw_byte_count) + 8U ;
468 return byte_count / 64UL ;
471G::Md5Imp::big_t G::Md5Imp::block::X( small_t dword_index )
const
473 small_t byte_index = ( m_block * 64U ) + ( dword_index * 4U ) ;
474 big_t result = x( byte_index + 3U ) ;
475 result <<= 8U ; result += x( byte_index + 2U ) ;
476 result <<= 8U ; result += x( byte_index + 1U ) ;
477 result <<= 8U ; result += x( byte_index + 0U ) ;
481G::Md5Imp::small_t G::Md5Imp::block::x( small_t i )
const
483 small_t length = m_n ;
486 return static_cast<unsigned char>(m_p[i]) ;
488 else if( i < rounded(length) )
490 return i == length ? 128U : 0U ;
494 small_t byte_shift = i - rounded(length) ;
495 if( byte_shift >=
sizeof(big_t) )
501 small_t bit_shift = byte_shift * 8U ;
503 big_t end_value = m_end_value >> bit_shift ;
504 return static_cast<small_t
>( end_value & 0xffUL ) ;
512 m_d(Md5Imp::digest().state())
517 m_d(Md5Imp::
format::decode(str_state,m_n))
519 G_ASSERT( str_state.size() == (
valuesize()+4U) ) ;
524 G_ASSERT( Md5Imp::format::encode(m_d,m_n).size() == (valuesize()+4U) ) ;
525 return Md5Imp::format::encode( m_d , m_n ) ;
530 m_s.append( data_p , data_n ) ;
542void G::Md5::consume()
545 Md5Imp::digest dd( m_d ) ;
546 while( m_s.length() >= 64U )
548 Md5Imp::block blk( m_s.data() , m_s.size() , 0U , 0UL ) ;
550 m_s.erase( 0U , 64U ) ;
557 Md5Imp::digest dd( m_d ) ;
558 Md5Imp::block blk( m_s.data() , m_s.size() , 0U , Md5Imp::block::end(m_n) ) ;
562 return Md5Imp::format::encode( m_d ) ;
568 Md5Imp::digest dd( input ) ;
569 return Md5Imp::format::encode( dd.state() ) ;
576 Md5Imp::digest dd( input ) ;
577 return Md5Imp::format::encode( dd.state() ) ;
581std::string
G::Md5::digest(
const std::string & input_1 ,
const std::string & input_2 )
592 x.
add( input_1.data() , input_1.size() ) ;
593 x.
add( input_2.data() , input_2.size() ) ;
597std::string
G::Md5::digest2(
const std::string & input_1 ,
const std::string & input_2 )
599 return digest( input_1 , input_2 ) ;
606 G_ASSERT( input.size() == blocksize() ) ;
607 return x.
state().substr(0U,valuesize()) ;
612 if( state_pair.size() != 32U )
613 throw InvalidState() ;
615 const char * _64 =
"\x40\0\0\0" ;
616 std::string state_i = state_pair.substr( 0U , state_pair.size()/2 ).append(_64,4U) ;
617 std::string state_o = state_pair.substr( state_pair.size()/2 ).append(_64,4U) ;
static void decode(const std::string &s, uint_type *values_out, size_type &size_out)
Converts an encode()d string back into a hash state of N/4 integers and a data size returned by refer...
MD5 message digest class.
static std::string postdigest(const std::string &state_pair, const std::string &message)
A convenience function that returns the value() from an outer digest that is initialised with the sec...
static std::size_t blocksize()
Returns the block size in bytes (64).
static std::string predigest(const std::string &padded_key)
A convenience function that add()s the given string of length blocksize() (typically a padded key) an...
static std::string digest2(const std::string &input_1, const std::string &input_2)
A non-overloaded name for the digest() overload taking two parameters.
static std::string digest(const std::string &input)
A convenience function that returns a digest from one input.
void add(const std::string &data)
Adds more data.
std::string value()
Returns the hash value as a 16-character string.
static std::size_t statesize()
Returns the size of the state() string (20).
static std::size_t valuesize()
Returns the value() size in bytes (16).
Md5()
Default constructor.
std::string state() const
Returns the current intermediate state as a 20 character string, although this requires the size of t...
Holds the four parts of the md5 state.