Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
src/md5.cpp
Go to the documentation of this file.
1 /* RFC 1321 compliante MD% implementation
2  *
3  * little-endian optimizations but works on all byte orderings
4  *
5  */
6 
7 #include <xstream/config.h>
8 #include <xstream/digest.h>
9 
10 #include <iosfwd>
11 #include <iomanip>
12 #include <iostream>
13 
14 #include "debug.h"
15 
16 //see md5_t.pl to understand T values
17 
18 #include "md5_t.h"
19 
20 //initial values of digest
21 
22 #define A0 0x01234567
23 #define B0 0x89abcdef
24 #define C0 0xfedcba98
25 #define D0 0x76543210
26 
27 //auxiliary functions
28 
29 static inline uint32_t rotate_left(uint32_t x, unsigned int n)
30 {
31  return ((x << n) | (x >> (32 - n)));
32 }
33 
34 static inline uint32_t F(uint32_t x, uint32_t y, uint32_t z)
35 {
36  return ((x & y) | ((~x) & z));
37 }
38 
39 static inline uint32_t G(uint32_t x, uint32_t y, uint32_t z)
40 {
41  return ((x & z) | (y & (~z)));
42 }
43 
44 static inline uint32_t H(uint32_t x, uint32_t y, uint32_t z)
45 {
46  return (x ^ y ^ z);
47 }
48 
49 static inline uint32_t I(uint32_t x, uint32_t y, uint32_t z)
50 {
51  return (y ^ (x | (~z)));
52 }
53 
54 static const size_t block_size = 16 * /*4 byte words*/ 4;
55 
56 namespace xstream{
57 namespace digest{
58 
59  //this is where the actual digest work is made
60  //buf should be 32*16 bytes long
61  static void process_chunk(
62  uint32_t& AA,
63  uint32_t& BB,
64  uint32_t& CC,
65  uint32_t& DD,
66  char* _buf)
67  {
68  LOG("md5::process_chunk (A,B,C,D) = (" << AA << "," << BB << "," << CC << "," << DD << ")");
69 
70  //hope register is at least tolerated by most compilers
71  register uint32_t A=AA;
72  register uint32_t B=BB;
73  register uint32_t C=CC;
74  register uint32_t D=DD;
75 
76  //needed for endian agnostic copy bellow
77  unsigned char* buf = reinterpret_cast<unsigned char*>(_buf);
78 
79 #if ARCH_LITTLE_ENDIAN
80  //on some systems this can be tricky due to allignment issues
81  //some compiler flags may solve that
82  //if it doesn' work ok, try configure without ARCH_LITTLE_ENDIAN
83  uint32_t* wbuf = reinterpret_cast<uint32_t*>(buf);
84 #else
85  uint32_t wbuf[block_size/4]; //word buffer
86  //we have to copy the words by a byte ordering agnostic procedure
87 
88  for (unsigned int i=0, j=0; i < block_size; i += 4, ++j) {
89  //LOG("\t(i,j) = ("<<i<<","<<j<<")");
90  wbuf[j] = buf[i] + (buf[i+1] << 8) + (buf[i+2] << 16) + (buf[i+3] << 24);
91  }
92 #endif
93 
94  //now that we have the words we process the word buffer
95 
96  //wish I could remove these defines and use templates instead
97 
98 #define BRA(q,w,e,r,k,s,Ti) \
99  q = w + ( rotate_left( q + FUN(w,e,r) + wbuf[k] + Ti, s) );
100 
101 #define FUN F
102 
103  BRA(A, B, C, D, 0, 7, T1);
104  BRA(D, A, B, C, 1, 12, T2);
105  BRA(C, D, A, B, 2, 17, T3);
106  BRA(B, C, D, A, 3, 22, T4);
107  BRA(A, B, C, D, 4, 7, T5);
108  BRA(D, A, B, C, 5, 12, T6);
109  BRA(C, D, A, B, 6, 17, T7);
110  BRA(B, C, D, A, 7, 22, T8);
111  BRA(A, B, C, D, 8, 7, T9);
112  BRA(D, A, B, C, 9, 12, T10);
113  BRA(C, D, A, B, 10, 17, T11);
114  BRA(B, C, D, A, 11, 22, T12);
115  BRA(A, B, C, D, 12, 7, T13);
116  BRA(D, A, B, C, 13, 12, T14);
117  BRA(C, D, A, B, 14, 17, T15);
118  BRA(B, C, D, A, 15, 22, T16);
119 
120 #undef FUN
121 #define FUN G
122 
123  BRA(A, B, C, D, 1, 5, T17);
124  BRA(D, A, B, C, 6, 9, T18);
125  BRA(C, D, A, B, 11, 14, T19);
126  BRA(B, C, D, A, 0, 20, T20);
127  BRA(A, B, C, D, 5, 5, T21);
128  BRA(D, A, B, C, 10, 9, T22);
129  BRA(C, D, A, B, 15, 14, T23);
130  BRA(B, C, D, A, 4, 20, T24);
131  BRA(A, B, C, D, 9, 5, T25);
132  BRA(D, A, B, C, 14, 9, T26);
133  BRA(C, D, A, B, 3, 14, T27);
134  BRA(B, C, D, A, 8, 20, T28);
135  BRA(A, B, C, D, 13, 5, T29);
136  BRA(D, A, B, C, 2, 9, T30);
137  BRA(C, D, A, B, 7, 14, T31);
138  BRA(B, C, D, A, 12, 20, T32);
139 
140 #undef FUN
141 #define FUN H
142 
143  BRA(A, B, C, D, 5, 4, T33);
144  BRA(D, A, B, C, 8, 11, T34);
145  BRA(C, D, A, B, 11, 16, T35);
146  BRA(B, C, D, A, 14, 23, T36);
147  BRA(A, B, C, D, 1, 4, T37);
148  BRA(D, A, B, C, 4, 11, T38);
149  BRA(C, D, A, B, 7, 16, T39);
150  BRA(B, C, D, A, 10, 23, T40);
151  BRA(A, B, C, D, 13, 4, T41);
152  BRA(D, A, B, C, 0, 11, T42);
153  BRA(C, D, A, B, 3, 16, T43);
154  BRA(B, C, D, A, 6, 23, T44);
155  BRA(A, B, C, D, 9, 4, T45);
156  BRA(D, A, B, C, 12, 11, T46);
157  BRA(C, D, A, B, 15, 16, T47);
158  BRA(B, C, D, A, 2, 23, T48);
159 
160 #undef FUN
161 #define FUN I
162 
163  BRA(A, B, C, D, 0, 6, T49);
164  BRA(D, A, B, C, 7, 10, T50);
165  BRA(C, D, A, B, 14, 15, T51);
166  BRA(B, C, D, A, 5, 21, T52);
167  BRA(A, B, C, D, 12, 6, T53);
168  BRA(D, A, B, C, 3, 10, T54);
169  BRA(C, D, A, B, 10, 15, T55);
170  BRA(B, C, D, A, 1, 21, T56);
171  BRA(A, B, C, D, 8, 6, T57);
172  BRA(D, A, B, C, 15, 10, T58);
173  BRA(C, D, A, B, 6, 15, T59);
174  BRA(B, C, D, A, 13, 21, T60);
175  BRA(A, B, C, D, 4, 6, T61);
176  BRA(D, A, B, C, 11, 10, T62);
177  BRA(C, D, A, B, 2, 15, T63);
178  BRA(B, C, D, A, 9, 21, T64);
179 
180  //end of "brackets"
181 
182  LOG("\tchunk values (A,B,C,D) = (" << A << "," << B << "," << C << "," << D << ")");
183 
184  AA += A;
185  BB += B;
186  CC += C;
187  DD += D;
188  }
189 
190  md5::md5()
191  : block_stream(block_size,4)
192  {
193  LOG("digest::md5");
194  reset_digest();
195  }
196 
197  void md5::reset_digest()
198  {
199  LOG("digest::md5::reset_digest");
200  result.a = 0x67452301;
201  result.b = 0xefcdab89;
202  result.c = 0x98badcfe;
203  result.d = 0x10325476;
204  }
205 
206  void md5::calculate_digest()
207  {
208  LOG("digest::md5::calculate_digest");
210  result.a,
211  result.b,
212  result.c,
213  result.d,
214  pbase()
215  );
216  }
217 
218  struct md5::result md5::digest()
219  {
220  LOG("digest::md5::digest");
221  //now for the real deal;
222  pubsync();
223 
224  //cache current digest
225  struct result d = result;
226 
227  const unsigned long int t = taken();
228  const unsigned long int l = length + t;
229  const char* orig = pbase();
230 
231  //I could make this a litle more efficient, but since this only occurs at the end, maybe it's ok
232  char b[block_size * 2];
233 
234  std::copy(orig, orig + t, b);
235 
236  //pad data
237  std::fill(b + t, b + 2 * block_size, '\0');
238  b[t] = 128; //add one bit after data
239 
240  LOG("\ttaken = " << t << "\tlen=" << l);
241 
242  //write size of data
243  unsigned long int ll = l * 8; //length in bits not bytes
244  char* const end = (b + block_size - 8) + (t >= block_size - 8 ? block_size : 0);
245  LOG("\tend-b = " << (end - b));
246 
247  for (int i=0; i < 8; ++i){
248  end[i] = ll & ((1 << 8) - 1);
249  ll >>= 8;
250  }
251 
252  LOG("\tprocessing chunks");
253  for(char* ptr=b; ptr < end; ptr += block_size) {
254  LOG("\tend-ptr = " << (end - ptr));
255  process_chunk(d.a, d.b, d.c, d.d, ptr);
256  }
257  return d;
258  }
259 
260  struct md5::result md5::reset()
261  {
262  LOG("digest::md5::reset");
263  struct result r = digest();
264  reset_digest();
265  return r;
266  }
267 
268  static void print_hex(std::ostream& o, uint32_t n)
269  {
270  for (int i=0; i < 4; ++i) {
271  o.width(2);
272  o.fill('0');
273  o << (n & ((1 << 8) - 1));
274  n >>= 8;
275  }
276  }
277 
278  std::ostream& operator<<(std::ostream& o, const struct md5::result& r)
279  {
280  std::ios::fmtflags orig = o.flags();
281  o.setf(std::ios::hex, std::ios::basefield);
282 
283  print_hex(o, r.a);
284  print_hex(o, r.b);
285  print_hex(o, r.c);
286  print_hex(o, r.d);
287 
288  o.flags(orig);
289 
290  return o;
291  }
292 
293  }//namespace digest
294 }//namespace xstream
#define T57
Definition: md5_t.h:57
Double_t T5(Double_t x)
Definition: chebyshev_fit.C:8
Double_t T1(Double_t x)
Definition: chebyshev_fit.C:4
#define T56
Definition: md5_t.h:56
#define T46
Definition: md5_t.h:46
#define T62
Definition: md5_t.h:62
debugging/logging support
#define T20
Definition: md5_t.h:20
Double_t x[NCHANNELS]
Definition: st_tw_resols.C:39
#define T32
Definition: md5_t.h:32
#define T12
Definition: md5_t.h:12
#define T10
Definition: md5_t.h:10
static uint32_t I(uint32_t x, uint32_t y, uint32_t z)
Definition: src/md5.cpp:49
#define y
#define T61
Definition: md5_t.h:61
#define T44
Definition: md5_t.h:44
C++ objects to calculate digests of data.
Double_t T6(Double_t x)
Definition: chebyshev_fit.C:9
#define T17
Definition: md5_t.h:17
Double_t T2(Double_t x)
Definition: chebyshev_fit.C:5
#define T19
Definition: md5_t.h:19
#define T30
Definition: md5_t.h:30
#define T21
Definition: md5_t.h:21
#define T59
Definition: md5_t.h:59
#define T18
Definition: md5_t.h:18
#define T49
Definition: md5_t.h:49
#define T35
Definition: md5_t.h:35
#define T50
Definition: md5_t.h:50
#define T13
Definition: md5_t.h:13
#define T55
Definition: md5_t.h:55
#define T29
Definition: md5_t.h:29
Double_t T3(Double_t x)
Definition: chebyshev_fit.C:6
#define T40
Definition: md5_t.h:40
#define T58
Definition: md5_t.h:58
static void process_chunk(uint32_t &AA, uint32_t &BB, uint32_t &CC, uint32_t &DD, char *_buf)
Definition: src/md5.cpp:61
static void print_hex(std::ostream &o, uint32_t n)
Definition: src/md5.cpp:268
#define T31
Definition: md5_t.h:31
#define BRA(q, w, e, r, k, s, Ti)
#define T38
Definition: md5_t.h:38
#define T43
Definition: md5_t.h:43
#define T53
Definition: md5_t.h:53
#define T41
Definition: md5_t.h:41
#define T45
Definition: md5_t.h:45
#define T52
Definition: md5_t.h:52
static uint32_t G(uint32_t x, uint32_t y, uint32_t z)
Definition: src/md5.cpp:39
#define T28
Definition: md5_t.h:28
#define T11
Definition: md5_t.h:11
#define T25
Definition: md5_t.h:25
#define T54
Definition: md5_t.h:54
static uint32_t F(uint32_t x, uint32_t y, uint32_t z)
Definition: src/md5.cpp:34
#define T60
Definition: md5_t.h:60
#define T15
Definition: md5_t.h:15
#define T64
Definition: md5_t.h:64
#define T26
Definition: md5_t.h:26
static uint32_t rotate_left(uint32_t x, unsigned int n)
Definition: src/md5.cpp:29
std::ostream & operator<<(std::ostream &o, const struct md5::result &m)
Definition: src/md5.cpp:278
#define T22
Definition: md5_t.h:22
#define T16
Definition: md5_t.h:16
#define T24
Definition: md5_t.h:24
Double_t T8(Double_t x)
Definition: chebyshev_fit.C:11
Double_t T9(Double_t x)
Definition: chebyshev_fit.C:12
static const size_t block_size
Definition: src/md5.cpp:54
static uint32_t H(uint32_t x, uint32_t y, uint32_t z)
Definition: src/md5.cpp:44
#define T36
Definition: md5_t.h:36
#define T33
Definition: md5_t.h:33
#define T42
Definition: md5_t.h:42
#define T63
Definition: md5_t.h:63
#define T51
Definition: md5_t.h:51
#define T48
Definition: md5_t.h:48
Double_t T4(Double_t x)
Definition: chebyshev_fit.C:7
#define T23
Definition: md5_t.h:23
#define LOG(s)
Definition: debug.h:30
#define T14
Definition: md5_t.h:14
#define T39
Definition: md5_t.h:39
#define T34
Definition: md5_t.h:34
#define T47
Definition: md5_t.h:47
#define T27
Definition: md5_t.h:27
static double DD[5]
Double_t T7(Double_t x)
Definition: chebyshev_fit.C:10
#define T37
Definition: md5_t.h:37