Coverage Report

Created: 2026-06-30 06:18

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
3.36M
#define F(x, y, z)      ((z) ^ ((x) & ((y) ^ (z))))
78
3.36M
#define G(x, y, z)      ((y) ^ ((z) & ((x) ^ (y))))
79
1.68M
#define H(x, y, z)      (((x) ^ (y)) ^ (z))
80
1.68M
#define H2(x, y, z)     ((x) ^ ((y) ^ (z)))
81
3.36M
#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
13.4M
  (a) += f((b), (c), (d)) + (x) + (t); \
88
13.4M
  (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
89
13.4M
  (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
125
{
121
125
  const unsigned char *ptr;
122
125
  hts_md5_u32plus a, b, c, d;
123
125
  hts_md5_u32plus saved_a, saved_b, saved_c, saved_d;
124
125
125
  ptr = (const unsigned char *)data;
126
127
125
  a = ctx->a;
128
125
  b = ctx->b;
129
125
  c = ctx->c;
130
125
  d = ctx->d;
131
132
210k
  do {
133
210k
    saved_a = a;
134
210k
    saved_b = b;
135
210k
    saved_c = c;
136
210k
    saved_d = d;
137
138
/* Round 1 */
139
210k
    STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
140
210k
    STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
141
210k
    STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
142
210k
    STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
143
210k
    STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
144
210k
    STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
145
210k
    STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
146
210k
    STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
147
210k
    STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
148
210k
    STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
149
210k
    STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
150
210k
    STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
151
210k
    STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
152
210k
    STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
153
210k
    STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
154
210k
    STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
155
156
/* Round 2 */
157
210k
    STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
158
210k
    STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
159
210k
    STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
160
210k
    STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
161
210k
    STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
162
210k
    STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
163
210k
    STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
164
210k
    STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
165
210k
    STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
166
210k
    STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
167
210k
    STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
168
210k
    STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
169
210k
    STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
170
210k
    STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
171
210k
    STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
172
210k
    STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
173
174
/* Round 3 */
175
210k
    STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
176
210k
    STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
177
210k
    STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
178
210k
    STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
179
210k
    STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
180
210k
    STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
181
210k
    STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
182
210k
    STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
183
210k
    STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
184
210k
    STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
185
210k
    STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
186
210k
    STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
187
210k
    STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
188
210k
    STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
189
210k
    STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
190
210k
    STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
191
192
/* Round 4 */
193
210k
    STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
194
210k
    STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
195
210k
    STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
196
210k
    STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
197
210k
    STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
198
210k
    STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
199
210k
    STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
200
210k
    STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
201
210k
    STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
202
210k
    STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
203
210k
    STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
204
210k
    STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
205
210k
    STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
206
210k
    STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
207
210k
    STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
208
210k
    STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
209
210
210k
    a += saved_a;
211
210k
    b += saved_b;
212
210k
    c += saved_c;
213
210k
    d += saved_d;
214
215
210k
    ptr += 64;
216
210k
  } while (size -= 64);
217
218
125
  ctx->a = a;
219
125
  ctx->b = b;
220
125
  ctx->c = c;
221
125
  ctx->d = d;
222
223
125
  return ptr;
224
125
}
225
226
void hts_md5_reset(hts_md5_context *ctx)
227
89
{
228
89
  ctx->a = 0x67452301;
229
89
  ctx->b = 0xefcdab89;
230
89
  ctx->c = 0x98badcfe;
231
89
  ctx->d = 0x10325476;
232
233
89
  ctx->lo = 0;
234
89
  ctx->hi = 0;
235
89
}
236
237
void hts_md5_update(hts_md5_context *ctx, const void *data, unsigned long size)
238
89
{
239
89
  hts_md5_u32plus saved_lo;
240
89
  unsigned long used, available;
241
242
89
  saved_lo = ctx->lo;
243
89
  if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
244
0
    ctx->hi++;
245
89
  ctx->hi += size >> 29;
246
247
89
  used = saved_lo & 0x3f;
248
249
89
  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
89
  if (size >= 64) {
264
32
    data = body(ctx, data, size & ~(unsigned long)0x3f);
265
32
    size &= 0x3f;
266
32
  }
267
268
89
  memcpy(ctx->buffer, data, size);
269
89
}
270
271
void hts_md5_final(unsigned char *result, hts_md5_context *ctx)
272
89
{
273
89
  unsigned long used, available;
274
275
89
  used = ctx->lo & 0x3f;
276
277
89
  ctx->buffer[used++] = 0x80;
278
279
89
  available = 64 - used;
280
281
89
  if (available < 8) {
282
4
    memset(&ctx->buffer[used], 0, available);
283
4
    body(ctx, ctx->buffer, 64);
284
4
    used = 0;
285
4
    available = 64;
286
4
  }
287
288
89
  memset(&ctx->buffer[used], 0, available - 8);
289
290
89
  ctx->lo <<= 3;
291
89
  ctx->buffer[56] = ctx->lo;
292
89
  ctx->buffer[57] = ctx->lo >> 8;
293
89
  ctx->buffer[58] = ctx->lo >> 16;
294
89
  ctx->buffer[59] = ctx->lo >> 24;
295
89
  ctx->buffer[60] = ctx->hi;
296
89
  ctx->buffer[61] = ctx->hi >> 8;
297
89
  ctx->buffer[62] = ctx->hi >> 16;
298
89
  ctx->buffer[63] = ctx->hi >> 24;
299
300
89
  body(ctx, ctx->buffer, 64);
301
302
89
  result[0] = ctx->a;
303
89
  result[1] = ctx->a >> 8;
304
89
  result[2] = ctx->a >> 16;
305
89
  result[3] = ctx->a >> 24;
306
89
  result[4] = ctx->b;
307
89
  result[5] = ctx->b >> 8;
308
89
  result[6] = ctx->b >> 16;
309
89
  result[7] = ctx->b >> 24;
310
89
  result[8] = ctx->c;
311
89
  result[9] = ctx->c >> 8;
312
89
  result[10] = ctx->c >> 16;
313
89
  result[11] = ctx->c >> 24;
314
89
  result[12] = ctx->d;
315
89
  result[13] = ctx->d >> 8;
316
89
  result[14] = ctx->d >> 16;
317
89
  result[15] = ctx->d >> 24;
318
319
89
  memset(ctx, 0, sizeof(*ctx));
320
89
}
321
322
323
hts_md5_context *hts_md5_init(void)
324
89
{
325
89
    hts_md5_context *ctx = malloc(sizeof(*ctx));
326
89
    if (!ctx)
327
0
        return NULL;
328
329
89
    hts_md5_reset(ctx);
330
89
    return ctx;
331
89
}
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
89
{
374
89
    if (!ctx)
375
0
        return;
376
377
89
    free(ctx);
378
89
}
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
}