Coverage Report

Created: 2025-01-28 06:58

/src/wget2/libwget/hashfile.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2012 Tim Ruehsen
3
 * Copyright (c) 2015-2024 Free Software Foundation, Inc.
4
 *
5
 * This file is part of Wget.
6
 *
7
 * Wget is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * Wget is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with Wget.  If not, see <https://www.gnu.org/licenses/>.
19
 *
20
 *
21
 * Hash routines
22
 *
23
 * Changelog
24
 * 29.07.2012  Tim Ruehsen  created
25
 *
26
 */
27
28
#include <config.h>
29
30
#include <unistd.h>
31
#include <stdlib.h>
32
#include <fcntl.h>
33
#include <sys/stat.h>
34
#ifdef HAVE_MMAP
35
# include <sys/mman.h>
36
#endif
37
38
#include <wget.h>
39
#include "private.h"
40
41
/**
42
 * \file
43
 * \brief Hashing functions
44
 * \ingroup libwget-hash
45
 * @{
46
 *
47
 */
48
49
/**
50
 * \param[in] hashname Name of the hashing algorithm (see table below)
51
 * \return A constant to be used by libwget hashing functions
52
 *
53
 * Get the hashing algorithms list item that corresponds to the named hashing algorithm.
54
 *
55
 * This function returns a constant that uniquely identifies a known supported hashing algorithm
56
 * within libwget. All the supported algorithms are listed in the ::wget_digest_algorithm enum.
57
 *
58
 * Algorithm name | Constant
59
 * -------------- | --------
60
 * sha1 or sha-1|WGET_DIGTYPE_SHA1
61
 * sha256 or sha-256|WGET_DIGTYPE_SHA256
62
 * sha512 or sha-512|WGET_DIGTYPE_SHA512
63
 * sha224 or sha-224|WGET_DIGTYPE_SHA224
64
 * sha384 or sha-384|WGET_DIGTYPE_SHA384
65
 * md5|WGET_DIGTYPE_MD5
66
 * md2|WGET_DIGTYPE_MD2
67
 * rmd160|WGET_DIGTYPE_RMD160
68
 */
69
wget_digest_algorithm wget_hash_get_algorithm(const char *hashname)
70
0
{
71
0
  if (hashname) {
72
0
    if (*hashname == 's' || *hashname == 'S') {
73
0
      if (!wget_strcasecmp_ascii(hashname, "sha-1") || !wget_strcasecmp_ascii(hashname, "sha1"))
74
0
        return WGET_DIGTYPE_SHA1;
75
0
      else if (!wget_strcasecmp_ascii(hashname, "sha-256") || !wget_strcasecmp_ascii(hashname, "sha256"))
76
0
        return WGET_DIGTYPE_SHA256;
77
0
      else if (!wget_strcasecmp_ascii(hashname, "sha-512") || !wget_strcasecmp_ascii(hashname, "sha512"))
78
0
        return WGET_DIGTYPE_SHA512;
79
0
      else if (!wget_strcasecmp_ascii(hashname, "sha-224") || !wget_strcasecmp_ascii(hashname, "sha224"))
80
0
        return WGET_DIGTYPE_SHA224;
81
0
      else if (!wget_strcasecmp_ascii(hashname, "sha-384") || !wget_strcasecmp_ascii(hashname, "sha384"))
82
0
        return WGET_DIGTYPE_SHA384;
83
0
    }
84
0
    else if (!wget_strcasecmp_ascii(hashname, "md5"))
85
0
      return WGET_DIGTYPE_MD5;
86
0
    else if (!wget_strcasecmp_ascii(hashname, "md2"))
87
0
      return WGET_DIGTYPE_MD2;
88
0
    else if (!wget_strcasecmp_ascii(hashname, "rmd160"))
89
0
      return WGET_DIGTYPE_RMD160;
90
0
  }
91
92
0
  error_printf(_("Unknown hash type '%s'\n"), hashname);
93
0
  return WGET_DIGTYPE_UNKNOWN;
94
0
}
95
96
#if defined WITH_GNUTLS && !defined WITH_LIBNETTLE
97
#include <gnutls/gnutls.h>
98
#ifdef HAVE_GNUTLS_CRYPTO_H
99
#  include <gnutls/crypto.h>
100
#endif
101
102
struct wget_hash_hd_st {
103
  gnutls_hash_hd_t
104
    dig;
105
};
106
107
static const gnutls_digest_algorithm_t
108
  algorithms[WGET_DIGTYPE_MAX] = {
109
//    [WGET_DIGTYPE_UNKNOWN] = GNUTLS_DIG_UNKNOWN, // both values are 0
110
    [WGET_DIGTYPE_MD2] = GNUTLS_DIG_MD2,
111
    [WGET_DIGTYPE_MD5] = GNUTLS_DIG_MD5,
112
    [WGET_DIGTYPE_RMD160] = GNUTLS_DIG_RMD160,
113
    [WGET_DIGTYPE_SHA1] = GNUTLS_DIG_SHA1,
114
    [WGET_DIGTYPE_SHA224] = GNUTLS_DIG_SHA224,
115
    [WGET_DIGTYPE_SHA256] = GNUTLS_DIG_SHA256,
116
    [WGET_DIGTYPE_SHA384] = GNUTLS_DIG_SHA384,
117
    [WGET_DIGTYPE_SHA512] = GNUTLS_DIG_SHA512
118
};
119
120
/**
121
 * \param[in] algorithm One of the hashing algorithms returned by wget_hash_get_algorithm()
122
 * \param[in] text Input data to hash
123
 * \param[in] textlen Length of the input data
124
 * \param[in] digest Caller-supplied buffer where the output hash will be placed
125
 * \return Zero on success or a negative value on error
126
 *
127
 * Convenience function to hash the given data in a single call.
128
 *
129
 * The caller must ensure that the provided output buffer \p digest is large enough
130
 * to store the hash. A particular hash algorithm is guaranteed to always generate
131
 * the same amount of data (e.g. 512 bits) but different hash algorithms will output
132
 * different lengths of data. To get the output length of the chosen algorithm \p algorithm,
133
 * call wget_hash_get_len().
134
 *
135
 * \note This function's behavior depends on the underlying cryptographic engine libwget was compiled with.
136
 */
137
int wget_hash_fast(wget_digest_algorithm algorithm, const void *text, size_t textlen, void *digest)
138
{
139
  if ((unsigned) algorithm >= countof(algorithms))
140
    return WGET_E_INVALID;
141
142
  gnutls_digest_algorithm_t hashtype = algorithms[algorithm];
143
  if (hashtype == GNUTLS_DIG_UNKNOWN)
144
    return WGET_E_UNSUPPORTED;
145
146
  if (gnutls_hash_fast(algorithms[algorithm], text, textlen, digest) != 0)
147
    return WGET_E_UNKNOWN;
148
149
  return WGET_E_SUCCESS;
150
}
151
152
/**
153
 * \param[in] algorithm One of the hashing algorithms returned by wget_hash_get_algorithm()
154
 * \return The length of the output data generated by the algorithm
155
 *
156
 * Determines the output length of the given hashing algorithm.
157
 *
158
 * A particular hash algorithm is guaranteed to always generate
159
 * the same amount of data (e.g. 512 bits) but different hash algorithms will output
160
 * different lengths of data.
161
 */
162
int wget_hash_get_len(wget_digest_algorithm algorithm)
163
{
164
  if ((unsigned)algorithm < countof(algorithms))
165
    return gnutls_hash_get_len(algorithms[algorithm]);
166
  else
167
    return 0;
168
}
169
170
/**
171
 * \param[out] handle Caller-provided pointer to a ::wget_hash_hd structure where the handle to this
172
 * hashing primitive will be stored, needed in subsequent calls to wget_hash()
173
 * \param[in] algorithm One of the hashing algorithms returned by wget_hash_get_algorithm()
174
 * \return Zero on success or a negative value on error
175
 *
176
 * Initialize the cryptographic engine to compute hashes with the given hashing algorithm,
177
 * as well as the hashing algorithm itself.
178
 *
179
 * After this function returns, wget_hash() might be called as many times as desired.
180
 */
181
int wget_hash_init(wget_hash_hd **handle, wget_digest_algorithm algorithm)
182
{
183
  if ((unsigned)algorithm >= countof(algorithms))
184
    return WGET_E_INVALID;
185
186
  gnutls_digest_algorithm_t hashtype = algorithms[algorithm];
187
  if (hashtype == GNUTLS_DIG_UNKNOWN)
188
    return WGET_E_UNSUPPORTED;
189
190
  if (!(*handle = wget_malloc(sizeof(struct wget_hash_hd_st))))
191
    return WGET_E_MEMORY;
192
193
  if (gnutls_hash_init(&(*handle)->dig, algorithms[algorithm]) != 0) {
194
    xfree(*handle);
195
    return WGET_E_UNKNOWN;
196
  }
197
198
  return WGET_E_SUCCESS;
199
}
200
201
/**
202
 * \param[in] handle Handle to the hashing primitive returned by a subsequent call to wget_hash_init()
203
 * \param[in] text Input data
204
 * \param[in] textlen Length of the input data
205
 * \return Zero on success or a negative value on error
206
 *
207
 * Update the digest by adding additional input data to it. This method can be called
208
 * as many times as desired. Once finished, call wget_hash_deinit() to complete
209
 * the computation and get the resulting hash.
210
 */
211
int wget_hash(wget_hash_hd *handle, const void *text, size_t textlen)
212
{
213
  return gnutls_hash(handle->dig, text, textlen) == 0 ? 0 : -1;
214
}
215
216
/**
217
 * \param[in] handle Handle to the hashing primitive returned by a subsequent call to wget_hash_init()
218
 * \param[out] digest Caller-supplied buffer where the output hash will be placed.
219
 * \return 0 on success, < 0 on failure
220
 *
221
 * Complete the hash computation by performing final operations, such as padding,
222
 * and obtain the final result. The result will be placed in the caller-supplied
223
 * buffer \p digest. The caller must ensure that the provided output buffer \p digest
224
 * is large enough to store the hash. To get the output length of the chosen algorithm
225
 * \p algorithm, call wget_hash_get_len().
226
 */
227
int wget_hash_deinit(wget_hash_hd **handle, void *digest)
228
{
229
  gnutls_hash_deinit((*handle)->dig, digest);
230
231
  xfree(*handle);
232
233
  return WGET_E_SUCCESS;
234
}
235
236
#elif defined WITH_LIBWOLFCRYPT
237
#define WOLFSSL_SHA224
238
#define WOLFSSL_SHA384
239
#define WOLFSSL_SHA512
240
#define WC_NO_HARDEN
241
#include <wolfssl/options.h>
242
#include <wolfssl/wolfcrypt/hash.h>
243
244
struct wget_hash_hd_st {
245
  wc_HashAlg
246
    hash;
247
  enum wc_HashType
248
    type;
249
};
250
251
static const enum wc_HashType
252
  algorithms[] = {
253
    // [WGET_DIGTYPE_UNKNOWN] = WC_HASH_TYPE_NONE, // both values are 0
254
    // [WGET_DIGTYPE_MD2] = WC_HASH_TYPE_MD2, // not in wc_hashAlg
255
    [WGET_DIGTYPE_MD5] = WC_HASH_TYPE_MD5,
256
    [WGET_DIGTYPE_SHA1] = WC_HASH_TYPE_SHA,
257
    [WGET_DIGTYPE_SHA224] = WC_HASH_TYPE_SHA224,
258
    [WGET_DIGTYPE_SHA256] = WC_HASH_TYPE_SHA256,
259
    [WGET_DIGTYPE_SHA384] = WC_HASH_TYPE_SHA384,
260
    [WGET_DIGTYPE_SHA512] = WC_HASH_TYPE_SHA512,
261
};
262
263
int wget_hash_fast(wget_digest_algorithm algorithm, const void *text, size_t textlen, void *digest)
264
{
265
  if ((unsigned) algorithm >= countof(algorithms))
266
    return WGET_E_INVALID;
267
268
  enum wc_HashType hashtype = algorithms[algorithm];
269
  if (hashtype == WC_HASH_TYPE_NONE)
270
    return WGET_E_UNSUPPORTED;
271
272
  if (wc_Hash(hashtype, text, (unsigned) textlen, digest, wc_HashGetDigestSize(hashtype)) != 0)
273
    return WGET_E_UNKNOWN;
274
275
  return WGET_E_SUCCESS;
276
}
277
278
int wget_hash_get_len(wget_digest_algorithm algorithm)
279
{
280
  if ((unsigned) algorithm < countof(algorithms)) {
281
    int ret = wc_HashGetDigestSize(algorithms[algorithm]);
282
    if (ret > 0)
283
      return ret;
284
  }
285
286
  return 0;
287
}
288
289
int wget_hash_init(wget_hash_hd **handle, wget_digest_algorithm algorithm)
290
{
291
  if ((unsigned) algorithm >= countof(algorithms))
292
    return WGET_E_INVALID;
293
294
  enum wc_HashType hashtype = algorithms[algorithm];
295
  if (hashtype == WC_HASH_TYPE_NONE)
296
    return WGET_E_UNSUPPORTED;
297
298
  if (!(*handle = wget_malloc(sizeof(struct wget_hash_hd_st))))
299
    return WGET_E_MEMORY;
300
301
  if (wc_HashInit(&(*handle)->hash, hashtype) != 0) {
302
    xfree(*handle);
303
    return WGET_E_UNKNOWN;
304
  }
305
306
  (*handle)->type = hashtype;
307
308
  return WGET_E_SUCCESS;
309
}
310
311
int wget_hash(wget_hash_hd *handle, const void *text, size_t textlen)
312
{
313
  if (wc_HashUpdate(&handle->hash, handle->type, text, (unsigned) textlen) == 0)
314
    return WGET_E_SUCCESS;
315
316
  return WGET_E_UNKNOWN;
317
}
318
319
int wget_hash_deinit(wget_hash_hd **handle, void *digest)
320
{
321
  int rc = wc_HashFinal(&(*handle)->hash, (*handle)->type, digest);
322
323
  xfree(*handle);
324
325
  return rc == 0 ? rc : WGET_E_UNKNOWN;
326
}
327
328
#elif defined WITH_LIBCRYPTO
329
#include <openssl/evp.h>
330
331
typedef const EVP_MD *evp_md_func(void);
332
333
struct wget_hash_hd_st {
334
  EVP_MD_CTX
335
    *ctx;
336
};
337
338
static evp_md_func *
339
  algorithms[] = {
340
//    [WGET_DIGTYPE_UNKNOWN] = NULL,
341
//    [WGET_DIGTYPE_MD2]     = EVP_md2,
342
    [WGET_DIGTYPE_MD5]     = EVP_md5,
343
    [WGET_DIGTYPE_RMD160]  = EVP_ripemd160,
344
    [WGET_DIGTYPE_SHA1]    = EVP_sha1,
345
    [WGET_DIGTYPE_SHA224]  = EVP_sha224,
346
    [WGET_DIGTYPE_SHA256]  = EVP_sha256,
347
    [WGET_DIGTYPE_SHA384]  = EVP_sha384,
348
    [WGET_DIGTYPE_SHA512]  = EVP_sha512,
349
  };
350
351
int wget_hash_fast(wget_digest_algorithm algorithm, const void *text, size_t textlen, void *digest)
352
{
353
  if ((unsigned) algorithm >= countof(algorithms))
354
    return WGET_E_INVALID;
355
356
  evp_md_func *evp = algorithms[algorithm];
357
  if (!evp)
358
    return WGET_E_UNSUPPORTED;
359
360
  if (EVP_Digest(text, textlen, digest, NULL, evp(), NULL) == 0)
361
    return WGET_E_UNKNOWN;
362
363
  return WGET_E_SUCCESS;
364
}
365
366
int wget_hash_get_len(wget_digest_algorithm algorithm)
367
{
368
  evp_md_func *evp;
369
370
  if ((unsigned) algorithm >= countof(algorithms)
371
    || (evp = algorithms[algorithm]) == NULL)
372
    return 0;
373
374
  return EVP_MD_size(evp());
375
}
376
377
int wget_hash_init(wget_hash_hd **handle, wget_digest_algorithm algorithm)
378
{
379
  evp_md_func *evp;
380
381
  if ((unsigned) algorithm >= countof(algorithms))
382
    return WGET_E_UNSUPPORTED;
383
384
  if ((evp = algorithms[algorithm]) == NULL)
385
    return WGET_E_UNSUPPORTED;
386
387
  if (!(*handle = wget_malloc(sizeof(struct wget_hash_hd_st))))
388
    return WGET_E_MEMORY;
389
390
  if (!((*handle)->ctx = EVP_MD_CTX_new())) {
391
    xfree(*handle);
392
    return WGET_E_UNKNOWN;
393
  }
394
395
  if (EVP_DigestInit_ex((*handle)->ctx, evp(), NULL))
396
    return WGET_E_SUCCESS;
397
398
  EVP_MD_CTX_free((*handle)->ctx);
399
  xfree(*handle);
400
401
  return WGET_E_UNKNOWN;
402
}
403
404
int wget_hash(wget_hash_hd *handle, const void *text, size_t textlen)
405
{
406
  if (EVP_DigestUpdate(handle->ctx, text, textlen))
407
    return WGET_E_SUCCESS;
408
409
  return WGET_E_INVALID;
410
}
411
412
int wget_hash_deinit(wget_hash_hd **handle, void *digest)
413
{
414
  EVP_DigestFinal_ex((*handle)->ctx, digest, NULL);
415
416
  EVP_MD_CTX_free((*handle)->ctx);
417
  xfree(*handle);
418
419
  return WGET_E_SUCCESS;
420
}
421
422
#elif defined WITH_LIBNETTLE
423
#include <nettle/nettle-meta.h>
424
#include <nettle/md2.h>
425
#include <nettle/md5.h>
426
#include <nettle/ripemd160.h>
427
#include <nettle/sha2.h>
428
429
struct wget_hash_hd_st {
430
  const struct nettle_hash
431
    *hash;
432
  void
433
    *context;
434
};
435
436
static const struct nettle_hash *
437
  algorithms[WGET_DIGTYPE_MAX] = {
438
//    [WGET_DIGTYPE_UNKNOWN] = NULL,
439
    [WGET_DIGTYPE_MD2] = &nettle_md2,
440
    [WGET_DIGTYPE_MD5] = &nettle_md5,
441
#ifdef RIPEMD160_DIGEST_SIZE
442
    [WGET_DIGTYPE_RMD160] = &nettle_ripemd160,
443
#endif
444
    [WGET_DIGTYPE_SHA1] = &nettle_sha1,
445
#ifdef SHA224_DIGEST_SIZE
446
    [WGET_DIGTYPE_SHA224] = &nettle_sha224,
447
#endif
448
#ifdef SHA256_DIGEST_SIZE
449
    [WGET_DIGTYPE_SHA256] = &nettle_sha256,
450
#endif
451
#ifdef SHA384_DIGEST_SIZE
452
    [WGET_DIGTYPE_SHA384] = &nettle_sha384,
453
#endif
454
#ifdef SHA512_DIGEST_SIZE
455
    [WGET_DIGTYPE_SHA512] = &nettle_sha512,
456
#endif
457
};
458
459
int wget_hash_fast(wget_digest_algorithm algorithm, const void *text, size_t textlen, void *digest)
460
326
{
461
326
  wget_hash_hd *dig;
462
326
  int rc;
463
464
326
  if ((rc = wget_hash_init(&dig, algorithm)) == 0) {
465
326
    rc = wget_hash(dig, text, textlen);
466
326
    wget_hash_deinit(&dig, digest);
467
326
  }
468
469
326
  return rc;
470
326
}
471
472
int wget_hash_get_len(wget_digest_algorithm algorithm)
473
1.72k
{
474
1.72k
  if ((unsigned)algorithm < countof(algorithms))
475
1.72k
    return algorithms[algorithm]->digest_size;
476
0
  else
477
0
    return 0;
478
1.72k
}
479
480
int wget_hash_init(wget_hash_hd **handle, wget_digest_algorithm algorithm)
481
326
{
482
326
  if ((unsigned)algorithm >= countof(algorithms))
483
0
    return WGET_E_INVALID;
484
485
326
  if (!algorithms[algorithm])
486
0
    return WGET_E_UNSUPPORTED;
487
488
326
  wget_hash_hd *h;
489
490
326
  if (!(h = wget_malloc(sizeof(struct wget_hash_hd_st))))
491
0
    return WGET_E_MEMORY;
492
493
326
  h->hash = algorithms[algorithm];
494
495
326
  if (!(h->context = wget_malloc(h->hash->context_size))) {
496
0
    xfree(h);
497
0
    return WGET_E_MEMORY;
498
0
  }
499
500
326
  h->hash->init(h->context);
501
326
  *handle = h;
502
503
326
  return WGET_E_SUCCESS;
504
326
}
505
506
int wget_hash(wget_hash_hd *handle, const void *text, size_t textlen)
507
326
{
508
326
  handle->hash->update(handle->context, textlen, text);
509
326
  return WGET_E_SUCCESS;
510
326
}
511
512
int wget_hash_deinit(wget_hash_hd **handle, void *digest)
513
326
{
514
326
  (*handle)->hash->digest((*handle)->context, (*handle)->hash->digest_size, digest);
515
326
  xfree((*handle)->context);
516
326
  xfree(*handle);
517
326
  return WGET_E_SUCCESS;
518
326
}
519
520
#elif defined WITH_GCRYPT
521
#ifdef HAVE_GCRYPT_H
522
  #include <gcrypt.h>
523
#endif
524
525
struct wget_hash_hd_st {
526
  int
527
    algorithm;
528
  gcry_md_hd_t
529
    context;
530
};
531
532
static const int algorithms[] = {
533
//  [WGET_DIGTYPE_UNKNOWN] = GCRY_MD_NONE,
534
  [WGET_DIGTYPE_MD2] = GCRY_MD_MD2,
535
  [WGET_DIGTYPE_MD5] = GCRY_MD_MD5,
536
  [WGET_DIGTYPE_RMD160] = GCRY_MD_RMD160,
537
  [WGET_DIGTYPE_SHA1] = GCRY_MD_SHA1,
538
  [WGET_DIGTYPE_SHA224] = GCRY_MD_SHA224,
539
  [WGET_DIGTYPE_SHA256] = GCRY_MD_SHA256,
540
  [WGET_DIGTYPE_SHA384] = GCRY_MD_SHA384,
541
  [WGET_DIGTYPE_SHA512] = GCRY_MD_SHA512
542
};
543
544
int wget_hash_fast(wget_digest_algorithm algorithm, const void *text, size_t textlen, void *digest)
545
{
546
  wget_hash_hd *dig;
547
  int rc;
548
549
  if ((rc = wget_hash_init(&dig, algorithm)) == 0) {
550
    rc = wget_hash(dig, text, textlen);
551
    wget_hash_deinit(&dig, digest);
552
  }
553
554
  return rc;
555
}
556
557
int wget_hash_get_len(wget_digest_algorithm algorithm)
558
{
559
  if ((unsigned)algorithm < countof(algorithms))
560
    return gcry_md_get_algo_dlen(algorithms[algorithm]);
561
  else
562
    return 0;
563
}
564
565
int wget_hash_init(wget_hash_hd **handle, wget_digest_algorithm algorithm)
566
{
567
  if ((unsigned)algorithm >= countof(algorithms))
568
    return WGET_E_INVALID;
569
570
  if (!algorithms[algorithm])
571
    return WGET_E_UNSUPPORTED;
572
573
  wget_hash_hd *h;
574
575
  if (!(h = wget_malloc(sizeof(struct wget_hash_hd_st))))
576
    return WGET_E_MEMORY;
577
578
  h->algorithm = algorithms[algorithm];
579
  gcry_md_open(&h->context, h->algorithm, 0);
580
581
  *handle = h;
582
583
  return WGET_E_SUCCESS;
584
}
585
586
int wget_hash(wget_hash_hd *handle, const void *text, size_t textlen)
587
{
588
  gcry_md_write(handle->context, text, textlen);
589
  return 0;
590
}
591
592
int wget_hash_deinit(wget_hash_hd **handle, void *digest)
593
{
594
  gcry_md_final((*handle)->context);
595
  void *ret = gcry_md_read((*handle)->context, (*handle)->algorithm);
596
  memcpy(digest, ret, gcry_md_get_algo_dlen((*handle)->algorithm));
597
  gcry_md_close((*handle)->context);
598
  xfree(*handle);
599
600
  return WGET_E_SUCCESS;
601
}
602
603
#else // use the gnulib functions
604
605
#pragma GCC diagnostic push
606
#pragma GCC diagnostic ignored "-Wundef"
607
#include "md2.h"
608
#include "md5.h"
609
#include "sha1.h"
610
#include "sha256.h"
611
#include "sha512.h"
612
#pragma GCC diagnostic pop
613
614
typedef void (*_hash_init_t)(void *);
615
typedef void (*_hash_process_t)(const void *, size_t, void *);
616
typedef void (*_hash_finish_t)(void *, void *);
617
typedef void (*_hash_read_t)(const void *, void *);
618
619
static struct _algorithm {
620
  _hash_init_t init;
621
  _hash_process_t process;
622
  _hash_finish_t finish;
623
  _hash_read_t read;
624
  size_t ctx_len;
625
  size_t digest_len;
626
} _algorithm[WGET_DIGTYPE_MAX] = {
627
  [WGET_DIGTYPE_MD2] = {
628
    (_hash_init_t)md2_init_ctx,
629
    (_hash_process_t)md2_process_bytes,
630
    (_hash_finish_t)md2_finish_ctx,
631
    (_hash_read_t)md2_read_ctx,
632
    sizeof(struct md2_ctx),
633
    MD2_DIGEST_SIZE
634
  },
635
  [WGET_DIGTYPE_MD5] = {
636
    (_hash_init_t)md5_init_ctx,
637
    (_hash_process_t)md5_process_bytes,
638
    (_hash_finish_t)md5_finish_ctx,
639
    (_hash_read_t)md5_read_ctx,
640
    sizeof(struct md5_ctx),
641
    MD5_DIGEST_SIZE
642
  },
643
  [WGET_DIGTYPE_SHA1] = {
644
    (_hash_init_t)sha1_init_ctx,
645
    (_hash_process_t)sha1_process_bytes,
646
    (_hash_finish_t)sha1_finish_ctx,
647
    (_hash_read_t)sha1_read_ctx,
648
    sizeof(struct sha1_ctx),
649
    SHA1_DIGEST_SIZE
650
  },
651
  [WGET_DIGTYPE_SHA224] = {
652
    (_hash_init_t)sha224_init_ctx,
653
    (_hash_process_t)sha256_process_bytes, // sha256 is intentional
654
    (_hash_finish_t)sha224_finish_ctx,
655
    (_hash_read_t)sha224_read_ctx,
656
    sizeof(struct sha256_ctx), // sha256 is intentional
657
    SHA224_DIGEST_SIZE
658
  },
659
  [WGET_DIGTYPE_SHA256] = {
660
    (_hash_init_t)sha256_init_ctx,
661
    (_hash_process_t)sha256_process_bytes,
662
    (_hash_finish_t)sha256_finish_ctx,
663
    (_hash_read_t)sha256_read_ctx,
664
    sizeof(struct sha256_ctx),
665
    SHA256_DIGEST_SIZE
666
  },
667
  [WGET_DIGTYPE_SHA384] = {
668
    (_hash_init_t)sha384_init_ctx,
669
    (_hash_process_t)sha512_process_bytes, // sha512 is intentional
670
    (_hash_finish_t)sha384_finish_ctx,
671
    (_hash_read_t)sha384_read_ctx,
672
    sizeof(struct sha512_ctx), // sha512 is intentional
673
    SHA384_DIGEST_SIZE
674
  },
675
  [WGET_DIGTYPE_SHA512] = {
676
    (_hash_init_t)sha512_init_ctx,
677
    (_hash_process_t)sha512_process_bytes,
678
    (_hash_finish_t)sha512_finish_ctx,
679
    (_hash_read_t)sha512_read_ctx,
680
    sizeof(struct sha512_ctx),
681
    SHA512_DIGEST_SIZE
682
  }
683
};
684
685
struct wget_hash_hd_st {
686
  const struct _algorithm
687
    *algorithm;
688
  void
689
    *context;
690
};
691
692
int wget_hash_fast(wget_digest_algorithm algorithm, const void *text, size_t textlen, void *digest)
693
{
694
  wget_hash_hd *dig;
695
  int rc;
696
697
  if ((rc = wget_hash_init(&dig, algorithm)) == WGET_E_SUCCESS) {
698
    rc = wget_hash(dig, text, textlen);
699
    wget_hash_deinit(&dig, digest);
700
  }
701
702
  return rc;
703
}
704
705
int wget_hash_get_len(wget_digest_algorithm algorithm)
706
{
707
  if ((unsigned)algorithm < countof(_algorithm))
708
    return (int) _algorithm[algorithm].digest_len;
709
  else
710
    return 0;
711
}
712
713
int wget_hash_init(wget_hash_hd **handle, wget_digest_algorithm algorithm)
714
{
715
  if ((unsigned)algorithm >= countof(_algorithm))
716
    return WGET_E_INVALID;
717
718
  if (!_algorithm[algorithm].ctx_len)
719
    return WGET_E_UNSUPPORTED;
720
721
  wget_hash_hd *h;
722
723
  if (!(h = wget_malloc(sizeof(struct wget_hash_hd_st))))
724
    return WGET_E_MEMORY;
725
726
  h->algorithm = &_algorithm[algorithm];
727
728
  if (!(h->context = wget_malloc(h->algorithm->ctx_len))) {
729
    xfree(h);
730
    return WGET_E_MEMORY;
731
  }
732
733
  h->algorithm->init(h->context);
734
  *handle = h;
735
736
  return WGET_E_SUCCESS;
737
}
738
739
int wget_hash(wget_hash_hd *handle, const void *text, size_t textlen)
740
{
741
  handle->algorithm->process(text, textlen, handle->context);
742
  return 0;
743
}
744
745
int wget_hash_deinit(wget_hash_hd **handle, void *digest)
746
{
747
  (*handle)->algorithm->finish((*handle)->context, digest);
748
  xfree((*handle)->context);
749
  xfree(*handle);
750
751
  return WGET_E_SUCCESS;
752
}
753
#endif
754
755
/**
756
 * \param[in] hashname Name of the hashing algorithm. See wget_hash_get_algorithm()
757
 * \param[in] fd File descriptor for the target file
758
 * \param[out] digest_hex caller-supplied buffer that will contain the resulting hex string
759
 * \param[in] digest_hex_size Length of \p digest_hex
760
 * \param[in] offset File offset to start hashing at
761
 * \param[in] length Number of bytes to hash, starting from \p offset. Zero will hash up to the end of the file
762
 * \return 0 on success or -1 in case of failure
763
 *
764
 * Compute the hash of the contents of the target file and return its hex representation.
765
 *
766
 * This function will encode the resulting hash in a string of hex digits, and
767
 * place that string in the user-supplied buffer \p digest_hex.
768
 */
769
int wget_hash_file_fd(const char *hashname, int fd, char *digest_hex, size_t digest_hex_size, off_t offset, off_t length)
770
0
{
771
0
  wget_digest_algorithm algorithm;
772
0
  int ret = WGET_E_UNKNOWN;
773
0
  struct stat st;
774
775
0
  if (digest_hex_size)
776
0
    *digest_hex=0;
777
778
0
  if (fd == -1 || fstat(fd, &st) != 0)
779
0
    return WGET_E_IO;
780
781
0
  if (length == 0)
782
0
    length = st.st_size;
783
784
0
  if (offset + length > st.st_size)
785
0
    return WGET_E_INVALID;
786
787
0
  debug_printf("%s hashing pos %llu, length %llu...\n", hashname, (unsigned long long)offset, (unsigned long long)length);
788
789
0
  if ((algorithm = wget_hash_get_algorithm(hashname)) != WGET_DIGTYPE_UNKNOWN) {
790
0
    unsigned char digest[256];
791
0
    size_t digestlen = wget_hash_get_len(algorithm);
792
793
0
    if (digestlen > sizeof(digest)) {
794
0
      error_printf(_("%s: Unexpected hash len %zu > %zu\n"), __func__, digestlen, sizeof(digest));
795
0
      return ret;
796
0
    }
797
798
0
#ifdef HAVE_MMAP
799
0
    char *buf = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, offset);
800
801
0
    if (buf != MAP_FAILED) {
802
0
      if (wget_hash_fast(algorithm, buf, length, digest) == 0) {
803
0
        wget_memtohex(digest, digestlen, digest_hex, digest_hex_size);
804
0
        debug_printf("  hash %s", digest_hex);
805
0
        ret = WGET_E_SUCCESS;
806
0
      }
807
0
      munmap(buf, length);
808
0
    } else {
809
0
#endif
810
      // Fallback to read
811
0
      ssize_t nbytes = 0;
812
0
      wget_hash_hd *dig;
813
0
      char tmp[65536];
814
815
0
      if ((ret = wget_hash_init(&dig, algorithm))) {
816
0
        error_printf(_("%s: Hash init failed for type '%s': %s\n"), __func__, hashname, wget_strerror(ret));
817
0
        return ret;
818
0
      }
819
820
0
      while (length > 0 && (nbytes = read(fd, tmp, sizeof(tmp))) > 0) {
821
0
        if ((ret = wget_hash(dig, tmp, nbytes))) {
822
0
          error_printf(_("%s: Hash update failed: %s\n"), __func__, wget_strerror(ret));
823
0
          return ret;
824
0
        }
825
826
0
        if (nbytes <= length)
827
0
          length -= nbytes;
828
0
        else
829
0
          length = 0;
830
0
      }
831
832
0
      if ((ret = wget_hash_deinit(&dig, digest))) {
833
0
        error_printf(_("%s: Hash finalization failed: %s\n"), __func__, wget_strerror(ret));
834
0
        return ret;
835
0
      }
836
837
0
      if (nbytes < 0) {
838
0
        error_printf(_("%s: Failed to read %llu bytes\n"), __func__, (unsigned long long)length);
839
0
        return WGET_E_IO;
840
0
      }
841
842
0
      wget_memtohex(digest, digestlen, digest_hex, digest_hex_size);
843
0
      ret = WGET_E_SUCCESS;
844
0
#ifdef HAVE_MMAP
845
0
    }
846
0
#endif
847
0
  }
848
849
0
  return ret;
850
0
}
851
852
/**
853
 * \param[in] hashname Name of the hashing algorithm. See wget_hash_get_algorithm()
854
 * \param[in] fname Target file name
855
 * \param[out] digest_hex Caller-supplied buffer that will contain the resulting hex string
856
 * \param[in] digest_hex_size Length of \p digest_hex
857
 * \param[in] offset File offset to start hashing at
858
 * \param[in] length Number of bytes to hash, starting from \p offset.  Zero will hash up to the end of the file
859
 * \return 0 on success or -1 in case of failure
860
 *
861
 * Compute the hash of the contents of the target file starting from \p offset and up to \p length bytes
862
 * and return its hex representation.
863
 *
864
 * This function will encode the resulting hash in a string of hex digits, and
865
 * place that string in the user-supplied buffer \p digest_hex.
866
 */
867
int wget_hash_file_offset(const char *hashname, const char *fname, char *digest_hex, size_t digest_hex_size, off_t offset, off_t length)
868
0
{
869
0
  int fd, ret;
870
871
0
  if ((fd = open(fname, O_RDONLY|O_BINARY)) == -1) {
872
0
    if (digest_hex_size)
873
0
      *digest_hex=0;
874
0
    return 0;
875
0
  }
876
877
0
  ret = wget_hash_file_fd(hashname, fd, digest_hex, digest_hex_size, offset, length);
878
0
  close(fd);
879
880
0
  return ret;
881
0
}
882
883
/**
884
 * \param[in] hashname Name of the hashing algorithm. See wget_hash_get_algorithm()
885
 * \param[in] fname Target file name
886
 * \param[out] digest_hex Caller-supplied buffer that will contain the resulting hex string
887
 * \param[in] digest_hex_size Length of \p digest_hex
888
 * \return 0 on success or -1 in case of failure
889
 *
890
 * Compute the hash of the contents of the target file and return its hex representation.
891
 *
892
 * This function will encode the resulting hash in a string of hex digits, and
893
 * place that string in the user-supplied buffer \p digest_hex.
894
 */
895
int wget_hash_file(const char *hashname, const char *fname, char *digest_hex, size_t digest_hex_size)
896
0
{
897
0
  return wget_hash_file_offset(hashname, fname, digest_hex, digest_hex_size, 0, 0);
898
0
}
899
900
/**@}*/