summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/md5.cpp293
-rw-r--r--src/md5.h13
-rw-r--r--src/unit/md5.unit82
3 files changed, 270 insertions, 118 deletions
diff --git a/src/md5.cpp b/src/md5.cpp
index 46ee769..a1345ce 100644
--- a/src/md5.cpp
+++ b/src/md5.cpp
@@ -11,9 +11,11 @@
11#include "bu/md5.h" 11#include "bu/md5.h"
12#include "bu/stream.h" 12#include "bu/stream.h"
13 13
14 14#ifdef SYSTEM_BIG_ENDIAN
15// This performs a wrapping bitwise shift, kinda' fun! 15# define toLittleEndian( a, b ) _toLittleEndian( a, b )
16#define bitRoll( val, amnt ) ((val<<(amnt)) | (val>>(32-(amnt)))) 16#else
17# define toLittleEndian( a, b ) (void)0
18#endif
17 19
18Bu::Md5::Md5() 20Bu::Md5::Md5()
19{ 21{
@@ -33,9 +35,8 @@ void Bu::Md5::reset()
33 sum[2] = 0x98BADCFEU; 35 sum[2] = 0x98BADCFEU;
34 sum[3] = 0x10325476U; 36 sum[3] = 0x10325476U;
35 37
36 iBytes = 0; 38 uBits[0] = 0;
37 memset( inbuf, 0, 4*16 ); 39 uBits[1] = 0;
38 iFill = 0;
39} 40}
40 41
41void Bu::Md5::setSalt( const Bu::FString & /*sSalt*/ ) 42void Bu::Md5::setSalt( const Bu::FString & /*sSalt*/ )
@@ -45,137 +46,201 @@ void Bu::Md5::setSalt( const Bu::FString & /*sSalt*/ )
45void Bu::Md5::addData( const void *sVData, int iSize ) 46void Bu::Md5::addData( const void *sVData, int iSize )
46{ 47{
47 const char *sData = (const char *)sVData; 48 const char *sData = (const char *)sVData;
49 uint32_t t;
50
51 t = uBits[0];
52 if( (uBits[0] = t + ((uint32_t)iSize << 3)) < t )
53 uBits[1]++;
54 uBits[1] += iSize >> 29;
55
56 t = (t >> 3) & 0x3f; /* How many bytes we have buffered */
48 57
49 int iInPos = 0; 58 /* Handle any leading odd-sized chunks */
50 for(;;) 59 if( t )
51 { 60 {
52 for( ; iFill < 16*4 && iInPos < iSize; iFill++, iInPos++ ) 61 unsigned char *p = (unsigned char *) inbuf + t;
53 { 62
54 inbuf[iFill>>2] |= ((long)sData[iInPos]) << ((iFill*8)%32); 63 t = 64 - t;
64 if( iSize < t ) {
65 memcpy( p, sData, iSize );
66 return;
55 } 67 }
56 if( iFill < 16*4 ) 68 memcpy( p, sData, t );
57 break; 69 toLittleEndian( inbuf, 16 );
58 compBlock( inbuf, sum ); 70 compBlock( sum, (uint32_t *)inbuf );
59 memset( inbuf, 0, 4*16 ); 71 sData += t;
60 iFill = 0; 72 iSize -= t;
61 } 73 }
62 iBytes += iSize; 74
75 /* Process data in 64-byte chunks */
76 while( iSize >= 64 )
77 {
78 memcpy( inbuf, sData, 64 );
79 toLittleEndian( inbuf, 16 );
80 compBlock( sum, (uint32_t *)inbuf );
81 sData += 64;
82 iSize -= 64;
83 }
84
85 /* Handle any remaining bytes of data. */
86 memcpy( inbuf, sData, iSize );
63} 87}
64 88
65Bu::FString Bu::Md5::getResult() 89Bu::FString Bu::Md5::getResult()
66{ 90{
67 long lsum[4]; 91 uint32_t lsum[4];
68 compCap( lsum ); 92 compCap( lsum );
69 return Bu::FString( (const char *)lsum, 4*4 ); 93 return Bu::FString( (const char *)lsum, 4*4 );
70} 94}
71 95
72void Bu::Md5::writeResult( Bu::Stream &sOut ) 96void Bu::Md5::writeResult( Bu::Stream &sOut )
73{ 97{
74 long lsum[4]; 98 uint32_t lsum[4];
75 compCap( lsum ); 99 compCap( lsum );
76 sOut.write( lsum, 4*4 ); 100 sOut.write( lsum, 4*4 );
77} 101}
78 102
79void Bu::Md5::compCap( long *sumout ) 103void Bu::Md5::compCap( uint32_t *sumout )
80{ 104{
105 uint8_t tmpbuf[64];
81 memcpy( sumout, sum, 4*4 ); 106 memcpy( sumout, sum, 4*4 );
82 long lbuf[16]; 107 memcpy( tmpbuf, inbuf, 64 );
83 memcpy( lbuf, inbuf, 4*16 ); 108
84 109 uint32_t count;
85 lbuf[iFill>>2] |= 0x80 << ((iFill*8)%32); 110 uint8_t *p;
86 uint64_t iBits = iBytes*8; 111
87 if( iBytes > 0 && iFill>>2 >= 14 ) 112 /* Compute number of bytes mod 64 */
88 { 113 count = (uBits[0] >> 3) & 0x3F;
89 compBlock( lbuf, sumout ); 114
90 memset( lbuf, 0, 4*16 ); 115 /* Set the first char of padding to 0x80. This is safe since there is
91 memcpy( lbuf+14, &iBits, 8 ); 116 always at least one byte free */
92 compBlock( lbuf, sumout ); 117 p = tmpbuf + count;
93 } 118 *p++ = 0x80;
94 else 119
95 { 120 /* Bytes of padding needed to make 64 bytes */
96 memcpy( lbuf+14, &iBits, 8 ); 121 count = 64 - 1 - count;
97 compBlock( lbuf, sumout ); 122
123 /* Pad out to 56 mod 64 */
124 if (count < 8) {
125 /* Two lots of padding: Pad the first block to 64 bytes */
126 memset( p, 0, count );
127 toLittleEndian( tmpbuf, 16 );
128 compBlock( sumout, (uint32_t *)tmpbuf );
129
130 /* Now fill the next block with 56 bytes */
131 memset( tmpbuf, 0, 56);
132 } else {
133 /* Pad block to 56 bytes */
134 memset( p, 0, count - 8);
98 } 135 }
136 toLittleEndian( tmpbuf, 14 );
137
138 /* Append length in bits and transform */
139 ((uint32_t *) tmpbuf)[14] = uBits[0];
140 ((uint32_t *) tmpbuf)[15] = uBits[1];
141
142 compBlock( sumout, (uint32_t *)tmpbuf );
143 toLittleEndian((unsigned char *)sumout, 4);
99} 144}
100 145
101void Bu::Md5::compBlock( long *x, long *lsum ) 146#define F1(x, y, z) (z ^ (x & (y ^ z)))
147#define F2(x, y, z) F1(z, x, y)
148#define F3(x, y, z) (x ^ y ^ z)
149#define F4(x, y, z) (y ^ (x | ~z))
150
151/* This is the central step in the MD5 algorithm. */
152#define MD5STEP(f, w, x, y, z, data, s) \
153 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
154
155void Bu::Md5::compBlock( uint32_t *lsum, uint32_t *x )
102{ 156{
103 long a = lsum[0]; 157 register uint32_t a, b, c, d;
104 long b = lsum[1]; 158 a = lsum[0];
105 long c = lsum[2]; 159 b = lsum[1];
106 long d = lsum[3]; 160 c = lsum[2];
107 161 d = lsum[3];
108 a = md5_ff(a, b, c, d, x[ 0], 7 , -680876936); 162
109 d = md5_ff(d, a, b, c, x[ 1], 12, -389564586); 163 MD5STEP(F1, a, b, c, d, x[0] + 0xd76aa478, 7);
110 c = md5_ff(c, d, a, b, x[ 2], 17, 606105819); 164 MD5STEP(F1, d, a, b, c, x[1] + 0xe8c7b756, 12);
111 b = md5_ff(b, c, d, a, x[ 3], 22, -1044525330); 165 MD5STEP(F1, c, d, a, b, x[2] + 0x242070db, 17);
112 a = md5_ff(a, b, c, d, x[ 4], 7 , -176418897); 166 MD5STEP(F1, b, c, d, a, x[3] + 0xc1bdceee, 22);
113 d = md5_ff(d, a, b, c, x[ 5], 12, 1200080426); 167 MD5STEP(F1, a, b, c, d, x[4] + 0xf57c0faf, 7);
114 c = md5_ff(c, d, a, b, x[ 6], 17, -1473231341); 168 MD5STEP(F1, d, a, b, c, x[5] + 0x4787c62a, 12);
115 b = md5_ff(b, c, d, a, x[ 7], 22, -45705983); 169 MD5STEP(F1, c, d, a, b, x[6] + 0xa8304613, 17);
116 a = md5_ff(a, b, c, d, x[ 8], 7 , 1770035416); 170 MD5STEP(F1, b, c, d, a, x[7] + 0xfd469501, 22);
117 d = md5_ff(d, a, b, c, x[ 9], 12, -1958414417); 171 MD5STEP(F1, a, b, c, d, x[8] + 0x698098d8, 7);
118 c = md5_ff(c, d, a, b, x[10], 17, -42063); 172 MD5STEP(F1, d, a, b, c, x[9] + 0x8b44f7af, 12);
119 b = md5_ff(b, c, d, a, x[11], 22, -1990404162); 173 MD5STEP(F1, c, d, a, b, x[10] + 0xffff5bb1, 17);
120 a = md5_ff(a, b, c, d, x[12], 7 , 1804603682); 174 MD5STEP(F1, b, c, d, a, x[11] + 0x895cd7be, 22);
121 d = md5_ff(d, a, b, c, x[13], 12, -40341101); 175 MD5STEP(F1, a, b, c, d, x[12] + 0x6b901122, 7);
122 c = md5_ff(c, d, a, b, x[14], 17, -1502002290); 176 MD5STEP(F1, d, a, b, c, x[13] + 0xfd987193, 12);
123 b = md5_ff(b, c, d, a, x[15], 22, 1236535329); 177 MD5STEP(F1, c, d, a, b, x[14] + 0xa679438e, 17);
124 178 MD5STEP(F1, b, c, d, a, x[15] + 0x49b40821, 22);
125 a = md5_gg(a, b, c, d, x[ 1], 5 , -165796510); 179
126 d = md5_gg(d, a, b, c, x[ 6], 9 , -1069501632); 180 MD5STEP(F2, a, b, c, d, x[1] + 0xf61e2562, 5);
127 c = md5_gg(c, d, a, b, x[11], 14, 643717713); 181 MD5STEP(F2, d, a, b, c, x[6] + 0xc040b340, 9);
128 b = md5_gg(b, c, d, a, x[ 0], 20, -373897302); 182 MD5STEP(F2, c, d, a, b, x[11] + 0x265e5a51, 14);
129 a = md5_gg(a, b, c, d, x[ 5], 5 , -701558691); 183 MD5STEP(F2, b, c, d, a, x[0] + 0xe9b6c7aa, 20);
130 d = md5_gg(d, a, b, c, x[10], 9 , 38016083); 184 MD5STEP(F2, a, b, c, d, x[5] + 0xd62f105d, 5);
131 c = md5_gg(c, d, a, b, x[15], 14, -660478335); 185 MD5STEP(F2, d, a, b, c, x[10] + 0x02441453, 9);
132 b = md5_gg(b, c, d, a, x[ 4], 20, -405537848); 186 MD5STEP(F2, c, d, a, b, x[15] + 0xd8a1e681, 14);
133 a = md5_gg(a, b, c, d, x[ 9], 5 , 568446438); 187 MD5STEP(F2, b, c, d, a, x[4] + 0xe7d3fbc8, 20);
134 d = md5_gg(d, a, b, c, x[14], 9 , -1019803690); 188 MD5STEP(F2, a, b, c, d, x[9] + 0x21e1cde6, 5);
135 c = md5_gg(c, d, a, b, x[ 3], 14, -187363961); 189 MD5STEP(F2, d, a, b, c, x[14] + 0xc33707d6, 9);
136 b = md5_gg(b, c, d, a, x[ 8], 20, 1163531501); 190 MD5STEP(F2, c, d, a, b, x[3] + 0xf4d50d87, 14);
137 a = md5_gg(a, b, c, d, x[13], 5 , -1444681467); 191 MD5STEP(F2, b, c, d, a, x[8] + 0x455a14ed, 20);
138 d = md5_gg(d, a, b, c, x[ 2], 9 , -51403784); 192 MD5STEP(F2, a, b, c, d, x[13] + 0xa9e3e905, 5);
139 c = md5_gg(c, d, a, b, x[ 7], 14, 1735328473); 193 MD5STEP(F2, d, a, b, c, x[2] + 0xfcefa3f8, 9);
140 b = md5_gg(b, c, d, a, x[12], 20, -1926607734); 194 MD5STEP(F2, c, d, a, b, x[7] + 0x676f02d9, 14);
141 195 MD5STEP(F2, b, c, d, a, x[12] + 0x8d2a4c8a, 20);
142 a = md5_hh(a, b, c, d, x[ 5], 4 , -378558); 196
143 d = md5_hh(d, a, b, c, x[ 8], 11, -2022574463); 197 MD5STEP(F3, a, b, c, d, x[5] + 0xfffa3942, 4);
144 c = md5_hh(c, d, a, b, x[11], 16, 1839030562); 198 MD5STEP(F3, d, a, b, c, x[8] + 0x8771f681, 11);
145 b = md5_hh(b, c, d, a, x[14], 23, -35309556); 199 MD5STEP(F3, c, d, a, b, x[11] + 0x6d9d6122, 16);
146 a = md5_hh(a, b, c, d, x[ 1], 4 , -1530992060); 200 MD5STEP(F3, b, c, d, a, x[14] + 0xfde5380c, 23);
147 d = md5_hh(d, a, b, c, x[ 4], 11, 1272893353); 201 MD5STEP(F3, a, b, c, d, x[1] + 0xa4beea44, 4);
148 c = md5_hh(c, d, a, b, x[ 7], 16, -155497632); 202 MD5STEP(F3, d, a, b, c, x[4] + 0x4bdecfa9, 11);
149 b = md5_hh(b, c, d, a, x[10], 23, -1094730640); 203 MD5STEP(F3, c, d, a, b, x[7] + 0xf6bb4b60, 16);
150 a = md5_hh(a, b, c, d, x[13], 4 , 681279174); 204 MD5STEP(F3, b, c, d, a, x[10] + 0xbebfbc70, 23);
151 d = md5_hh(d, a, b, c, x[ 0], 11, -358537222); 205 MD5STEP(F3, a, b, c, d, x[13] + 0x289b7ec6, 4);
152 c = md5_hh(c, d, a, b, x[ 3], 16, -722521979); 206 MD5STEP(F3, d, a, b, c, x[0] + 0xeaa127fa, 11);
153 b = md5_hh(b, c, d, a, x[ 6], 23, 76029189); 207 MD5STEP(F3, c, d, a, b, x[3] + 0xd4ef3085, 16);
154 a = md5_hh(a, b, c, d, x[ 9], 4 , -640364487); 208 MD5STEP(F3, b, c, d, a, x[6] + 0x04881d05, 23);
155 d = md5_hh(d, a, b, c, x[12], 11, -421815835); 209 MD5STEP(F3, a, b, c, d, x[9] + 0xd9d4d039, 4);
156 c = md5_hh(c, d, a, b, x[15], 16, 530742520); 210 MD5STEP(F3, d, a, b, c, x[12] + 0xe6db99e5, 11);
157 b = md5_hh(b, c, d, a, x[ 2], 23, -995338651); 211 MD5STEP(F3, c, d, a, b, x[15] + 0x1fa27cf8, 16);
158 212 MD5STEP(F3, b, c, d, a, x[2] + 0xc4ac5665, 23);
159 a = md5_ii(a, b, c, d, x[ 0], 6 , -198630844); 213
160 d = md5_ii(d, a, b, c, x[ 7], 10, 1126891415); 214 MD5STEP(F4, a, b, c, d, x[0] + 0xf4292244, 6);
161 c = md5_ii(c, d, a, b, x[14], 15, -1416354905); 215 MD5STEP(F4, d, a, b, c, x[7] + 0x432aff97, 10);
162 b = md5_ii(b, c, d, a, x[ 5], 21, -57434055); 216 MD5STEP(F4, c, d, a, b, x[14] + 0xab9423a7, 15);
163 a = md5_ii(a, b, c, d, x[12], 6 , 1700485571); 217 MD5STEP(F4, b, c, d, a, x[5] + 0xfc93a039, 21);
164 d = md5_ii(d, a, b, c, x[ 3], 10, -1894986606); 218 MD5STEP(F4, a, b, c, d, x[12] + 0x655b59c3, 6);
165 c = md5_ii(c, d, a, b, x[10], 15, -1051523); 219 MD5STEP(F4, d, a, b, c, x[3] + 0x8f0ccc92, 10);
166 b = md5_ii(b, c, d, a, x[ 1], 21, -2054922799); 220 MD5STEP(F4, c, d, a, b, x[10] + 0xffeff47d, 15);
167 a = md5_ii(a, b, c, d, x[ 8], 6 , 1873313359); 221 MD5STEP(F4, b, c, d, a, x[1] + 0x85845dd1, 21);
168 d = md5_ii(d, a, b, c, x[15], 10, -30611744); 222 MD5STEP(F4, a, b, c, d, x[8] + 0x6fa87e4f, 6);
169 c = md5_ii(c, d, a, b, x[ 6], 15, -1560198380); 223 MD5STEP(F4, d, a, b, c, x[15] + 0xfe2ce6e0, 10);
170 b = md5_ii(b, c, d, a, x[13], 21, 1309151649); 224 MD5STEP(F4, c, d, a, b, x[6] + 0xa3014314, 15);
171 a = md5_ii(a, b, c, d, x[ 4], 6 , -145523070); 225 MD5STEP(F4, b, c, d, a, x[13] + 0x4e0811a1, 21);
172 d = md5_ii(d, a, b, c, x[11], 10, -1120210379); 226 MD5STEP(F4, a, b, c, d, x[4] + 0xf7537e82, 6);
173 c = md5_ii(c, d, a, b, x[ 2], 15, 718787259); 227 MD5STEP(F4, d, a, b, c, x[11] + 0xbd3af235, 10);
174 b = md5_ii(b, c, d, a, x[ 9], 21, -343485551); 228 MD5STEP(F4, c, d, a, b, x[2] + 0x2ad7d2bb, 15);
175 229 MD5STEP(F4, b, c, d, a, x[9] + 0xeb86d391, 21);
176 lsum[0] = a + lsum[0]; 230
177 lsum[1] = b + lsum[1]; 231 lsum[0] += a;
178 lsum[2] = c + lsum[2]; 232 lsum[1] += b;
179 lsum[3] = d + lsum[3]; 233 lsum[2] += c;
234 lsum[3] += d;
180} 235}
181 236
237void Bu::Md5::_toLittleEndian( uint8_t *buf, uint32_t count )
238{
239 uint32_t t;
240 do {
241 t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
242 ((unsigned) buf[1] << 8 | buf[0]);
243 *(uint32_t *) buf = t;
244 buf += 4;
245 } while( --count );
246}
diff --git a/src/md5.h b/src/md5.h
index 0be65fd..60992ac 100644
--- a/src/md5.h
+++ b/src/md5.h
@@ -14,6 +14,8 @@ namespace Bu
14{ 14{
15 /** 15 /**
16 * Class for easily calculating MD5 sums of just about any data. 16 * Class for easily calculating MD5 sums of just about any data.
17 * This code is based on some public domain code written by Colin Plumb in
18 * 1993.
17 *@author Mike Buland 19 *@author Mike Buland
18 */ 20 */
19 class Md5 : public Bu::CryptoHash 21 class Md5 : public Bu::CryptoHash
@@ -36,13 +38,16 @@ namespace Bu
36 /** 38 /**
37 * Compute one block of input data. 39 * Compute one block of input data.
38 */ 40 */
39 void compBlock( long *x, uint32_t *lsum ); 41 void compBlock( uint32_t *lsum, uint32_t *x );
40 void compCap( uint32_t *sumout ); 42 void compCap( uint32_t *sumout );
43
44 void _addData( uint8_t *target, int &iCurFill, const void *sData,
45 int iSize );
46 void _toLittleEndian( uint8_t *buf, uint32_t count );
41 47
42 uint32_t inbuf[16]; 48 uint8_t inbuf[64];
43 uint32_t iFill;
44 uint32_t sum[4]; 49 uint32_t sum[4];
45 uint64_t iBytes; 50 uint32_t uBits[2];
46 }; 51 };
47}; 52};
48 53
diff --git a/src/unit/md5.unit b/src/unit/md5.unit
new file mode 100644
index 0000000..248aaaf
--- /dev/null
+++ b/src/unit/md5.unit
@@ -0,0 +1,82 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2010 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/md5.h"
10
11#include <stdlib.h>
12
13suite Md5
14{
15 test basics
16 {
17#define tryStr( a, b ) \
18 { Bu::Md5 m; m.addData(a); unitTest( m.getHexResult() == b ); } (void)0
19 tryStr("", "d41d8cd98f00b204e9800998ecf8427e");
20 tryStr("a", "0cc175b9c0f1b6a831c399e269772661");
21 tryStr("abc", "900150983cd24fb0d6963f7d28e17f72");
22 tryStr("message digest", "f96b697d7cb7938d525a2f31aaf161d0");
23 tryStr("abcdefghijklmnopqrstuvwxyz",
24 "c3fcd3d76192e4007dfb496cca67e13b");
25 tryStr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
26 "d174ab98d277d9f5a5611c2c9f419d9f");
27 tryStr("12345678901234567890123456789012345"
28 "678901234567890123456789012345678901234567890",
29 "57edf4a22be3c955ac49da2e2107b67a");
30 }
31
32 test twoChunks
33 {
34 Bu::Md5 m;
35 m.addData("12345678901234567890123456789012345");
36 m.addData("678901234567890123456789012345678901234567890");
37 unitTest( m.getHexResult() == "57edf4a22be3c955ac49da2e2107b67a" );
38 }
39
40 test biggerBlocks
41 {
42 const char *sums[33] = {
43 "75fcf199abe516903321095a588b938d",
44 "e26a863c96d6bdba6601175aedaae108",
45 "2b207fdcb222078d3ebfeb8d5e7c9315",
46 "b08683aaa465add72cc2b43ae42f4f70",
47 "638bb73963b2d925771c3579ccb5e879",
48 "c727bd4b48a88e3df5924a2604de0790",
49 "f33d21203c80490f7342e5853c5550eb",
50 "db449faca66a177aae59b1e36a19d053",
51 "c800d429afb5f5c820f75c2c94e2e2bb",
52 "43b79c70b9a6a11e823ffbfa0f45a4db",
53 "0177ffc483cf598ae3966b3a5ae00c8c",
54 "1a68fdf4b17a3820d48d101e9355a818"
55 };
56
57 char block[128];
58 for( int i = 0; i < 128; i++ )
59 block[i] = i*2;
60
61 const char **curSum = sums;
62 for( int j = 1; j < 4096; j*=2 )
63 {
64 /*
65 Bu::File fOut("temp", Bu::File::WriteNew );
66 for( int b = 0; b < j; b++ )
67 {
68 fOut.write( block, 128 );
69 }
70 fOut.close();
71 system("md5sum -b temp");
72 */
73 Bu::Md5 m;
74 for( int b = 0; b < j; b++ )
75 {
76 m.addData( block, 128 );
77 }
78 unitTest( m.getHexResult() == *curSum );
79 curSum++;
80 }
81 }
82}