Coverage Report

Created: 2026-10-17 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/htslib/md5.c
Line
Count
Source
1
/*
2
 * Trivial amendments by James Bonfield <jkb@sanger.ac.uk> to provide an
3
 * HTSlib interface. 2015.
4
 *
5
 * Externally our API uses an opaque hts_md5_context structure.
6
 *
7
 * Internally either this gets defined and used with the routines here
8
 * or it remains incomplete and is cast to the OpenSSL MD5_CTX structure
9
 * and used by routines from OpenSSL.
10
 */
11
12
/*
13
 * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
14
 * MD5 Message-Digest Algorithm (RFC 1321).
15
 *
16
 * Homepage:
17
 * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
18
 *
19
 * Author:
20
 * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
21
 *
22
 * This software was written by Alexander Peslyak in 2001.  No copyright is
23
 * claimed, and the software is hereby placed in the public domain.
24
 * In case this attempt to disclaim copyright and place the software in the
25
 * public domain is deemed null and void, then the software is
26
 * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
27
 * general public under the following terms:
28
 *
29
 * Redistribution and use in source and binary forms, with or without
30
 * modification, are permitted.
31
 *
32
 * There's ABSOLUTELY NO WARRANTY, express or implied.
33
 *
34
 * (This is a heavily cut-down "BSD license".)
35
 *
36
 * This differs from Colin Plumb's older public domain implementation in that
37
 * no exactly 32-bit integer data type is required (any 32-bit or wider
38
 * unsigned integer data type will do), there's no compile-time endianness
39
 * configuration, and the function prototypes match OpenSSL's.  No code from
40
 * Colin Plumb's implementation has been reused; this comment merely compares
41
 * the properties of the two independent implementations.
42
 *
43
 * The primary goals of this implementation are portability and ease of use.
44
 * It is meant to be fast, but not as fast as possible.  Some known
45
 * optimizations are not included to reduce source code size and avoid
46
 * compile-time configuration.
47
 */
48
49
#define HTS_BUILDING_LIBRARY // Enables HTSLIB_EXPORT, see htslib/hts_defs.h
50
#include <config.h>
51
52
#include <stdlib.h>
53
#include "htslib/hts.h"
54
#include "htslib/hts_endian.h"
55
56
#ifndef HAVE_OPENSSL
57
58
#include <string.h>
59
60
/* Any 32-bit or wider unsigned integer data type will do */
61
typedef unsigned int hts_md5_u32plus;
62
63
struct hts_md5_context {
64
  hts_md5_u32plus lo, hi;
65
  hts_md5_u32plus a, b, c, d;
66
  unsigned char buffer[64];
67
  hts_md5_u32plus block[16];
68
};
69
70
/*
71
 * The basic MD5 functions.
72
 *
73
 * F and G are optimized compared to their RFC 1321 definitions for
74
 * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
75
 * implementation.
76
 */
77
371k
#define F(x, y, z)      ((z) ^ ((x) & ((y) ^ (z))))
78
371k
#define G(x, y, z)      ((y) ^ ((z) & ((x) ^ (y))))
79
185k
#define H(x, y, z)      (((x) ^ (y)) ^ (z))
80
185k
#define H2(x, y, z)     ((x) ^ ((y) ^ (z)))
81
371k
#define I(x, y, z)      ((y) ^ ((x) | ~(z)))
82
83
/*
84
 * The MD5 transformation for all four rounds.
85
 */
86
#define STEP(f, a, b, c, d, x, t, s) \
87
1.48M
  (a) += f((b), (c), (d)) + (x) + (t); \
88
1.48M
  (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
89
1.48M
  (a) += (b);
90
91
/*
92
 * SET reads 4 input bytes in little-endian byte order and stores them
93
 * in a properly aligned word in host byte order.
94
 *
95
 * The check for little-endian architectures that tolerate unaligned
96
 * memory accesses is just an optimization.  Nothing will break if it
97
 * doesn't work.
98
 */
99
#if defined(HTS_LITTLE_ENDIAN) && HTS_ALLOW_UNALIGNED != 0
100
#define SET(n) \
101
  (*(hts_md5_u32plus *)&ptr[(n) * 4])
102
#define GET(n) \
103
  SET(n)
104
#else
105
#define SET(n) \
106
  (ctx->block[(n)] = \
107
  (hts_md5_u32plus)ptr[(n) * 4] | \
108
  ((hts_md5_u32plus)ptr[(n) * 4 + 1] << 8) | \
109
  ((hts_md5_u32plus)ptr[(n) * 4 + 2] << 16) | \
110
  ((hts_md5_u32plus)ptr[(n) * 4 + 3] << 24))
111
#define GET(n) \
112
  (ctx->block[(n)])
113
#endif
114
115
/*
116
 * This processes one or more 64-byte data blocks, but does NOT update
117
 * the bit counters.  There are no alignment requirements.
118
 */
119
static const void *body(hts_md5_context *ctx, const void *data, unsigned long size)
120
19.6k
{
121
19.6k
  const unsigned char *ptr;
122
19.6k
  hts_md5_u32plus a, b, c, d;
123
19.6k
  hts_md5_u32plus saved_a, saved_b, saved_c, saved_d;
124
125
19.6k
  ptr = (const unsigned char *)data;
126
127
19.6k
  a = ctx->a;
128
19.6k
  b = ctx->b;
129
19.6k
  c = ctx->c;
130
19.6k
  d = ctx->d;
131
132
23.2k
  do {
133
23.2k
    saved_a = a;
134
23.2k
    saved_b = b;
135
23.2k
    saved_c = c;
136
23.2k
    saved_d = d;
137
138
/* Round 1 */
139
23.2k
    STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
140
23.2k
    STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
141
23.2k
    STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
142
23.2k
    STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
143
23.2k
    STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
144
23.2k
    STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
145
23.2k
    STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
146
23.2k
    STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
147
23.2k
    STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
148
23.2k
    STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
149
23.2k
    STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
150
23.2k
    STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
151
23.2k
    STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
152
23.2k
    STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
153
23.2k
    STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
154
23.2k
    STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
155
156
/* Round 2 */
157
23.2k
    STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
158
23.2k
    STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
159
23.2k
    STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
160
23.2k
    STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
161
23.2k
    STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
162
23.2k
    STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
163
23.2k
    STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
164
23.2k
    STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
165
23.2k
    STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
166
23.2k
    STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
167
23.2k
    STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
168
23.2k
    STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
169
23.2k
    STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
170
23.2k
    STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
171
23.2k
    STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
172
23.2k
    STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
173
174
/* Round 3 */
175
23.2k
    STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
176
23.2k
    STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
177
23.2k
    STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
178
23.2k
    STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
179
23.2k
    STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
180
23.2k
    STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
181
23.2k
    STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
182
23.2k
    STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
183
23.2k
    STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
184
23.2k
    STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
185
23.2k
    STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
186
23.2k
    STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
187
23.2k
    STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
188
23.2k
    STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
189
23.2k
    STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
190
23.2k
    STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
191
192
/* Round 4 */
193
23.2k
    STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
194
23.2k
    STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
195
23.2k
    STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
196
23.2k
    STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
197
23.2k
    STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
198
23.2k
    STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
199
23.2k
    STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
200
23.2k
    STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
201
23.2k
    STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
202
23.2k
    STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
203
23.2k
    STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
204
23.2k
    STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
205
23.2k
    STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
206
23.2k
    STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
207
23.2k
    STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
208
23.2k
    STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
209
210
23.2k
    a += saved_a;
211
23.2k
    b += saved_b;
212
23.2k
    c += saved_c;
213
23.2k
    d += saved_d;
214
215
23.2k
    ptr += 64;
216
23.2k
  } while (size -= 64);
217
218
19.6k
  ctx->a = a;
219
19.6k
  ctx->b = b;
220
19.6k
  ctx->c = c;
221
19.6k
  ctx->d = d;
222
223
19.6k
  return ptr;
224
19.6k
}
225
226
void hts_md5_reset(hts_md5_context *ctx)
227
17.5k
{
228
17.5k
  ctx->a = 0x67452301;
229
17.5k
  ctx->b = 0xefcdab89;
230
17.5k
  ctx->c = 0x98badcfe;
231
17.5k
  ctx->d = 0x10325476;
232
233
17.5k
  ctx->lo = 0;
234
17.5k
  ctx->hi = 0;
235
17.5k
}
236
237
void hts_md5_update(hts_md5_context *ctx, const void *data, unsigned long size)
238
17.5k
{
239
17.5k
  hts_md5_u32plus saved_lo;
240
17.5k
  unsigned long used, available;
241
242
17.5k
  saved_lo = ctx->lo;
243
17.5k
  if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
244
0
    ctx->hi++;
245
17.5k
  ctx->hi += size >> 29;
246
247
17.5k
  used = saved_lo & 0x3f;
248
249
17.5k
  if (used) {
250
0
    available = 64 - used;
251
252
0
    if (size < available) {
253
0
      memcpy(&ctx->buffer[used], data, size);
254
0
      return;
255
0
    }
256
257
0
    memcpy(&ctx->buffer[used], data, available);
258
0
    data = (const unsigned char *)data + available;
259
0
    size -= available;
260
0
    body(ctx, ctx->buffer, 64);
261
0
  }
262
263
17.5k
  if (size >= 64) {
264
1.34k
    data = body(ctx, data, size & ~(unsigned long)0x3f);
265
1.34k
    size &= 0x3f;
266
1.34k
  }
267
268
17.5k
  memcpy(ctx->buffer, data, size);
269
17.5k
}
270
271
void hts_md5_final(unsigned char *result, hts_md5_context *ctx)
272
17.5k
{
273
17.5k
  unsigned long used, available;
274
275
17.5k
  used = ctx->lo & 0x3f;
276
277
17.5k
  ctx->buffer[used++] = 0x80;
278
279
17.5k
  available = 64 - used;
280
281
17.5k
  if (available < 8) {
282
725
    memset(&ctx->buffer[used], 0, available);
283
725
    body(ctx, ctx->buffer, 64);
284
725
    used = 0;
285
725
    available = 64;
286
725
  }
287
288
17.5k
  memset(&ctx->buffer[used], 0, available - 8);
289
290
17.5k
  ctx->lo <<= 3;
291
17.5k
  ctx->buffer[56] = ctx->lo;
292
17.5k
  ctx->buffer[57] = ctx->lo >> 8;
293
17.5k
  ctx->buffer[58] = ctx->lo >> 16;
294
17.5k
  ctx->buffer[59] = ctx->lo >> 24;
295
17.5k
  ctx->buffer[60] = ctx->hi;
296
17.5k
  ctx->buffer[61] = ctx->hi >> 8;
297
17.5k
  ctx->buffer[62] = ctx->hi >> 16;
298
17.5k
  ctx->buffer[63] = ctx->hi >> 24;
299
300
17.5k
  body(ctx, ctx->buffer, 64);
301
302
17.5k
  result[0] = ctx->a;
303
17.5k
  result[1] = ctx->a >> 8;
304
17.5k
  result[2] = ctx->a >> 16;
305
17.5k
  result[3] = ctx->a >> 24;
306
17.5k
  result[4] = ctx->b;
307
17.5k
  result[5] = ctx->b >> 8;
308
17.5k
  result[6] = ctx->b >> 16;
309
17.5k
  result[7] = ctx->b >> 24;
310
17.5k
  result[8] = ctx->c;
311
17.5k
  result[9] = ctx->c >> 8;
312
17.5k
  result[10] = ctx->c >> 16;
313
17.5k
  result[11] = ctx->c >> 24;
314
17.5k
  result[12] = ctx->d;
315
17.5k
  result[13] = ctx->d >> 8;
316
17.5k
  result[14] = ctx->d >> 16;
317
17.5k
  result[15] = ctx->d >> 24;
318
319
17.5k
  memset(ctx, 0, sizeof(*ctx));
320
17.5k
}
321
322
323
hts_md5_context *hts_md5_init(void)
324
17.5k
{
325
17.5k
    hts_md5_context *ctx = malloc(sizeof(*ctx));
326
17.5k
    if (!ctx)
327
0
        return NULL;
328
329
17.5k
    hts_md5_reset(ctx);
330
17.5k
    return ctx;
331
17.5k
}
332
333
#else
334
335
#include <openssl/md5.h>
336
#include <assert.h>
337
338
/*
339
 * Wrappers around the OpenSSL libcrypto.so MD5 implementation.
340
 *
341
 * These are here to ensure they end up in the symbol table of the
342
 * library regardless of the static inline in the headers.
343
 */
344
hts_md5_context *hts_md5_init(void)
345
{
346
    MD5_CTX *ctx = malloc(sizeof(*ctx));
347
    if (!ctx)
348
        return NULL;
349
350
    MD5_Init(ctx);
351
352
    return (hts_md5_context *)ctx;
353
}
354
355
void hts_md5_reset(hts_md5_context *ctx)
356
{
357
    MD5_Init((MD5_CTX *)ctx);
358
}
359
360
void hts_md5_update(hts_md5_context *ctx, const void *data, unsigned long size)
361
{
362
    MD5_Update((MD5_CTX *)ctx, data, size);
363
}
364
365
void hts_md5_final(unsigned char *result, hts_md5_context *ctx)
366
{
367
    MD5_Final(result, (MD5_CTX *)ctx);
368
}
369
370
#endif
371
372
void hts_md5_destroy(hts_md5_context *ctx)
373
17.5k
{
374
17.5k
    if (!ctx)
375
0
        return;
376
377
17.5k
    free(ctx);
378
17.5k
}
379
380
void hts_md5_hex(char *hex, const unsigned char *digest)
381
0
{
382
0
    int i;
383
0
    for (i = 0; i < 16; i++) {
384
0
        hex[i*2+0] = "0123456789abcdef"[(digest[i]>>4)&0xf];
385
0
        hex[i*2+1] = "0123456789abcdef"[digest[i]&0xf];
386
0
    }
387
0
    hex[32] = 0;
388
0
}