NeoMutt  2023-03-22
Teaching an old dog new tricks
DOXYGEN
md5.c File Reference

Calculate the MD5 checksum of a buffer. More...

#include "config.h"
#include <stddef.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "md5.h"
+ Include dependency graph for md5.c:

Go to the source code of this file.

Macros

#define SWAP(n)   (n)
 
#define FF(b, c, d)   (d ^ (b & (c ^ d)))
 
#define FG(b, c, d)   FF(d, b, c)
 
#define FH(b, c, d)   (b ^ c ^ d)
 
#define FI(b, c, d)   (c ^ (b | ~d))
 
#define OP(a, b, c, d, s, T)
 
#define CYCLIC(w, s)   (w = (w << s) | (w >> (32 - s)))
 
#define OP(f, a, b, c, d, k, s, T)
 
#define alignof(type)
 
#define UNALIGNED_P(p)   (((size_t) p) % alignof(md5_uint32) != 0)
 

Functions

static void mutt_md5_process_block (const void *buffer, size_t len, struct Md5Ctx *md5ctx)
 Process a block with MD5. More...
 
static void set_uint32 (char *cp, md5_uint32 v)
 Write a 32 bit number. More...
 
static void * mutt_md5_read_ctx (const struct Md5Ctx *md5ctx, void *resbuf)
 Read from the context into a buffer. More...
 
void mutt_md5_init_ctx (struct Md5Ctx *md5ctx)
 Initialise the MD5 computation. More...
 
void * mutt_md5_finish_ctx (struct Md5Ctx *md5ctx, void *resbuf)
 Process the remaining bytes in the buffer. More...
 
void * mutt_md5 (const char *str, void *buf)
 Calculate the MD5 hash of a NULL-terminated string. More...
 
void * mutt_md5_bytes (const void *buffer, size_t len, void *resbuf)
 Calculate the MD5 hash of a buffer. More...
 
void mutt_md5_process (const char *str, struct Md5Ctx *md5ctx)
 Process a NULL-terminated string. More...
 
void mutt_md5_process_bytes (const void *buf, size_t buflen, struct Md5Ctx *md5ctx)
 Process a block of data. More...
 
void mutt_md5_toascii (const void *digest, char *resbuf)
 Convert a binary MD5 digest into ASCII Hexadecimal. More...
 

Variables

static const unsigned char fillbuf [64] = { 0x80, 0 }
 

Detailed Description

Calculate the MD5 checksum of a buffer.

Authors
  • Ulrich Drepper
  • Free Software Foundation, Inc.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file md5.c.

Macro Definition Documentation

◆ SWAP

#define SWAP (   n)    (n)

Definition at line 41 of file md5.c.

◆ FF

#define FF (   b,
  c,
 
)    (d ^ (b & (c ^ d)))

Definition at line 52 of file md5.c.

◆ FG

#define FG (   b,
  c,
 
)    FF(d, b, c)

Definition at line 53 of file md5.c.

◆ FH

#define FH (   b,
  c,
 
)    (b ^ c ^ d)

Definition at line 54 of file md5.c.

◆ FI

#define FI (   b,
  c,
 
)    (c ^ (b | ~d))

Definition at line 55 of file md5.c.

◆ OP [1/2]

#define OP (   a,
  b,
  c,
  d,
  s,
 
)
Value:
do \
{ \
a += FF(b, c, d) + (*cwp++ = SWAP(*words)) + T; \
words++; \
CYCLIC(a, s); \
a += b; \
} while (false)
#define FF(b, c, d)
Definition: md5.c:52
#define SWAP(n)
Definition: md5.c:41

◆ CYCLIC

#define CYCLIC (   w,
 
)    (w = (w << s) | (w >> (32 - s)))

◆ OP [2/2]

#define OP (   f,
  a,
  b,
  c,
  d,
  k,
  s,
 
)
Value:
do \
{ \
a += f(b, c, d) + correct_words[k] + T; \
CYCLIC(a, s); \
a += b; \
} while (false)

◆ alignof

#define alignof (   type)
Value:
offsetof( \
struct { \
char c; \
type x; \
}, \
x)

◆ UNALIGNED_P

#define UNALIGNED_P (   p)    (((size_t) p) % alignof(md5_uint32) != 0)

Function Documentation

◆ mutt_md5_process_block()

static void mutt_md5_process_block ( const void *  buffer,
size_t  len,
struct Md5Ctx md5ctx 
)
static

Process a block with MD5.

Parameters
bufferBuffer to hash
lenLength of buffer
md5ctxMD5 context

Process LEN bytes of Buffer, accumulating context into MD5CTX. LEN must be a multiple of 64.

Definition at line 66 of file md5.c.

67{
68 md5_uint32 correct_words[16];
69 const md5_uint32 *words = buffer;
70 size_t nwords = len / sizeof(md5_uint32);
71 const md5_uint32 *endp = words + nwords;
72 md5_uint32 A = md5ctx->A;
73 md5_uint32 B = md5ctx->B;
74 md5_uint32 C = md5ctx->C;
75 md5_uint32 D = md5ctx->D;
76
77 /* First increment the byte count. RFC1321 specifies the possible length of
78 * the file up to 2^64 bits. Here we only compute the number of bytes. Do a
79 * double word increment. */
80 md5ctx->total[0] += len;
81 if (md5ctx->total[0] < len)
82 md5ctx->total[1]++;
83
84 /* Process all bytes in the buffer with 64 bytes in each round of the loop. */
85 while (words < endp)
86 {
87 md5_uint32 *cwp = correct_words;
88 md5_uint32 save_A = A;
89 md5_uint32 save_B = B;
90 md5_uint32 save_C = C;
91 md5_uint32 save_D = D;
92
93 /* First round: using the given function, the context and a constant the
94 * next context is computed. Because the algorithms processing unit is a
95 * 32-bit word and it is determined to work on words in little endian byte
96 * order we perhaps have to change the byte order before the computation.
97 * To reduce the work for the next steps we store the swapped words in the
98 * array CORRECT_WORDS. */
99
100#define OP(a, b, c, d, s, T) \
101 do \
102 { \
103 a += FF(b, c, d) + (*cwp++ = SWAP(*words)) + T; \
104 words++; \
105 CYCLIC(a, s); \
106 a += b; \
107 } while (false)
108
109/* It is unfortunate that C does not provide an operator for
110 * cyclic rotation. Hope the C compiler is smart enough. */
111#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
112
113 /* Before we start, one word to the strange constants.
114 * They are defined in RFC1321 as
115 * T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
116 * Here is an equivalent invocation using Perl:
117 * perl -e 'foreach(1..64){printf "0x%08x\n", int (4294967296 * abs (sin $_))}'
118 */
119
120 /* Round 1. */
121 OP(A, B, C, D, 7, 0xd76aa478);
122 OP(D, A, B, C, 12, 0xe8c7b756);
123 OP(C, D, A, B, 17, 0x242070db);
124 OP(B, C, D, A, 22, 0xc1bdceee);
125 OP(A, B, C, D, 7, 0xf57c0faf);
126 OP(D, A, B, C, 12, 0x4787c62a);
127 OP(C, D, A, B, 17, 0xa8304613);
128 OP(B, C, D, A, 22, 0xfd469501);
129 OP(A, B, C, D, 7, 0x698098d8);
130 OP(D, A, B, C, 12, 0x8b44f7af);
131 OP(C, D, A, B, 17, 0xffff5bb1);
132 OP(B, C, D, A, 22, 0x895cd7be);
133 OP(A, B, C, D, 7, 0x6b901122);
134 OP(D, A, B, C, 12, 0xfd987193);
135 OP(C, D, A, B, 17, 0xa679438e);
136 OP(B, C, D, A, 22, 0x49b40821);
137
138/* For the second to fourth round we have the possibly swapped words
139 * in CORRECT_WORDS. Redefine the macro to take an additional first
140 * argument specifying the function to use. */
141#undef OP
142#define OP(f, a, b, c, d, k, s, T) \
143 do \
144 { \
145 a += f(b, c, d) + correct_words[k] + T; \
146 CYCLIC(a, s); \
147 a += b; \
148 } while (false)
149
150 /* Round 2. */
151 OP(FG, A, B, C, D, 1, 5, 0xf61e2562);
152 OP(FG, D, A, B, C, 6, 9, 0xc040b340);
153 OP(FG, C, D, A, B, 11, 14, 0x265e5a51);
154 OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
155 OP(FG, A, B, C, D, 5, 5, 0xd62f105d);
156 OP(FG, D, A, B, C, 10, 9, 0x02441453);
157 OP(FG, C, D, A, B, 15, 14, 0xd8a1e681);
158 OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
159 OP(FG, A, B, C, D, 9, 5, 0x21e1cde6);
160 OP(FG, D, A, B, C, 14, 9, 0xc33707d6);
161 OP(FG, C, D, A, B, 3, 14, 0xf4d50d87);
162 OP(FG, B, C, D, A, 8, 20, 0x455a14ed);
163 OP(FG, A, B, C, D, 13, 5, 0xa9e3e905);
164 OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8);
165 OP(FG, C, D, A, B, 7, 14, 0x676f02d9);
166 OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
167
168 /* Round 3. */
169 OP(FH, A, B, C, D, 5, 4, 0xfffa3942);
170 OP(FH, D, A, B, C, 8, 11, 0x8771f681);
171 OP(FH, C, D, A, B, 11, 16, 0x6d9d6122);
172 OP(FH, B, C, D, A, 14, 23, 0xfde5380c);
173 OP(FH, A, B, C, D, 1, 4, 0xa4beea44);
174 OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9);
175 OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60);
176 OP(FH, B, C, D, A, 10, 23, 0xbebfbc70);
177 OP(FH, A, B, C, D, 13, 4, 0x289b7ec6);
178 OP(FH, D, A, B, C, 0, 11, 0xeaa127fa);
179 OP(FH, C, D, A, B, 3, 16, 0xd4ef3085);
180 OP(FH, B, C, D, A, 6, 23, 0x04881d05);
181 OP(FH, A, B, C, D, 9, 4, 0xd9d4d039);
182 OP(FH, D, A, B, C, 12, 11, 0xe6db99e5);
183 OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8);
184 OP(FH, B, C, D, A, 2, 23, 0xc4ac5665);
185
186 /* Round 4. */
187 OP(FI, A, B, C, D, 0, 6, 0xf4292244);
188 OP(FI, D, A, B, C, 7, 10, 0x432aff97);
189 OP(FI, C, D, A, B, 14, 15, 0xab9423a7);
190 OP(FI, B, C, D, A, 5, 21, 0xfc93a039);
191 OP(FI, A, B, C, D, 12, 6, 0x655b59c3);
192 OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92);
193 OP(FI, C, D, A, B, 10, 15, 0xffeff47d);
194 OP(FI, B, C, D, A, 1, 21, 0x85845dd1);
195 OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f);
196 OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
197 OP(FI, C, D, A, B, 6, 15, 0xa3014314);
198 OP(FI, B, C, D, A, 13, 21, 0x4e0811a1);
199 OP(FI, A, B, C, D, 4, 6, 0xf7537e82);
200 OP(FI, D, A, B, C, 11, 10, 0xbd3af235);
201 OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
202 OP(FI, B, C, D, A, 9, 21, 0xeb86d391);
203
204 /* Add the starting values of the context. */
205 A += save_A;
206 B += save_B;
207 C += save_C;
208 D += save_D;
209 }
210
211 /* Put checksum in context given as argument. */
212 md5ctx->A = A;
213 md5ctx->B = B;
214 md5ctx->C = C;
215 md5ctx->D = D;
216}
#define FH(b, c, d)
Definition: md5.c:54
#define FG(b, c, d)
Definition: md5.c:53
#define OP(a, b, c, d, s, T)
#define FI(b, c, d)
Definition: md5.c:55
uint32_t md5_uint32
Definition: md5.h:29
#define C
md5_uint32 total[2]
Definition: md5.h:43
md5_uint32 D
Definition: md5.h:41
md5_uint32 C
Definition: md5.h:40
md5_uint32 A
Definition: md5.h:38
md5_uint32 B
Definition: md5.h:39
+ Here is the caller graph for this function:

◆ set_uint32()

static void set_uint32 ( char *  cp,
md5_uint32  v 
)
inlinestatic

Write a 32 bit number.

Parameters
cpDestination for data
vValue to write

Copy the 4 byte value from v into the memory location pointed to by *cp, If your architecture allows unaligned access this is equivalent to *(md5_uint32*) cp = v

Definition at line 227 of file md5.c.

228{
229 memcpy(cp, &v, sizeof(v));
230}
+ Here is the caller graph for this function:

◆ mutt_md5_read_ctx()

static void * mutt_md5_read_ctx ( const struct Md5Ctx md5ctx,
void *  resbuf 
)
static

Read from the context into a buffer.

Parameters
md5ctxMD5 context
resbufBuffer for result
Return values
ptrResults buffer

Put result from MD5CTX in first 16 bytes following RESBUF. The result must be in little endian byte order.

Definition at line 241 of file md5.c.

242{
243 if (!md5ctx || !resbuf)
244 return NULL;
245
246 char *r = resbuf;
247
248 set_uint32(r + 0 * sizeof(md5ctx->A), SWAP(md5ctx->A));
249 set_uint32(r + 1 * sizeof(md5ctx->B), SWAP(md5ctx->B));
250 set_uint32(r + 2 * sizeof(md5ctx->C), SWAP(md5ctx->C));
251 set_uint32(r + 3 * sizeof(md5ctx->D), SWAP(md5ctx->D));
252
253 return resbuf;
254}
static void set_uint32(char *cp, md5_uint32 v)
Write a 32 bit number.
Definition: md5.c:227
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_md5_init_ctx()

void mutt_md5_init_ctx ( struct Md5Ctx md5ctx)

Initialise the MD5 computation.

Parameters
md5ctxMD5 context

RFC1321, 3.3: Step 3

Definition at line 262 of file md5.c.

263{
264 if (!md5ctx)
265 return;
266
267 md5ctx->A = 0x67452301;
268 md5ctx->B = 0xefcdab89;
269 md5ctx->C = 0x98badcfe;
270 md5ctx->D = 0x10325476;
271
272 md5ctx->total[0] = 0;
273 md5ctx->total[1] = 0;
274 md5ctx->buflen = 0;
275}
md5_uint32 buflen
Definition: md5.h:44
+ Here is the caller graph for this function:

◆ mutt_md5_finish_ctx()

void * mutt_md5_finish_ctx ( struct Md5Ctx md5ctx,
void *  resbuf 
)

Process the remaining bytes in the buffer.

Parameters
md5ctxMD5 context
resbufBuffer for result
Return values
ptrResults buffer

Process the remaining bytes in the internal buffer and the usual prologue according to the standard and write the result to RESBUF.

Definition at line 286 of file md5.c.

287{
288 if (!md5ctx)
289 return NULL;
290
291 /* Take yet unprocessed bytes into account. */
292 md5_uint32 bytes = md5ctx->buflen;
293 size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4;
294
295 /* Now count remaining bytes. */
296 md5ctx->total[0] += bytes;
297 if (md5ctx->total[0] < bytes)
298 md5ctx->total[1]++;
299
300 /* Put the 64-bit file length in *bits* at the end of the buffer. */
301 md5ctx->buffer[size - 2] = SWAP(md5ctx->total[0] << 3);
302 md5ctx->buffer[size - 1] = SWAP((md5ctx->total[1] << 3) | (md5ctx->total[0] >> 29));
303
304 memcpy(&((char *) md5ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes);
305
306 /* Process last bytes. */
307 mutt_md5_process_block(md5ctx->buffer, size * 4, md5ctx);
308
309 return mutt_md5_read_ctx(md5ctx, resbuf);
310}
static void * mutt_md5_read_ctx(const struct Md5Ctx *md5ctx, void *resbuf)
Read from the context into a buffer.
Definition: md5.c:241
static void mutt_md5_process_block(const void *buffer, size_t len, struct Md5Ctx *md5ctx)
Process a block with MD5.
Definition: md5.c:66
static const unsigned char fillbuf[64]
Definition: md5.c:46
md5_uint32 buffer[32]
Definition: md5.h:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_md5()

void * mutt_md5 ( const char *  str,
void *  buf 
)

Calculate the MD5 hash of a NULL-terminated string.

Parameters
strString to hash
bufBuffer for result
Return values
ptrResults buffer

Definition at line 318 of file md5.c.

319{
320 if (!str)
321 return NULL;
322
323 return mutt_md5_bytes(str, strlen(str), buf);
324}
void * mutt_md5_bytes(const void *buffer, size_t len, void *resbuf)
Calculate the MD5 hash of a buffer.
Definition: md5.c:337
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_md5_bytes()

void * mutt_md5_bytes ( const void *  buffer,
size_t  len,
void *  resbuf 
)

Calculate the MD5 hash of a buffer.

Parameters
bufferBuffer to hash
lenLength of buffer
resbufBuffer for result
Return values
ptrResults buffer

Compute MD5 message digest for LEN bytes beginning at Buffer. The result is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII representation of the message digest.

Definition at line 337 of file md5.c.

338{
339 struct Md5Ctx md5ctx;
340
341 /* Initialize the computation context. */
342 mutt_md5_init_ctx(&md5ctx);
343
344 /* Process whole buffer but last len % 64 bytes. */
345 mutt_md5_process_bytes(buffer, len, &md5ctx);
346
347 /* Put result in desired memory area. */
348 return mutt_md5_finish_ctx(&md5ctx, resbuf);
349}
void mutt_md5_process_bytes(const void *buf, size_t buflen, struct Md5Ctx *md5ctx)
Process a block of data.
Definition: md5.c:374
void mutt_md5_init_ctx(struct Md5Ctx *md5ctx)
Initialise the MD5 computation.
Definition: md5.c:262
void * mutt_md5_finish_ctx(struct Md5Ctx *md5ctx, void *resbuf)
Process the remaining bytes in the buffer.
Definition: md5.c:286
Cursor for the MD5 hashing.
Definition: md5.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_md5_process()

void mutt_md5_process ( const char *  str,
struct Md5Ctx md5ctx 
)

Process a NULL-terminated string.

Parameters
strString to process
md5ctxMD5 context

Definition at line 356 of file md5.c.

357{
358 if (!str)
359 return;
360
361 mutt_md5_process_bytes(str, strlen(str), md5ctx);
362}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_md5_process_bytes()

void mutt_md5_process_bytes ( const void *  buf,
size_t  buflen,
struct Md5Ctx md5ctx 
)

Process a block of data.

Parameters
bufBuffer to process
buflenLength of buffer
md5ctxMD5 context

Starting with the result of former calls of this function (or the initialization function update the context for the next BUFLEN bytes starting at Buffer. It is NOT required that BUFLEN is a multiple of 64.

Definition at line 374 of file md5.c.

375{
376 if (!buf || !md5ctx)
377 return;
378
379 /* When we already have some bits in our internal buffer concatenate both
380 * inputs first. */
381 if (md5ctx->buflen != 0)
382 {
383 size_t left_over = md5ctx->buflen;
384 size_t add = ((128 - left_over) > buflen) ? buflen : (128 - left_over);
385
386 memcpy(&((char *) md5ctx->buffer)[left_over], buf, add);
387 md5ctx->buflen += add;
388
389 if (md5ctx->buflen > 64)
390 {
391 mutt_md5_process_block(md5ctx->buffer, md5ctx->buflen & ~63, md5ctx);
392
393 md5ctx->buflen &= 63;
394 /* The regions in the following copy operation can't overlap. */
395 memcpy(md5ctx->buffer, &((char *) md5ctx->buffer)[(left_over + add) & ~63],
396 md5ctx->buflen);
397 }
398
399 buf = (const char *) buf + add;
400 buflen -= add;
401 }
402
403 /* Process available complete blocks. */
404 if (buflen >= 64)
405 {
406#if !defined(_STRING_ARCH_unaligned)
407#define alignof(type) \
408 offsetof( \
409 struct { \
410 char c; \
411 type x; \
412 }, \
413 x)
414#define UNALIGNED_P(p) (((size_t) p) % alignof(md5_uint32) != 0)
415 if (UNALIGNED_P(buf))
416 {
417 while (buflen > 64)
418 {
419 mutt_md5_process_block(memcpy(md5ctx->buffer, buf, 64), 64, md5ctx);
420 buf = (const char *) buf + 64;
421 buflen -= 64;
422 }
423 }
424 else
425#endif
426 {
427 mutt_md5_process_block(buf, buflen & ~63, md5ctx);
428 buf = (const char *) buf + (buflen & ~63);
429 buflen &= 63;
430 }
431 }
432
433 /* Move remaining bytes in internal buffer. */
434 if (buflen > 0)
435 {
436 size_t left_over = md5ctx->buflen;
437
438 memcpy(&((char *) md5ctx->buffer)[left_over], buf, buflen);
439 left_over += buflen;
440 if (left_over >= 64)
441 {
442 mutt_md5_process_block(md5ctx->buffer, 64, md5ctx);
443 left_over -= 64;
444 memmove(md5ctx->buffer, &md5ctx->buffer[16], left_over);
445 }
446 md5ctx->buflen = left_over;
447 }
448}
#define UNALIGNED_P(p)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_md5_toascii()

void mutt_md5_toascii ( const void *  digest,
char *  resbuf 
)

Convert a binary MD5 digest into ASCII Hexadecimal.

Parameters
digestBinary MD5 digest
resbufBuffer for the ASCII result
Note
refbuf must be at least 33 bytes long.

Definition at line 457 of file md5.c.

458{
459 if (!digest || !resbuf)
460 return;
461
462 const unsigned char *c = digest;
463 sprintf(resbuf, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
464 c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10],
465 c[11], c[12], c[13], c[14], c[15]);
466}
+ Here is the caller graph for this function:

Variable Documentation

◆ fillbuf

const unsigned char fillbuf[64] = { 0x80, 0 }
static

Definition at line 46 of file md5.c.