E-MailRelay
gmd5.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2024 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file gmd5.cpp
19///
20
21#include "gdef.h"
22#include "gmd5.h"
23#include "ghashstate.h"
24#include "gexception.h"
25#include "gassert.h"
26#include <string> // std::string
27#include <cstdlib> // std::size_t
28#include <array>
29
30namespace G
31{
32 namespace Md5Imp
33 {
34 using digest_state = Md5::digest_state ;
35 using small_t = Md5::small_t ;
36 using big_t = Md5::big_t ;
37 class digest ;
38 class format ;
39 class block ;
40 }
41}
42
43//| \class G::Md5Imp::digest
44/// A class that calculates an md5 digest from one or more 64-byte blocks of
45/// data using the algorithm described by RFC-1321.
46///
47/// A digest can be calculated in one go from an arbitrarily-sized block of
48/// data, or incrementally from a series of 64-byte blocks. The 64-byte
49/// blocks must be passed as Md5Imp::block objects.
50///
51class G::Md5Imp::digest : private G::Md5::digest_state
52{
53public:
54 digest() ;
55 // Default constructor. The message to be digested
56 // should be add()ed in 64-byte blocks.
57
58 explicit digest( const std::string & s ) ;
59 // Constuctor. Calculates a digest for the given
60 // message string. Do not use add() with this
61 // constructor.
62
63 explicit digest( std::string_view ) ;
64 // Constuctor. Calculates a digest for the given
65 // message data. Do not use add() with this
66 // constructor.
67
68 explicit digest( digest_state ) ;
69 // Constructor taking the result of an earlier call
70 // to state(). This allows calculation of a digest
71 // from a stream of 64-byte blocks to be suspended
72 // mid-stream and then resumed using a new digest
73 // object.
74
75 digest_state state() const ;
76 // Returns the internal state. Typically passed to
77 // the Md5Imp::format class.
78
79 void add( const block & ) ;
80 // Adds a 64-byte block of the message.
81
82private:
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 ;
86
87private:
88 explicit digest( const block & ) ;
89 void add( const digest & ) ;
90 void init() ;
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 ) ;
104} ;
105
106//| \class G::Md5Imp::format
107/// A thin veneer over G::HashState.
108///
109class G::Md5Imp::format
110{
111public:
112 static std::string encode( const digest_state & ) ;
113 // Returns the digest state as a string typically
114 // containing non-printing characters.
115
116 static std::string encode( const digest_state & , big_t n ) ;
117 // Returns the digest state and a stream-size
118 // in the encode() format.
119
120 static digest_state decode( const std::string & , small_t & ) ;
121 // Converts a encode() string back into a digest
122 // state and a stream-size.
123
124public:
125 format() = delete ;
126} ;
127
128//| \class G::Md5Imp::block
129/// A helper class used by the Md5Imp::digest implementation to represent a
130/// 64-character data block.
131///
132class G::Md5Imp::block
133{
134public:
135 block( const char * data_p , std::size_t data_n , small_t block_offset , big_t end_value ) ;
136 // Constructor. The data pointer is kept.
137 //
138 // The 'block-offset' indicates, in units of 64-character
139 // blocks, how far into 'p' the current block's data is.
140 //
141 // The data pointer must have at least 64 bytes beyond the
142 // 'block-offset' point, except for the last block in
143 // a message sequence. Note that this is the number
144 // of blocks, not the number of bytes.
145 //
146 // The 'end-value' is derived from the length of the
147 // full message (not just the current block). It is only
148 // used for the last block. See end().
149
150 static big_t end( small_t data_length ) ;
151 // Takes the total number of bytes in the input message and
152 // returns a value which can be passed to the constructor's
153 // third parameter. This is used for the last block in
154 // the sequence of blocks that make up a complete message.
155
156 static small_t blocks( small_t data_length ) ;
157 // Takes the total number of bytes in the input message and
158 // returns the number of 64-byte blocks, allowing for
159 // padding. In practice 0..55 maps to 1, 56..119 maps to
160 // 2, etc.
161
162 big_t X( small_t ) const ;
163 // Returns a value from within the block. See RFC-1321.
164
165public:
166 ~block() = default ;
167 block( const block & ) = delete ;
168 block( block && ) = delete ;
169 block & operator=( const block & ) = delete ;
170 block & operator=( block && ) = delete ;
171
172private:
173 small_t x( small_t ) const ;
174 static small_t rounded( small_t n ) ;
175
176private:
177 const char * m_p ;
178 std::size_t m_n ;
179 small_t m_block ;
180 big_t m_end_value ;
181} ;
182
183// ==
184
185G::Md5Imp::digest::digest() :
186 digest_state{}
187{
188 init() ;
189}
190
191G::Md5Imp::digest::digest( const std::string & s ) :
192 digest_state{}
193{
194 init() ;
195 small_t nblocks = block::blocks( s.size() ) ;
196 for( small_t i = 0U ; i < nblocks ; ++i )
197 {
198 block blk( s.data() , s.size() , i , block::end(s.size()) ) ;
199 add( blk ) ;
200 }
201}
202
203G::Md5Imp::digest::digest( std::string_view sv ) :
204 digest_state{}
205{
206 init() ;
207 small_t nblocks = block::blocks( sv.size() ) ;
208 for( small_t i = 0U ; i < nblocks ; ++i )
209 {
210 block blk( sv.data() , sv.size() , i , block::end(sv.size()) ) ;
211 add( blk ) ;
212 }
213}
214
215G::Md5Imp::digest::digest( digest_state d_in ) :
216 digest_state{}
217{
218 a = d_in.a ;
219 b = d_in.b ;
220 c = d_in.c ;
221 d = d_in.d ;
222}
223
224void G::Md5Imp::digest::init()
225{
226 a = 0x67452301UL ;
227 b = 0xefcdab89UL ;
228 c = 0x98badcfeUL ;
229 d = 0x10325476UL ;
230}
231
232G::Md5Imp::digest::digest_state G::Md5Imp::digest::state() const
233{
234 big_t mask = 0 ;
235 small_t thirty_two = 32U ;
236 small_t sizeof_thirty_two_bits = 4U ; // 4x8=32
237 if( sizeof(mask) > sizeof_thirty_two_bits )
238 {
239 mask = ~0U ;
240 mask <<= thirty_two ; // ignore warnings here
241 }
242 digest_state result = { a & ~mask , b & ~mask , c & ~mask , d & ~mask } ;
243 return result ;
244}
245
246void G::Md5Imp::digest::add( const block & blk )
247{
248 digest old( *this ) ;
249 round1( blk ) ;
250 round2( blk ) ;
251 round3( blk ) ;
252 round4( blk ) ;
253 add( old ) ;
254}
255
256void G::Md5Imp::digest::add( const digest & other )
257{
258 a += other.a ;
259 b += other.b ;
260 c += other.c ;
261 d += other.d ;
262}
263
264void G::Md5Imp::digest::round1( const block & m )
265{
266 digest & r = *this ;
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);
271}
272
273void G::Md5Imp::digest::round2( const block & m )
274{
275 digest & r = *this ;
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);
280}
281
282void G::Md5Imp::digest::round3( const block & m )
283{
284 digest & r = *this ;
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);
289}
290
291void G::Md5Imp::digest::round4( const block & m )
292{
293 digest & r = *this ;
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);
298}
299
300void G::Md5Imp::digest::operator()( const block & m , aux_fn_t aux , Permutation p ,
301 small_t k , small_t s , small_t i )
302{
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 ) ;
307}
308
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 )
311{
312 return b + rot32( s , ( a + (*aux)( b , c , d ) + m.X(k) + T(i) ) ) ;
313}
314
315G::Md5Imp::big_t G::Md5Imp::digest::rot32( small_t places , big_t n )
316{
317 // circular rotate of 32 LSBs, with corruption of higher bits
318 big_t overflow_mask = ( big_t(1U) << places ) - big_t(1U) ; // in case big_t is more than 32 bits
319 big_t overflow = ( n >> ( small_t(32U) - places ) ) ;
320 return ( n << places ) | ( overflow & overflow_mask ) ;
321}
322
323G::Md5Imp::big_t G::Md5Imp::digest::F( big_t x , big_t y , big_t z )
324{
325 return ( x & y ) | ( ~x & z ) ;
326}
327
328G::Md5Imp::big_t G::Md5Imp::digest::G( big_t x , big_t y , big_t z )
329{
330 return ( x & z ) | ( y & ~z ) ;
331}
332
333G::Md5Imp::big_t G::Md5Imp::digest::H( big_t x , big_t y , big_t z )
334{
335 return x ^ y ^ z ;
336}
337
338G::Md5Imp::big_t G::Md5Imp::digest::I( big_t x , big_t y , big_t z )
339{
340 return y ^ ( x | ~z ) ;
341}
342
343G::Md5Imp::big_t G::Md5Imp::digest::T( small_t i )
344{
345 // T = static_cast<big_t>( 4294967296.0 * std::fabs(std::sin(static_cast<double>(i))) ) for 1 <= i <= 64
346 //
347 static constexpr std::array<big_t,64U> t_map {{
348 0xd76aa478UL ,
349 0xe8c7b756UL ,
350 0x242070dbUL ,
351 0xc1bdceeeUL ,
352 0xf57c0fafUL ,
353 0x4787c62aUL ,
354 0xa8304613UL ,
355 0xfd469501UL ,
356 0x698098d8UL ,
357 0x8b44f7afUL ,
358 0xffff5bb1UL ,
359 0x895cd7beUL ,
360 0x6b901122UL ,
361 0xfd987193UL ,
362 0xa679438eUL ,
363 0x49b40821UL ,
364 0xf61e2562UL ,
365 0xc040b340UL ,
366 0x265e5a51UL ,
367 0xe9b6c7aaUL ,
368 0xd62f105dUL ,
369 0x02441453UL ,
370 0xd8a1e681UL ,
371 0xe7d3fbc8UL ,
372 0x21e1cde6UL ,
373 0xc33707d6UL ,
374 0xf4d50d87UL ,
375 0x455a14edUL ,
376 0xa9e3e905UL ,
377 0xfcefa3f8UL ,
378 0x676f02d9UL ,
379 0x8d2a4c8aUL ,
380 0xfffa3942UL ,
381 0x8771f681UL ,
382 0x6d9d6122UL ,
383 0xfde5380cUL ,
384 0xa4beea44UL ,
385 0x4bdecfa9UL ,
386 0xf6bb4b60UL ,
387 0xbebfbc70UL ,
388 0x289b7ec6UL ,
389 0xeaa127faUL ,
390 0xd4ef3085UL ,
391 0x04881d05UL ,
392 0xd9d4d039UL ,
393 0xe6db99e5UL ,
394 0x1fa27cf8UL ,
395 0xc4ac5665UL ,
396 0xf4292244UL ,
397 0x432aff97UL ,
398 0xab9423a7UL ,
399 0xfc93a039UL ,
400 0x655b59c3UL ,
401 0x8f0ccc92UL ,
402 0xffeff47dUL ,
403 0x85845dd1UL ,
404 0x6fa87e4fUL ,
405 0xfe2ce6e0UL ,
406 0xa3014314UL ,
407 0x4e0811a1UL ,
408 0xf7537e82UL ,
409 0xbd3af235UL ,
410 0x2ad7d2bbUL ,
411 0xeb86d391UL }} ;
412 G_ASSERT( i > 0 && i <= t_map.size() ) ;
413 return t_map.at(i-1U) ;
414}
415
416// ===
417
418std::string G::Md5Imp::format::encode( const digest_state & state )
419{
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() ) ;
422}
423
424std::string G::Md5Imp::format::encode( const digest_state & state , big_t n )
425{
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 ) ;
428}
429
430G::Md5Imp::digest_state G::Md5Imp::format::decode( const std::string & str , small_t & n )
431{
432 std::array<big_t,4U> state_array {{ 0 , 0 , 0 , 0 }} ;
433 G::HashState<16,big_t,small_t>::decode( str , state_array.data() , n ) ;
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] ;
439 return result ;
440}
441
442// ===
443
444G::Md5Imp::block::block( const char * data_p , std::size_t data_n , small_t block_in , big_t end_value ) :
445 m_p(data_p) ,
446 m_n(data_n) ,
447 m_block(block_in) ,
448 m_end_value(end_value)
449{
450}
451
452G::Md5Imp::big_t G::Md5Imp::block::end( small_t length )
453{
454 big_t result = length ;
455 result *= 8UL ;
456 return result ;
457}
458
459G::Md5Imp::small_t G::Md5Imp::block::rounded( small_t raw_byte_count )
460{
461 small_t n = raw_byte_count + 64U ;
462 return n - ( ( raw_byte_count + 8U ) % 64U ) ;
463}
464
465G::Md5Imp::small_t G::Md5Imp::block::blocks( small_t raw_byte_count )
466{
467 small_t byte_count = rounded(raw_byte_count) + 8U ;
468 return byte_count / 64UL ;
469}
470
471G::Md5Imp::big_t G::Md5Imp::block::X( small_t dword_index ) const
472{
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 ) ;
478 return result ;
479}
480
481G::Md5Imp::small_t G::Md5Imp::block::x( small_t i ) const
482{
483 small_t length = m_n ;
484 if( i < length )
485 {
486 return static_cast<unsigned char>(m_p[i]) ;
487 }
488 else if( i < rounded(length) )
489 {
490 return i == length ? 128U : 0U ;
491 }
492 else
493 {
494 small_t byte_shift = i - rounded(length) ;
495 if( byte_shift >= sizeof(big_t) )
496 {
497 return 0U ;
498 }
499 else
500 {
501 small_t bit_shift = byte_shift * 8U ;
502
503 big_t end_value = m_end_value >> bit_shift ;
504 return static_cast<small_t>( end_value & 0xffUL ) ;
505 }
506 }
507}
508
509// ==
510
512 m_d(Md5Imp::digest().state())
513{
514}
515
516G::Md5::Md5( const std::string & str_state ) :
517 m_d(Md5Imp::format::decode(str_state,m_n))
518{
519 G_ASSERT( str_state.size() == (valuesize()+4U) ) ;
520}
521
522std::string G::Md5::state() const
523{
524 G_ASSERT( Md5Imp::format::encode(m_d,m_n).size() == (valuesize()+4U) ) ;
525 return Md5Imp::format::encode( m_d , m_n ) ;
526}
527
528void G::Md5::add( const char * data_p , std::size_t data_n )
529{
530 m_s.append( data_p , data_n ) ;
531 m_n += data_n ;
532 consume() ;
533}
534
535void G::Md5::add( const std::string & data )
536{
537 m_s.append( data ) ;
538 m_n += data.size() ;
539 consume() ;
540}
541
542void G::Md5::consume()
543{
544 // consume complete blocks and keep the residue in m_s
545 Md5Imp::digest dd( m_d ) ;
546 while( m_s.length() >= 64U )
547 {
548 Md5Imp::block blk( m_s.data() , m_s.size() , 0U , 0UL ) ;
549 dd.add( blk ) ;
550 m_s.erase( 0U , 64U ) ;
551 }
552 m_d = dd.state() ;
553}
554
555std::string G::Md5::value()
556{
557 Md5Imp::digest dd( m_d ) ;
558 Md5Imp::block blk( m_s.data() , m_s.size() , 0U , Md5Imp::block::end(m_n) ) ;
559 dd.add( blk ) ;
560 m_s.erase() ;
561 m_d = dd.state() ;
562 return Md5Imp::format::encode( m_d ) ;
563}
564
565#ifndef G_LIB_SMALL
566std::string G::Md5::digest( const std::string & input )
567{
568 Md5Imp::digest dd( input ) ;
569 return Md5Imp::format::encode( dd.state() ) ;
570}
571#endif
572
573#ifndef G_LIB_SMALL
574std::string G::Md5::digest( std::string_view input )
575{
576 Md5Imp::digest dd( input ) ;
577 return Md5Imp::format::encode( dd.state() ) ;
578}
579#endif
580
581std::string G::Md5::digest( const std::string & input_1 , const std::string & input_2 )
582{
583 G::Md5 x ;
584 x.add( input_1 ) ;
585 x.add( input_2 ) ;
586 return x.value() ;
587}
588
589std::string G::Md5::digest( std::string_view input_1 , std::string_view input_2 )
590{
591 G::Md5 x ;
592 x.add( input_1.data() , input_1.size() ) ;
593 x.add( input_2.data() , input_2.size() ) ;
594 return x.value() ;
595}
596
597std::string G::Md5::digest2( const std::string & input_1 , const std::string & input_2 )
598{
599 return digest( input_1 , input_2 ) ;
600}
601
602std::string G::Md5::predigest( const std::string & input )
603{
604 Md5 x ;
605 x.add( input ) ;
606 G_ASSERT( input.size() == blocksize() ) ;
607 return x.state().substr(0U,valuesize()) ; // strip off the size; added back in postdigest()
608}
609
610std::string G::Md5::postdigest( const std::string & state_pair , const std::string & message )
611{
612 if( state_pair.size() != 32U ) // valuesize()*2
613 throw InvalidState() ;
614
615 const char * _64 = "\x40\0\0\0" ; // state size suffix
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) ;
618
619 Md5 xi( state_i ) ;
620 xi.add( message ) ;
621
622 Md5 xo( state_o ) ;
623 xo.add( xi.value() ) ;
624
625 return xo.value() ;
626}
627
628std::size_t G::Md5::blocksize()
629{
630 return 64U ;
631}
632
633std::size_t G::Md5::valuesize()
634{
635 return 16U ;
636}
637
638#ifndef G_LIB_SMALL
639std::size_t G::Md5::statesize()
640{
641 return 20U ;
642}
643#endif
644
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...
Definition: ghashstate.h:170
MD5 message digest class.
Definition: gmd5.h:50
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...
Definition: gmd5.cpp:610
static std::size_t blocksize()
Returns the block size in bytes (64).
Definition: gmd5.cpp:628
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...
Definition: gmd5.cpp:602
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.
Definition: gmd5.cpp:597
static std::string digest(const std::string &input)
A convenience function that returns a digest from one input.
Definition: gmd5.cpp:566
void add(const std::string &data)
Adds more data.
Definition: gmd5.cpp:535
std::string value()
Returns the hash value as a 16-character string.
Definition: gmd5.cpp:555
static std::size_t statesize()
Returns the size of the state() string (20).
Definition: gmd5.cpp:639
static std::size_t valuesize()
Returns the value() size in bytes (16).
Definition: gmd5.cpp:633
Md5()
Default constructor.
Definition: gmd5.cpp:511
std::string state() const
Returns the current intermediate state as a 20 character string, although this requires the size of t...
Definition: gmd5.cpp:522
A simple version of boost::format for formatting strings in an i18n-friendly way.
Definition: gformat.h:46
Low-level classes.
Definition: garg.h:36
Holds the four parts of the md5 state.
Definition: gmd5.h:57