- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

md5.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2013 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 // md5.cpp
19 //
20 // An implementation of the RFC-1321 message digest algorithm.
21 //
22 // This code was developed from main body of RFC 1321 without reference to the
23 // RSA reference implementation in the appendix.
24 //
25 // A minor portability advantage over the RSA implementation is that there is no
26 // need to define a datatype that is exactly 32 bits: the requirement is that
27 // 'big_t' is at least 32 bits, but it can be more.
28 //
29 // Stylistic advantages are that it is written in C++ with an enclosing namespace,
30 // it does not use preprocessor macros, and there is an element of layering with
31 // digest_stream built on top of the low-level digest class.
32
33 #include "md5.h"
34
35 md5::digest::digest()
36 {
37 init() ;
38 }
39
40 md5::digest::digest( state_type d_in ) :
41 a(d_in.a) ,
42 b(d_in.b) ,
43 c(d_in.c) ,
44 d(d_in.d)
45 {
46 }
47
48 md5::digest::state_type md5::digest::state() const
49 {
50 big_t mask = 0 ;
51 small_t thirty_two = 32U ;
52 small_t sizeof_thirty_two_bits = 4U ; // 4x8=32
53 if( sizeof(mask) > sizeof_thirty_two_bits )
54 {
55 mask = ~0U ;
56 mask <<= thirty_two ; // ignore warnings here
57 }
58 state_type result = { a & ~mask , b & ~mask , c & ~mask , d & ~mask } ;
59 return result ;
60 }
61
62 md5::digest::digest( const md5::string_type & s )
63 {
64 init() ;
65 small_t n = block::blocks( s.length() ) ;
66 for( small_t i = 0U ; i < n ; ++i )
67 {
68 block blk( s , i , block::end(s.length()) ) ;
69 add( blk ) ;
70 }
71 }
72
73 void md5::digest::add( const block & m )
74 {
75 digest old( *this ) ;
76 round1( m ) ;
77 round2( m ) ;
78 round3( m ) ;
79 round4( m ) ;
80 add( old ) ;
81 }
82
83 void md5::digest::init()
84 {
85 a = 0x67452301UL ;
86 b = 0xefcdab89UL ;
87 c = 0x98badcfeUL ;
88 d = 0x10325476UL ;
89 }
90
91 void md5::digest::add( const digest & other )
92 {
93 a += other.a ;
94 b += other.b ;
95 c += other.c ;
96 d += other.d ;
97 }
98
99 void md5::digest::round1( const block & m )
100 {
101 digest & r = *this ;
102 r(m,F,ABCD, 0, 7, 1); r(m,F,DABC, 1,12, 2); r(m,F,CDAB, 2,17, 3); r(m,F,BCDA, 3,22, 4);
103 r(m,F,ABCD, 4, 7, 5); r(m,F,DABC, 5,12, 6); r(m,F,CDAB, 6,17, 7); r(m,F,BCDA, 7,22, 8);
104 r(m,F,ABCD, 8, 7, 9); r(m,F,DABC, 9,12,10); r(m,F,CDAB,10,17,11); r(m,F,BCDA,11,22,12);
105 r(m,F,ABCD,12, 7,13); r(m,F,DABC,13,12,14); r(m,F,CDAB,14,17,15); r(m,F,BCDA,15,22,16);
106 }
107
108 void md5::digest::round2( const block & m )
109 {
110 digest & r = *this ;
111 r(m,G,ABCD, 1, 5,17); r(m,G,DABC, 6, 9,18); r(m,G,CDAB,11,14,19); r(m,G,BCDA, 0,20,20);
112 r(m,G,ABCD, 5, 5,21); r(m,G,DABC,10, 9,22); r(m,G,CDAB,15,14,23); r(m,G,BCDA, 4,20,24);
113 r(m,G,ABCD, 9, 5,25); r(m,G,DABC,14, 9,26); r(m,G,CDAB, 3,14,27); r(m,G,BCDA, 8,20,28);
114 r(m,G,ABCD,13, 5,29); r(m,G,DABC, 2, 9,30); r(m,G,CDAB, 7,14,31); r(m,G,BCDA,12,20,32);
115 }
116
117 void md5::digest::round3( const block & m )
118 {
119 digest & r = *this ;
120 r(m,H,ABCD, 5, 4,33); r(m,H,DABC, 8,11,34); r(m,H,CDAB,11,16,35); r(m,H,BCDA,14,23,36);
121 r(m,H,ABCD, 1, 4,37); r(m,H,DABC, 4,11,38); r(m,H,CDAB, 7,16,39); r(m,H,BCDA,10,23,40);
122 r(m,H,ABCD,13, 4,41); r(m,H,DABC, 0,11,42); r(m,H,CDAB, 3,16,43); r(m,H,BCDA, 6,23,44);
123 r(m,H,ABCD, 9, 4,45); r(m,H,DABC,12,11,46); r(m,H,CDAB,15,16,47); r(m,H,BCDA, 2,23,48);
124 }
125
126 void md5::digest::round4( const block & m )
127 {
128 digest & r = *this ;
129 r(m,I,ABCD, 0, 6,49); r(m,I,DABC, 7,10,50); r(m,I,CDAB,14,15,51); r(m,I,BCDA, 5,21,52);
130 r(m,I,ABCD,12, 6,53); r(m,I,DABC, 3,10,54); r(m,I,CDAB,10,15,55); r(m,I,BCDA, 1,21,56);
131 r(m,I,ABCD, 8, 6,57); r(m,I,DABC,15,10,58); r(m,I,CDAB, 6,15,59); r(m,I,BCDA,13,21,60);
132 r(m,I,ABCD, 4, 6,61); r(m,I,DABC,11,10,62); r(m,I,CDAB, 2,15,63); r(m,I,BCDA, 9,21,64);
133 }
134
135 void md5::digest::operator()( const block & m , aux_fn_t aux , Permutation p , small_t k , small_t s , small_t i )
136 {
137 if( p == ABCD ) a = op( m , aux , a , b , c , d , k , s , i ) ;
138 if( p == DABC ) d = op( m , aux , d , a , b , c , k , s , i ) ;
139 if( p == CDAB ) c = op( m , aux , c , d , a , b , k , s , i ) ;
140 if( p == BCDA ) b = op( m , aux , b , c , d , a , k , s , i ) ;
141 }
142
143 md5::big_t md5::digest::op( const block & m , aux_fn_t aux , big_t a , big_t b , big_t c , big_t d ,
144 small_t k , small_t s , small_t i )
145 {
146 return b + rot32( s , ( a + (*aux)( b , c , d ) + m.X(k) + T(i) ) ) ;
147 }
148
149 md5::big_t md5::digest::rot32( small_t places , big_t n )
150 {
151 // circular rotate of 32 LSBs, with corruption of higher bits
152 big_t overflow_mask = ( 1UL << places ) - 1UL ; // in case big_t is more than 32 bits
153 big_t overflow = ( n >> ( 32U - places ) ) ;
154 return ( n << places ) | ( overflow & overflow_mask ) ;
155 }
156
157 md5::big_t md5::digest::F( big_t x , big_t y , big_t z )
158 {
159 return ( x & y ) | ( ~x & z ) ;
160 }
161
162 md5::big_t md5::digest::G( big_t x , big_t y , big_t z )
163 {
164 return ( x & z ) | ( y & ~z ) ;
165 }
166
167 md5::big_t md5::digest::H( big_t x , big_t y , big_t z )
168 {
169 return x ^ y ^ z ;
170 }
171
172 md5::big_t md5::digest::I( big_t x , big_t y , big_t z )
173 {
174 return y ^ ( x | ~z ) ;
175 }
176
177 md5::big_t md5::digest::T( small_t i )
178 {
179 // T = static_cast<big_t>( 4294967296.0 * std::fabs(std::sin(static_cast<double>(i))) ) for 1 <= i <= 64
180 //
181 static big_t t_map[] =
182 {
183 0xd76aa478UL ,
184 0xe8c7b756UL ,
185 0x242070dbUL ,
186 0xc1bdceeeUL ,
187 0xf57c0fafUL ,
188 0x4787c62aUL ,
189 0xa8304613UL ,
190 0xfd469501UL ,
191 0x698098d8UL ,
192 0x8b44f7afUL ,
193 0xffff5bb1UL ,
194 0x895cd7beUL ,
195 0x6b901122UL ,
196 0xfd987193UL ,
197 0xa679438eUL ,
198 0x49b40821UL ,
199 0xf61e2562UL ,
200 0xc040b340UL ,
201 0x265e5a51UL ,
202 0xe9b6c7aaUL ,
203 0xd62f105dUL ,
204 0x02441453UL ,
205 0xd8a1e681UL ,
206 0xe7d3fbc8UL ,
207 0x21e1cde6UL ,
208 0xc33707d6UL ,
209 0xf4d50d87UL ,
210 0x455a14edUL ,
211 0xa9e3e905UL ,
212 0xfcefa3f8UL ,
213 0x676f02d9UL ,
214 0x8d2a4c8aUL ,
215 0xfffa3942UL ,
216 0x8771f681UL ,
217 0x6d9d6122UL ,
218 0xfde5380cUL ,
219 0xa4beea44UL ,
220 0x4bdecfa9UL ,
221 0xf6bb4b60UL ,
222 0xbebfbc70UL ,
223 0x289b7ec6UL ,
224 0xeaa127faUL ,
225 0xd4ef3085UL ,
226 0x04881d05UL ,
227 0xd9d4d039UL ,
228 0xe6db99e5UL ,
229 0x1fa27cf8UL ,
230 0xc4ac5665UL ,
231 0xf4292244UL ,
232 0x432aff97UL ,
233 0xab9423a7UL ,
234 0xfc93a039UL ,
235 0x655b59c3UL ,
236 0x8f0ccc92UL ,
237 0xffeff47dUL ,
238 0x85845dd1UL ,
239 0x6fa87e4fUL ,
240 0xfe2ce6e0UL ,
241 0xa3014314UL ,
242 0x4e0811a1UL ,
243 0xf7537e82UL ,
244 0xbd3af235UL ,
245 0x2ad7d2bbUL ,
246 0xeb86d391UL } ;
247 return t_map[i-1UL] ;
248 }
249
250 // ===
251
252 md5::string_type md5::format::raw( const digest::state_type & d )
253 {
254 string_type result ;
255 result.reserve( 16U ) ;
256 result.append( raw(d.a) ) ;
257 result.append( raw(d.b) ) ;
258 result.append( raw(d.c) ) ;
259 result.append( raw(d.d) ) ;
260 return result ;
261 }
262
263 md5::string_type md5::format::raw( big_t n )
264 {
265 string_type result ;
266 result.reserve( 4U ) ;
267 result.append( 1U , static_cast<char>(n&0xffUL) ) ; n >>= 8U ;
268 result.append( 1U , static_cast<char>(n&0xffUL) ) ; n >>= 8U ;
269 result.append( 1U , static_cast<char>(n&0xffUL) ) ; n >>= 8U ;
270 result.append( 1U , static_cast<char>(n&0xffUL) ) ;
271 return result ;
272 }
273
274 md5::string_type md5::format::rfc( const digest & d )
275 {
276 return rfc( d.state() ) ;
277 }
278
279 md5::string_type md5::format::rfc( const digest::state_type & d )
280 {
281 string_type result ;
282 result.reserve( 32U ) ;
283 result.append( str(d.a) ) ;
284 result.append( str(d.b) ) ;
285 result.append( str(d.c) ) ;
286 result.append( str(d.d) ) ;
287 return result ;
288 }
289
290 md5::string_type md5::format::str( big_t n )
291 {
292 string_type result ;
293 result.reserve( 8U ) ;
294 result.append( str2(n&0xffUL) ) ; n >>= 8U ;
295 result.append( str2(n&0xffUL) ) ; n >>= 8U ;
296 result.append( str2(n&0xffUL) ) ; n >>= 8U ;
297 result.append( str2(n&0xffUL) ) ;
298 return result ;
299 }
300
301 md5::string_type md5::format::str2( small_t n )
302 {
303 return str1((n>>4U)&0xfU) + str1(n&0xfU) ;
304 }
305
306 md5::string_type md5::format::str1( small_t n )
307 {
308 n = n <= 15U ? n : 0U ;
309 const char * map = "0123456789abcdef" ;
310 return string_type( 1U , map[n] ) ;
311 }
312
313 // ===
314
315 md5::block::block( const md5::string_type & s , small_t block , big_t end_value ) :
316 m_s(s) ,
317 m_block(block) ,
318 m_end_value(end_value)
319 {
320 }
321
322 md5::big_t md5::block::end( small_t length )
323 {
324 big_t result = length ;
325 result *= 8UL ;
326 return result ;
327 }
328
329 md5::small_t md5::block::rounded( small_t raw_byte_count )
330 {
331 small_t n = raw_byte_count + 64U ;
332 return n - ( ( raw_byte_count + 8U ) % 64U ) ;
333 }
334
335 md5::small_t md5::block::blocks( small_t raw_byte_count )
336 {
337 small_t byte_count = rounded(raw_byte_count) + 8U ;
338 return byte_count / 64UL ;
339 }
340
341 md5::big_t md5::block::X( small_t dword_index ) const
342 {
343 small_t byte_index = ( m_block * 64U ) + ( dword_index * 4U ) ;
344 big_t result = x( byte_index + 3U ) ;
345 result <<= 8U ; result += x( byte_index + 2U ) ;
346 result <<= 8U ; result += x( byte_index + 1U ) ;
347 result <<= 8U ; result += x( byte_index + 0U ) ;
348 return result ;
349 }
350
351 md5::small_t md5::block::x( small_t i ) const
352 {
353 small_t length = m_s.length() ;
354 if( i < length )
355 {
356 return static_cast<unsigned char>(m_s[i]) ;
357 }
358 else if( i < rounded(length) )
359 {
360 return i == length ? 128U : 0U ;
361 }
362 else
363 {
364 small_t byte_shift = i - rounded(length) ;
365 if( byte_shift >= sizeof(big_t) )
366 {
367 return 0U ;
368 }
369 else
370 {
371 small_t bit_shift = byte_shift * 8U ;
372
373 big_t end_value = m_end_value >> bit_shift ;
374 return static_cast<small_t>( end_value & 0xffUL ) ;
375 }
376 }
377 }
378
379 // ===
380
381 md5::digest_stream::digest_stream() :
382 m_length(0U)
383 {
384 }
385
386 md5::digest_stream::digest_stream( digest::state_type dd , small_t length ) :
387 m_digest(dd) ,
388 m_length(length)
389 {
390 }
391
392 void md5::digest_stream::add( const md5::string_type & s )
393 {
394 m_buffer.append( s ) ;
395 m_length += s.length() ;
396
397 while( m_buffer.length() >= 64U )
398 {
399 block m( m_buffer , 0U , 0UL ) ;
400 m_digest.add( m ) ;
401 m_buffer.erase( 0U , 64U ) ;
402 }
403 }
404
405 void md5::digest_stream::close()
406 {
407 block b( m_buffer , 0U , block::end(m_length) ) ;
408 m_digest.add( b ) ;
409 m_buffer.erase() ;
410 }
411
412 md5::digest_stream::state_type md5::digest_stream::state() const
413 {
414 state_type result ;
415 result.d = m_digest.state() ;
416 result.n = m_length ;
417 result.s = m_buffer ;
418 return result ;
419 }
420
421 md5::small_t md5::digest_stream::size() const
422 {
423 return m_length ;
424 }
425
md5::digest_stream::add
void add(const string_type &)
Adds more message data.
Definition: md5.cpp:392
md5::big_t
size_type big_t
To hold at least 32 bits, maybe more. Try unsigned long on small systems.
Definition: md5.h:44
md5::digest_stream::close
void close()
Called after the last add().
Definition: md5.cpp:405
md5::small_t
size_type small_t
To hold at least a size_t. Must fit in a big_t.
Definition: md5.h:45
md5::digest_stream::state_type::d
digest::state_type d
Definition: md5.h:242
md5::block::X
big_t X(small_t) const
Returns a value from within the block. See RFC 1321.
Definition: md5.cpp:341
md5::digest::state_type::d
big_t d
Definition: md5.h:81
md5::block::block
block(const string_type &s, small_t block_offset, big_t end_value)
Constructor.
Definition: md5.cpp:315
G
Low-level classes.
md5::digest::digest
digest()
Default constructor.
Definition: md5.cpp:35
md5::digest::state_type
Holds the md5 algorithm state. Used by md5::digest.
Definition: md5.h:80
md5::block
A helper class used by the md5::digest implementation to represent a 64-character data block...
Definition: md5.h:167
md5::string_type
std::string string_type
A string type.
Definition: md5.h:42
md5::block::blocks
static small_t blocks(small_t data_length)
Takes the total number of bytes in the input message and returns the number of 64-byte blocks...
Definition: md5.cpp:335
md5::digest
A class that calculates an md5 digest from one or more 64-byte blocks of data using the algorithm des...
Definition: md5.h:77
md5::digest_stream::size
small_t size() const
Returns how many data bytes have been accumulated so far.
Definition: md5.cpp:421
md5::digest::state
state_type state() const
Returns the internal state.
Definition: md5.cpp:48
md5::digest::state_type::a
big_t a
Definition: md5.h:81
md5::digest_stream::state
state_type state() const
Returns the current state.
Definition: md5.cpp:412
md5::block::end
static big_t end(small_t data_length)
Takes the total number of bytes in the input message and returns a value which can be passed to the c...
Definition: md5.cpp:322
md5::digest_stream::digest_stream
digest_stream()
Default constructor.
Definition: md5.cpp:381
md5::format::rfc
static string_type rfc(const digest &)
Returns the digest string in the RFC format.
Definition: md5.cpp:274
md5::digest::state_type::c
big_t c
Definition: md5.h:81
md5::digest::state_type::b
big_t b
Definition: md5.h:81
md5::digest_stream::state_type::s
string_type s
Definition: md5.h:242
md5::digest::add
void add(const block &)
Adds a 64-byte block of the message.
Definition: md5.cpp:73
md5.h
md5::digest_stream::state_type::n
small_t n
Definition: md5.h:242
md5::digest_stream::state_type
< Holds the state of an md5 digest stream. Used by md5::digest_stream.
Definition: md5.h:241
md5::format::raw
static string_type raw(const digest::state_type &)
Returns the raw digest data as a std::string.
Definition: md5.cpp:252