KerMor  0.9
Model order reduction for nonlinear dynamical systems and nonlinear approximation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
CalcMD5.c
Go to the documentation of this file.
1 // CalcMD5.c
2 // 128 bit MD5 checksum: file, string, byte stream
3 // This function calculates a 128 bit checksum for arrays or files.
4 // Digest = CalcMD5(Data, [InClass], [OutClass])
5 // INPUT:
6 // Data: Data array or file name. Either numerical or CHAR array.
7 // Currently only files and arrays with up to 2^32 bytes (2.1GB) are
8 // accepted.
9 // InClass: String to declare the type of the 1st input.
10 // Optional. Default: 'Char'.
11 // 'File': [Data] is a file name as string. The digest is calculated
12 // for this file.
13 // 'Char': [Data] is a char array to calculate the digest for. Only the
14 // ASCII part of the Matlab CHARs is used, such that the digest
15 // is the same as if the Matlab string is written to a file as
16 // UCHAR, e.g. with FWRITE.
17 // 'Unicode': All bytes of the input [Data] are used to calculate the
18 // digest. If [Data] has a numerical type, this method is
19 // applied ever.
20 // OutClass: String, format of the output. Just the first character matters.
21 // Optional, default: 'hex'.
22 // 'hex': [1 x 32] string as lowercase hexadecimal number.
23 // 'HEX': [1 x 32] string as lowercase hexadecimal number.
24 // 'Dec': [1 x 16] double vector with UINT8 values.
25 // 'Base64': [1 x 22] string, encoded to base 64 (A:Z,a:z,0:9,+,/).
26 //
27 // OUTPUT:
28 // Digest: A 128 bit number is replied in a format depending on [OutClass].
29 //
30 // EXAMPLES:
31 // Three methods to get the MD5 of a file:
32 // 1. Direct file access (recommended):
33 // MD5 = CalcMD5(which('CalcMD5.m'), 'File')
34 // 2. Import the file to a CHAR array (binary mode for exact line breaks!):
35 // FID = fopen(which('CalcMD5.m'), 'rb');
36 // S = fread(FID, inf, 'uchar=>char');
37 // fclose(FID);
38 // MD5 = CalcMD5(S, 'char')
39 // 3. Import file as a byte stream:
40 // FID = fopen(which('CalcMD5.m'), 'rb');
41 // S = fread(FID, inf, 'uint8=>uint8');
42 // fclose(FID);
43 // MD5 = CalcMD5(S, 'unicode'); // 'unicode' can be omitted here
44 //
45 // Test data:
46 // CalcMD5(char(0:511), 'char', 'HEX')
47 // => F5C8E3C31C044BAE0E65569560B54332
48 // CalcMD5(char(0:511), 'unicode')
49 // => 3484769D4F7EBB88BBE942BB924834CD
50 //
51 // Compile with:
52 // mex -O CalcMD5.c
53 // On Linux the C99 comments must be considered (thanks Sebastiaan Breedveld):
54 // mex -O CFLAGS="\$CFLAGS -std=C99" CalcMD5.c
55 //
56 // Tested: Matlab 6.5, 7.7, 7.8, WinXP, [UnitTest]
57 // Compiler: BCC5.5, LCC2.4/3.8, OpenWatcom 1.8
58 // Author: Jan Simon, Heidelberg, (C) 2006-2010 J@n-Simon.De
59 // License: BSD. This program is based on:
60 // RFC 1321, MD5 Message-Digest Algorithm, April 1992
61 // RSA Data Security, Inc. MD5 Message Digest Algorithm
62 // Modifications:
63 // - Acceleration: Unrolled loops. Compacted macros FF, GG, HH, II.
64 // - Mex-interface: Input and output from and to Matlab.
65 //
66 // See also: CalcCRC32.
67 //
68 // Michael Kleder has published a Java call to compute the MD5 and SHA sums:
69 // http://www.mathworks.com/matlabcentral/fileexchange/8944
70 
71 /**********************************************************************
72  ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
73  ** **
74  ** License to copy and use this software is granted provided that **
75  ** it is identified as the "RSA Data Security, Inc. MD5 Message **
76  ** Digest Algorithm" in all material mentioning or referencing this **
77  ** software or this function. **
78  ** **
79  ** License is also granted to make and use derivative works **
80  ** provided that such works are identified as "derived from the RSA **
81  ** Data Security, Inc. MD5 Message Digest Algorithm" in all **
82  ** material mentioning or referencing the derived work. **
83  ** **
84  ** RSA Data Security, Inc. makes no representations concerning **
85  ** either the merchantability of this software or the suitability **
86  ** of this software for any particular purpose. It is provided "as **
87  ** is" without express or implied warranty of any kind. **
88  ** **
89  ** These notices must be retained in any copies of any part of this **
90  ** documentation and/or software. **
91  **********************************************************************
92  */
93 
94 /*
95 % $JRev: R5.00z V:025 Sum:/kHGslMmCpAS Date:17-Dec-2009 12:46:26 $
96 % $File: CalcMD5\CalcMD5.c $
97 % History:
98 % 011: 20-Oct-2006 20:50, [16 x 1] -> [1 x 16] replied as double.
99 % 012: 01-Nov-2006 23:10, BUGFIX: hex output for 'Hex' input now.
100 % 015: 02-Oct-2008 14:47, Base64 output.
101 % 017: 19-Oct-2008 22:33, Accept numerical arrays as byte stream.
102 % 023: 15-Dec-2009 16:53, BUGFIX: UINT32 has 32 bits on 64 bit systems now.
103 % Thanks to Sebastiaan Breedveld!
104 */
105 
106 // Headers:
107 #include <stdlib.h>
108 #include <stdio.h>
109 #include <string.h>
110 #include <ctype.h>
111 #include "mex.h"
112 
113 // Assume 32 bit array dimensions for Matlab 6.5:
114 // See option "compatibleArrayDims" for MEX in Matlab >= 7.7.
115 #ifndef mwSize
116 #define mwSize int
117 #define mwIndex int
118 #endif
119 
120 // Types:
121 typedef unsigned char UCHAR;
122 typedef unsigned int UINT;
123 typedef unsigned char * POINTER; // generic pointer
124 typedef UINT32_T UINT32; // four byte word (defined in tmwtypes.h)
125 
126 typedef struct {
127  UINT32 state[4]; // state (ABCD)
128  UINT32 count[2]; // number of bits, modulo 64 (lsb first)
129  UCHAR buffer[64]; // input buffer
130 } MD5_CTX;
131 
132 // Prototypes:
133 void MD5Init (MD5_CTX *);
134 void MD5Update (MD5_CTX *, UCHAR *, UINT);
135 void MD5Final (UCHAR[16], MD5_CTX *);
136 void MD5Transform(UINT32[4], UCHAR[64]);
137 void MD5Encode (UCHAR *, UINT32 *, UINT);
138 void MD5Array (UCHAR *data, mwSize N, UCHAR digest[16]);
139 void MD5File (char *FileName, UCHAR digest[16]);
140 void MD5Char (mxChar *data, mwSize N, UCHAR digest[16]);
141 void ToHex (const UCHAR In[16], char *Out, int LowerCase);
142 void ToBase64 (const UCHAR In[16], char *Out);
143 
144 // Constants for MD5Transform routine:
145 #define S11 7
146 #define S12 12
147 #define S13 17
148 #define S14 22
149 #define S21 5
150 #define S22 9
151 #define S23 14
152 #define S24 20
153 #define S31 4
154 #define S32 11
155 #define S33 16
156 #define S34 23
157 #define S41 6
158 #define S42 10
159 #define S43 15
160 #define S44 21
161 
162 static UCHAR PADDING[64] = {
163  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
164  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
165  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
166 
167 // F, G, H and I are basic MD5 functions:
168 #define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
169 #define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
170 #define H(x, y, z) ((x) ^ (y) ^ (z))
171 #define I(x, y, z) ((y) ^ ((x) | (~z)))
172 
173 // ROTATE_LEFT rotates x left n bits:
174 // Rotation is separate from addition to prevent recomputation.
175 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
176 
177 // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4:
178 #define FF(a, b, c, d, x, s, ac) { \
179  (a) = ROTATE_LEFT((a) + F((b), (c), (d)) + (x) + (UINT32)(ac), (s)) + (b); }
180 #define GG(a, b, c, d, x, s, ac) { \
181  (a) = ROTATE_LEFT((a) + G((b), (c), (d)) + (x) + (UINT32)(ac), (s)) + (b); }
182 #define HH(a, b, c, d, x, s, ac) { \
183  (a) = ROTATE_LEFT((a) + H((b), (c), (d)) + (x) + (UINT32)(ac), (s)) + (b); }
184 #define II(a, b, c, d, x, s, ac) { \
185  (a) = ROTATE_LEFT((a) + I((b), (c), (d)) + (x) + (UINT32)(ac), (s)) + (b); }
186 
187 // Length of the file buffer (must be < 2^31 for INT conversion):
188 #define BUFFER_LEN 1024
190 
191 // MD5 initialization. Begins an MD5 operation, writing a new context. =========
192 void MD5Init(MD5_CTX *context)
193 {
194  // Load magic initialization constants:
195  context->count[0] = 0;
196  context->count[1] = 0;
197  context->state[0] = 0x67452301;
198  context->state[1] = 0xefcdab89;
199  context->state[2] = 0x98badcfe;
200  context->state[3] = 0x10325476;
201 }
202 
203 // MD5 block update operation. Continues an MD5 message-digest operation,
204 // processing another message block, and updating the context.
205 void MD5Update(MD5_CTX *context, UCHAR *input, UINT inputLen)
206 {
207  UINT index, partLen;
208  int i, inputLenM63;
209 
210  // Compute number of bytes mod 64:
211  index = (UINT)((context->count[0] >> 3) & 0x3F);
212 
213  // Update number of bits:
214  if ((context->count[0] += ((UINT32)inputLen << 3)) < ((UINT32)inputLen << 3)) {
215  context->count[1]++;
216  }
217  context->count[1] += ((UINT32)inputLen >> 29);
218 
219  partLen = 64 - index;
220 
221  // Transform as many times as possible:
222  if (inputLen >= partLen) {
223  memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen);
224  MD5Transform(context->state, context->buffer);
225 
226  inputLenM63 = inputLen - 63;
227  for (i = partLen; i < inputLenM63; i += 64) {
228  MD5Transform(context->state, &input[i]);
229  }
230 
231  // Buffer remaining input: index = 0
232  memcpy((POINTER)&context->buffer[0], (POINTER)&input[i], inputLen - i);
233  } else {
234  // Buffer remaining input: i = 0
235  memcpy((POINTER)&context->buffer[index], (POINTER)input, inputLen);
236  }
237 
238  return;
239 }
240 
241 // Finalize MD5: ===============================================================
242 // Ends an MD5 message-digest operation, writing the message digest and zeroing
243 // the context.
244 void MD5Final(UCHAR digest[16], MD5_CTX *context)
245 {
246  UCHAR bits[8];
247  UINT index, padLen;
248 
249  // Save number of bits:
250  MD5Encode(bits, context->count, 2);
251 
252  // Pad out to 56 mod 64:
253  index = (UINT)((context->count[0] >> 3) & 0x3f);
254  padLen = (index < 56) ? (56 - index) : (120 - index);
255  MD5Update(context, PADDING, padLen);
256 
257  // Append length before padding:
258  MD5Update(context, bits, 8);
259 
260  // Store state in digest:
261  MD5Encode(digest, context->state, 4);
262 
263  // Zero sensitive information:
264  memset((POINTER)context, 0, sizeof(MD5_CTX));
265 }
266 
267 // MD5 basic transformation. Transforms state based on block: ==================
268 void MD5Transform(UINT32 state[4], UCHAR block[64])
269 {
270  UINT32 a = state[0],
271  b = state[1],
272  c = state[2],
273  d = state[3],
274  x[16];
275 
276  // Unroll the loop for speed:
277  // UINT i, j;
278  // for (i = 0, j = 0; j < 64; i++, j += 4) {
279  // x[i] = ((UINT32)block[j]) | (((UINT32)block[j + 1]) << 8) |
280  // (((UINT32)block[j + 2]) << 16) | (((UINT32)block[j + 3]) << 24);
281  // }
282  x[0] = ( (UINT32)block[0]) | (((UINT32)block[1]) << 8) |
283  (((UINT32)block[2]) << 16) | (((UINT32)block[3]) << 24);
284  x[1] = ( (UINT32)block[4]) | (((UINT32)block[5]) << 8) |
285  (((UINT32)block[6]) << 16) | (((UINT32)block[7]) << 24);
286  x[2] = ( (UINT32)block[8]) | (((UINT32)block[9]) << 8) |
287  (((UINT32)block[10]) << 16) | (((UINT32)block[11]) << 24);
288  x[3] = ( (UINT32)block[12]) | (((UINT32)block[13]) << 8) |
289  (((UINT32)block[14]) << 16) | (((UINT32)block[15]) << 24);
290  x[4] = ( (UINT32)block[16]) | (((UINT32)block[17]) << 8) |
291  (((UINT32)block[18]) << 16) | (((UINT32)block[19]) << 24);
292  x[5] = ( (UINT32)block[20]) | (((UINT32)block[21]) << 8) |
293  (((UINT32)block[22]) << 16) | (((UINT32)block[23]) << 24);
294  x[6] = ( (UINT32)block[24]) | (((UINT32)block[25]) << 8) |
295  (((UINT32)block[26]) << 16) | (((UINT32)block[27]) << 24);
296  x[7] = ( (UINT32)block[28]) | (((UINT32)block[29]) << 8) |
297  (((UINT32)block[30]) << 16) | (((UINT32)block[31]) << 24);
298  x[8] = ( (UINT32)block[32]) | (((UINT32)block[33]) << 8) |
299  (((UINT32)block[34]) << 16) | (((UINT32)block[35]) << 24);
300  x[9] = ( (UINT32)block[36]) | (((UINT32)block[37]) << 8) |
301  (((UINT32)block[38]) << 16) | (((UINT32)block[39]) << 24);
302  x[10] = ( (UINT32)block[40]) | (((UINT32)block[41]) << 8) |
303  (((UINT32)block[42]) << 16) | (((UINT32)block[43]) << 24);
304  x[11] = ( (UINT32)block[44]) | (((UINT32)block[45]) << 8) |
305  (((UINT32)block[46]) << 16) | (((UINT32)block[47]) << 24);
306  x[12] = ( (UINT32)block[48]) | (((UINT32)block[49]) << 8) |
307  (((UINT32)block[50]) << 16) | (((UINT32)block[51]) << 24);
308  x[13] = ( (UINT32)block[52]) | (((UINT32)block[53]) << 8) |
309  (((UINT32)block[54]) << 16) | (((UINT32)block[55]) << 24);
310  x[14] = ( (UINT32)block[56]) | (((UINT32)block[57]) << 8) |
311  (((UINT32)block[58]) << 16) | (((UINT32)block[59]) << 24);
312  x[15] = ( (UINT32)block[60]) | (((UINT32)block[61]) << 8) |
313  (((UINT32)block[62]) << 16) | (((UINT32)block[63]) << 24);
314 
315  // Round 1
316  FF(a, b, c, d, x[ 0], S11, 0xd76aa478); // 1
317  FF(d, a, b, c, x[ 1], S12, 0xe8c7b756); // 2
318  FF(c, d, a, b, x[ 2], S13, 0x242070db); // 3
319  FF(b, c, d, a, x[ 3], S14, 0xc1bdceee); // 4
320  FF(a, b, c, d, x[ 4], S11, 0xf57c0faf); // 5
321  FF(d, a, b, c, x[ 5], S12, 0x4787c62a); // 6
322  FF(c, d, a, b, x[ 6], S13, 0xa8304613); // 7
323  FF(b, c, d, a, x[ 7], S14, 0xfd469501); // 8
324  FF(a, b, c, d, x[ 8], S11, 0x698098d8); // 9
325  FF(d, a, b, c, x[ 9], S12, 0x8b44f7af); // 10
326  FF(c, d, a, b, x[10], S13, 0xffff5bb1); // 11
327  FF(b, c, d, a, x[11], S14, 0x895cd7be); // 12
328  FF(a, b, c, d, x[12], S11, 0x6b901122); // 13
329  FF(d, a, b, c, x[13], S12, 0xfd987193); // 14
330  FF(c, d, a, b, x[14], S13, 0xa679438e); // 15
331  FF(b, c, d, a, x[15], S14, 0x49b40821); // 16
332 
333  // Round 2
334  GG(a, b, c, d, x[ 1], S21, 0xf61e2562); // 17
335  GG(d, a, b, c, x[ 6], S22, 0xc040b340); // 18
336  GG(c, d, a, b, x[11], S23, 0x265e5a51); // 19
337  GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); // 20
338  GG(a, b, c, d, x[ 5], S21, 0xd62f105d); // 21
339  GG(d, a, b, c, x[10], S22, 0x2441453); // 22
340  GG(c, d, a, b, x[15], S23, 0xd8a1e681); // 23
341  GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); // 24
342  GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); // 25
343  GG(d, a, b, c, x[14], S22, 0xc33707d6); // 26
344  GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); // 27
345 
346  GG(b, c, d, a, x[ 8], S24, 0x455a14ed); // 28
347  GG(a, b, c, d, x[13], S21, 0xa9e3e905); // 29
348  GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); // 30
349  GG(c, d, a, b, x[ 7], S23, 0x676f02d9); // 31
350  GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); // 32
351 
352  // Round 3
353  HH(a, b, c, d, x[ 5], S31, 0xfffa3942); // 33
354  HH(d, a, b, c, x[ 8], S32, 0x8771f681); // 34
355  HH(c, d, a, b, x[11], S33, 0x6d9d6122); // 35
356  HH(b, c, d, a, x[14], S34, 0xfde5380c); // 36
357  HH(a, b, c, d, x[ 1], S31, 0xa4beea44); // 37
358  HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); // 38
359  HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); // 39
360  HH(b, c, d, a, x[10], S34, 0xbebfbc70); // 40
361  HH(a, b, c, d, x[13], S31, 0x289b7ec6); // 41
362  HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); // 42
363  HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); // 43
364  HH(b, c, d, a, x[ 6], S34, 0x4881d05); // 44
365  HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); // 45
366  HH(d, a, b, c, x[12], S32, 0xe6db99e5); // 46
367  HH(c, d, a, b, x[15], S33, 0x1fa27cf8); // 47
368  HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); // 48
369 
370  // Round 4
371  II(a, b, c, d, x[ 0], S41, 0xf4292244); // 49
372  II(d, a, b, c, x[ 7], S42, 0x432aff97); // 50
373  II(c, d, a, b, x[14], S43, 0xab9423a7); // 51
374  II(b, c, d, a, x[ 5], S44, 0xfc93a039); // 52
375  II(a, b, c, d, x[12], S41, 0x655b59c3); // 53
376  II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); // 54
377  II(c, d, a, b, x[10], S43, 0xffeff47d); // 55
378  II(b, c, d, a, x[ 1], S44, 0x85845dd1); // 56
379  II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); // 57
380  II(d, a, b, c, x[15], S42, 0xfe2ce6e0); // 58
381  II(c, d, a, b, x[ 6], S43, 0xa3014314); // 59
382  II(b, c, d, a, x[13], S44, 0x4e0811a1); // 60
383  II(a, b, c, d, x[ 4], S41, 0xf7537e82); // 61
384  II(d, a, b, c, x[11], S42, 0xbd3af235); // 62
385  II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); // 63
386  II(b, c, d, a, x[ 9], S44, 0xeb86d391); // 64
387 
388  state[0] += a;
389  state[1] += b;
390  state[2] += c;
391  state[3] += d;
392 
393  memset((POINTER)x, 0, sizeof(x));
394 }
395 
396 // Encodes input (UINT32) into output (UCHAR) (length is divided by 4) =========
397 void MD5Encode(UCHAR *output, UINT32 *input, UINT len)
398 {
399  UINT j;
400 
401  for (j = 0; j < len; j++) {
402  *output++ = (UCHAR)( *input & 0xff);
403  *output++ = (UCHAR)((*input >> 8) & 0xff);
404  *output++ = (UCHAR)((*input >> 16) & 0xff);
405  *output++ = (UCHAR)((*input++ >> 24) & 0xff);
406  }
407 }
408 
409 // Calcualte digest: ===========================================================
410 void MD5Char(mxChar *array, mwSize inputLen, UCHAR digest[16])
411 {
412  // Process string: Matlab stores strings as mxChar, which are 2 bytes per
413  // character. This function considers the first byte of each CHAR only, which
414  // is equivalent to calculate the sum after a conversion to a ASCII UCHAR
415  // string.
416  MD5_CTX context;
417  UINT Chunk;
418  UCHAR *bufferP, *bufferEnd = buffer + BUFFER_LEN, *arrayP;
419 
420  // Limit length to 32 bit address, because I cannot test this function
421  // with 64 bit arrays currently (under construction):
422  if (inputLen >> 31 != 0) { // Detect sign-bit if mwSize is int
423  mexErrMsgTxt("*** CalcMD5[mex]: Input > 2^31 byte not handled yet.");
424  }
425 
426  arrayP = (UCHAR *) array; // UCHAR *, not mxChar *!
427 
428  MD5Init(&context);
429 
430  // Copy chunks of input data - only the first byte of each mxChar:
431  Chunk = inputLen / BUFFER_LEN;
432  while (Chunk--) {
433  bufferP = buffer;
434  while (bufferP < bufferEnd) {
435  *bufferP++ = *arrayP;
436  arrayP += 2;
437  }
438 
439  MD5Update(&context, buffer, BUFFER_LEN);
440  }
441 
442  // Last chunk:
443  Chunk = inputLen % BUFFER_LEN;
444  if (Chunk != 0) {
445  bufferEnd = buffer + Chunk;
446  bufferP = buffer;
447  while (bufferP < bufferEnd) {
448  *bufferP++ = *arrayP;
449  arrayP += 2;
450  }
451 
452  MD5Update(&context, buffer, Chunk);
453  }
454 
455  MD5Final(digest, &context);
456 
457  return;
458 }
459 
460 // Array of any type as byte stream: ===========================================
461 void MD5Array(UCHAR *array, mwSize inputLen, UCHAR digest[16])
462 {
463  MD5_CTX context;
464 
465  // Limit length to 32 bit address, because I cannot test this function
466  // with 64 bit arrays currently (under construction):
467  if (inputLen >> 31 != 0) { // Detect sign-bit if mwSize is signed int
468  mexErrMsgTxt("*** CalcMD5[mex]: Input > 2^31 byte not handled yet.");
469  }
470 
471  MD5Init(&context);
472  MD5Update(&context, array, (UINT) inputLen);
473  MD5Final(digest, &context);
474 }
475 
476 // File as byte stream: ========================================================
477 void MD5File(char *filename, UCHAR digest[16])
478 {
479  FILE *FID;
480  MD5_CTX context;
481  int len;
482  UINT32 allLen = 0;
483 
484  // Open the file in binary mode:
485  if ((FID = fopen(filename, "rb")) == NULL) {
486  mexPrintf("*** Error for file: [%s]\n", filename);
487  mexErrMsgTxt("*** CalcMD5[mex]: Cannot open file.");
488  }
489 
490  MD5Init(&context);
491  while ((len = fread(buffer, 1, BUFFER_LEN, FID)) != 0) {
492  // Limit length to 32 bit address, because I cannot test this function
493  // with 64 bit arrays currently (under construction):
494  allLen += len;
495  if (allLen > 2147483647) { // 2^31
496  fclose(FID);
497  mexErrMsgTxt("*** CalcMD5[mex]: Cannot handle files > 2.1GB yet.");
498  }
499 
500  MD5Update(&context, buffer, (UINT) len);
501  }
502  MD5Final(digest, &context);
503 
504  fclose(FID);
505 }
506 
507 // Output of 16 UCHARs as 32 character hexadecimals: ===========================
508 void ToHex(const UCHAR digest[16], char *output, int LowerCase)
509 {
510  char *outputEnd;
511 
512  if (LowerCase) {
513  for (outputEnd = output + 32; output < outputEnd; output += 2) {
514  sprintf(output, "%02x", *(digest++));
515  }
516  } else { // Upper case:
517  for (outputEnd = output + 32; output < outputEnd; output += 2) {
518  sprintf(output, "%02X", *(digest++));
519  }
520  }
521 
522  return;
523 }
524 
525 // BASE64 encoded output: ======================================================
526 void ToBase64(const UCHAR In[16], char *Out)
527 {
528  // The base64 encoded string is shorter than the hex string.
529  // Needed length: ((len + 2) / 3 * 4) + 1, here fixed to 22+1 here (trailing
530  // 0 included).
531  static const UCHAR B64[] =
532  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
533 
534  int i;
535  char *p;
536  const UCHAR *s;
537 
538  p = Out;
539  s = In;
540  for (i = 0; i < 5; i++) {
541  *p++ = B64[(*s >> 2) & 0x3F];
542  *p++ = B64[((*s & 0x3) << 4) | ((s[1] & 0xF0) >> 4)];
543  *p++ = B64[((s[1] & 0xF) << 2) | ((s[2] & 0xC0) >> 6)];
544  *p++ = B64[s[2] & 0x3F];
545  s += 3;
546  }
547 
548  *p++ = B64[(*s >> 2) & 0x3F];
549  *p++ = B64[((*s & 0x3) << 4)];
550  *p = '\0';
551 
552  return;
553 }
554 
555 // Main function: ==============================================================
556 void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
557 {
558  // Mex interface:
559  // - Define default values of optional arguments.
560  // - Forward input data to different calculators according to the input type.
561  // - Convert digest to output format.
562 
563  char *FileName, InType, hexOut[33], b64Out[23];
564  UCHAR digest[16], *digestP, OutType = 'h';
565  int isFile = false, isUnicode = false;
566  double *outP, *outEnd;
567 
568  // Check number of inputs and outputs:
569  if (nrhs == 0 || nrhs > 3) {
570  mexErrMsgTxt("*** CalcMD5[mex]: 1 to 3 inputs required.");
571  }
572  if (nlhs > 1) {
573  mexErrMsgTxt("*** CalcMD5[mex]: Too many output arguments.");
574  }
575 
576  // If 2nd input starts with 'f', treat string in 1st argument as file name:
577  if (nrhs >= 2 && mxGetNumberOfElements(prhs[1]) > 0) {
578  if (mxIsChar(prhs[1]) == 0) {
579  mexErrMsgTxt("*** CalcMD5[mex]: 2nd input must be a string.");
580  }
581 
582  InType = (char) tolower(*(POINTER) mxGetData(prhs[1]));
583  isFile = (InType == 'f');
584  isUnicode = (InType == 'u');
585  } // Default otherwise!
586 
587  // Output type - default: hex:
588  if (nrhs == 3 && !mxIsEmpty(prhs[2])) {
589  if (mxIsChar(prhs[2]) == 0) {
590  mexErrMsgTxt("*** CalcMD5[mex]: 3rd input must be a string.");
591  }
592 
593  OutType = *(POINTER) mxGetData(prhs[2]); // Just 1st character
594  }
595 
596  // Calculate check sum:
597  if (isFile) {
598  if ((FileName = mxArrayToString(prhs[0])) == NULL) {
599  mexErrMsgTxt("*** CalcMD5[mex]: Cannot get file name.");
600  }
601  MD5File(FileName, digest);
602  mxFree(FileName);
603 
604  } else if (mxIsNumeric(prhs[0]) || isUnicode) {
605  MD5Array((POINTER) mxGetData(prhs[0]),
606  mxGetNumberOfElements(prhs[0]) * mxGetElementSize(prhs[0]),
607  digest);
608 
609  } else if (mxIsChar(prhs[0])) {
610  MD5Char((mxChar *) mxGetData(prhs[0]),
611  mxGetNumberOfElements(prhs[0]),
612  digest);
613 
614  } else {
615  mexErrMsgTxt("*** CalcMD5[mex]: Input type not accepted.");
616  }
617 
618  // Create output:
619  switch (OutType) {
620  case 'H':
621  case 'h': // Hexadecimal upper/lower case:
622  ToHex(digest, hexOut, OutType == 'h');
623  plhs[0] = mxCreateString(hexOut);
624  break;
625 
626  case 'D':
627  case 'd': // DOUBLE with integer values:
628  plhs[0] = mxCreateDoubleMatrix(1, 16, mxREAL);
629  outP = mxGetPr(plhs[0]);
630  digestP = digest;
631  for (outEnd = outP + 16; outP < outEnd; outP++) {
632  *outP = (double) *digestP++;
633  }
634  break;
635 
636  case 'B':
637  case 'b': // Base64:
638  //strtobase64(b64Out, 26, digest, 16); // included in LCC3.8
639  //b64Out[24] = '\0';
640  ToBase64(digest, b64Out); // Locally implemented
641  plhs[0] = mxCreateString(b64Out);
642  break;
643 
644  default:
645  mexErrMsgTxt("*** CalcMD5[mex]: Unknown output type.");
646  }
647 
648  return;
649 }
void MD5Encode(UCHAR *, UINT32 *, UINT)
Definition: CalcMD5.c:397
UINT32 state[4]
Definition: CalcMD5.c:127
UCHAR buffer[64]
Definition: CalcMD5.c:129
unsigned char * POINTER
Definition: CalcMD5.c:123
#define mwSize
Definition: CalcMD5.c:116
#define S43
Definition: CalcMD5.c:159
void MD5Array(UCHAR *data, mwSize N, UCHAR digest[16])
Definition: CalcMD5.c:461
void MD5Init(MD5_CTX *)
Definition: CalcMD5.c:192
unsigned char UCHAR
Definition: CalcMD5.c:121
#define S32
Definition: CalcMD5.c:154
A double value.
#define S21
Definition: CalcMD5.c:149
static UCHAR PADDING[64]
Definition: CalcMD5.c:162
#define S23
Definition: CalcMD5.c:151
#define S13
Definition: CalcMD5.c:147
void MD5File(char *FileName, UCHAR digest[16])
Definition: CalcMD5.c:477
#define S44
Definition: CalcMD5.c:160
UINT32_T UINT32
Definition: CalcMD5.c:124
#define S41
Definition: CalcMD5.c:157
void ToBase64(const UCHAR In[16], char *Out)
Definition: CalcMD5.c:526
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
Definition: CalcMD5.c:556
#define S24
Definition: CalcMD5.c:152
#define S33
Definition: CalcMD5.c:155
#define II(a, b, c, d, x, s, ac)
Definition: CalcMD5.c:184
static UCHAR buffer[BUFFER_LEN]
Definition: CalcMD5.c:189
#define S42
Definition: CalcMD5.c:158
#define S22
Definition: CalcMD5.c:150
#define FF(a, b, c, d, x, s, ac)
Definition: CalcMD5.c:178
#define S34
Definition: CalcMD5.c:156
void MD5Char(mxChar *data, mwSize N, UCHAR digest[16])
Definition: CalcMD5.c:410
#define HH(a, b, c, d, x, s, ac)
Definition: CalcMD5.c:182
void MD5Update(MD5_CTX *, UCHAR *, UINT)
Definition: CalcMD5.c:205
void MD5Transform(UINT32[4], UCHAR[64])
Definition: CalcMD5.c:268
#define S31
Definition: CalcMD5.c:153
#define S14
Definition: CalcMD5.c:148
void ToHex(const UCHAR In[16], char *Out, int LowerCase)
Definition: CalcMD5.c:508
UINT32 count[2]
Definition: CalcMD5.c:128
void MD5Final(UCHAR[16], MD5_CTX *)
Definition: CalcMD5.c:244
unsigned int UINT
Definition: CalcMD5.c:122
#define BUFFER_LEN
Definition: CalcMD5.c:188
#define GG(a, b, c, d, x, s, ac)
Definition: CalcMD5.c:180
A MatLab character array.
#define S12
Definition: CalcMD5.c:146
#define S11
Definition: CalcMD5.c:145