libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

unit_md5.c (26950B)


      1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
      2 /*
      3   This file is part of GNU libmicrohttpd.
      4   Copyright (C) 2025 Christian Grothoff
      5 
      6   GNU libmicrohttpd is free software; you can redistribute it and/or
      7   modify it under the terms of the GNU Lesser General Public
      8   License as published by the Free Software Foundation; either
      9   version 2.1 of the License, or (at your option) any later version.
     10 
     11   GNU libmicrohttpd is distributed in the hope that it will be useful,
     12   but WITHOUT ANY WARRANTY; without even the implied warranty of
     13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14   Lesser General Public License for more details.
     15 
     16   Alternatively, you can redistribute GNU libmicrohttpd and/or
     17   modify it under the terms of the GNU General Public License as
     18   published by the Free Software Foundation; either version 2 of
     19   the License, or (at your option) any later version, together
     20   with the eCos exception, as follows:
     21 
     22     As a special exception, if other files instantiate templates or
     23     use macros or inline functions from this file, or you compile this
     24     file and link it with other works to produce a work based on this
     25     file, this file does not by itself cause the resulting work to be
     26     covered by the GNU General Public License. However the source code
     27     for this file must still be made available in accordance with
     28     section (3) of the GNU General Public License v2.
     29 
     30     This exception does not invalidate any other reasons why a work
     31     based on this file might be covered by the GNU General Public
     32     License.
     33 
     34   You should have received copies of the GNU Lesser General Public
     35   License and the GNU General Public License along with this library;
     36   if not, see <https://www.gnu.org/licenses/>.
     37 */
     38 
     39 /**
     40  * @file src/test/unit/unit_md5.c
     41  * @brief  Unit tests for md5 functions
     42  * @author Karlson2k (Evgeny Grin) & Christian Grothoff
     43  */
     44 
     45 #include <stdio.h>
     46 #include <stdlib.h>
     47 #include <string.h>
     48 #include <stdint.h>
     49 
     50 #include "mhd_sys_options.h"
     51 
     52 #if MHD_MD5_EXTR_OPENSSL
     53 #include "../mhd2/md5_ext_openssl.c"
     54 #elif MHD_MD5_EXTR_GNUTLS
     55 #include "../mhd2/md5_ext_gnutls.c"
     56 #elif MHD_MD5_EXTR_MBEDTLS
     57 #include "../mhd2/md5_ext_mbedtls.c"
     58 #else
     59 #include "../mhd2/md5_int.c"
     60 #endif
     61 
     62 #include "../mhd2/mhd_md5.h"
     63 
     64 #define MD5_DIGEST_STRING_SIZE (mhd_MD5_DIGEST_SIZE * 2 + 1)
     65 
     66 /**
     67  * Verbose output?
     68  */
     69 static int verbose;
     70 
     71 
     72 /**
     73  * Check whether one of strings in array is equal to @a param.
     74  * String @a argv[0] is ignored.
     75  * @param argc number of strings in @a argv, as passed to main function
     76  * @param argv array of strings, as passed to main function
     77  * @param param parameter to look for.
     78  * @return zero if @a argv is NULL, @a param is NULL or empty string,
     79  *         @a argc is less then 2 or @a param is not found in @a argv,
     80  *         non-zero if one of strings in @a argv is equal to @a param.
     81  */
     82 static int
     83 has_param (int argc, char *const argv[], const char *param)
     84 {
     85   int i;
     86   if (! argv || ! param || ! param[0])
     87     return 0;
     88 
     89   for (i = 1; i < argc; i++)
     90   {
     91     if (argv[i] && (strcmp (argv[i], param) == 0) )
     92       return ! 0;
     93   }
     94 
     95   return 0;
     96 }
     97 
     98 
     99 /* Define to 1 if libmicrohttpd is compiled with MD5 hashing by OpenSSL. */
    100 /* #undef MHD_MD5_EXTR_OPENSSL */
    101 
    102 /* Helper function to convert hex string to binary */
    103 static size_t
    104 hex2bin (const char *hex,
    105          uint8_t *bin,
    106          size_t max_len)
    107 {
    108   size_t len = strlen (hex) / 2;
    109 
    110   if (len > max_len)
    111     len = max_len;
    112   for (size_t i = 0; i < len; i++)
    113   {
    114     sscanf (hex + 2 * i,
    115             "%2hhx",
    116             &bin[i]);
    117   }
    118   return len;
    119 }
    120 
    121 
    122 /*
    123  *  Helper functions
    124  */
    125 
    126 /**
    127  * Print bin as hex
    128  *
    129  * @param bin binary data
    130  * @param len number of bytes in bin
    131  * @param hex pointer to len*2+1 bytes buffer
    132  */
    133 static void
    134 bin2hex (const uint8_t *bin,
    135          size_t len,
    136          char *hex)
    137 {
    138   while (len-- > 0)
    139   {
    140     unsigned int b1, b2;
    141     b1 = (*bin >> 4) & 0xf;
    142     *hex++ = (char) ((b1 > 9) ? (b1 + 'A' - 10) : (b1 + '0'));
    143     b2 = *bin++ & 0xf;
    144     *hex++ = (char) ((b2 > 9) ? (b2 + 'A' - 10) : (b2 + '0'));
    145   }
    146   *hex = 0;
    147 }
    148 
    149 
    150 static int
    151 check_result (const char *test_name,
    152               unsigned int check_num,
    153               const uint8_t calculated[mhd_MD5_DIGEST_SIZE],
    154               const uint8_t expected[mhd_MD5_DIGEST_SIZE])
    155 {
    156   int failed = memcmp (calculated,
    157                        expected,
    158                        mhd_MD5_DIGEST_SIZE);
    159 
    160   check_num++; /* Print 1-based numbers */
    161   if (failed)
    162   {
    163     char calc_str[MD5_DIGEST_STRING_SIZE];
    164     char expc_str[MD5_DIGEST_STRING_SIZE];
    165 
    166     bin2hex (calculated,
    167              mhd_MD5_DIGEST_SIZE,
    168              calc_str);
    169     bin2hex (expected,
    170              mhd_MD5_DIGEST_SIZE,
    171              expc_str);
    172     fprintf (stderr,
    173              "FAILED: %s check %u: calculated digest %s, expected digest %s.\n",
    174              test_name,
    175              check_num,
    176              calc_str,
    177              expc_str);
    178     fflush (stderr);
    179     return 1;
    180   }
    181   if (verbose)
    182   {
    183     char calc_str[MD5_DIGEST_STRING_SIZE];
    184 
    185     bin2hex (calculated,
    186              mhd_MD5_DIGEST_SIZE,
    187              calc_str);
    188     fprintf (stderr,
    189              "PASSED: %s check %u: calculated digest %s "
    190              "matches expected digest.\n",
    191              test_name,
    192              check_num,
    193              calc_str);
    194     fflush (stdout);
    195   }
    196   return 0;
    197 }
    198 
    199 
    200 struct str_with_len
    201 {
    202   const char *const str;
    203   const size_t len;
    204 };
    205 
    206 #define D_STR_W_LEN(s) {(s), (sizeof((s)) / sizeof(char)) - 1}
    207 
    208 struct data_unit1
    209 {
    210   const struct str_with_len str_l;
    211   const uint8_t digest[mhd_MD5_DIGEST_SIZE];
    212 };
    213 
    214 
    215 static const struct data_unit1 data_units1[] = {
    216   {D_STR_W_LEN ("1234567890!@~%&$@#{}[]\\/!?`."),
    217    {0x1c, 0x68, 0xc2, 0xe5, 0x1f, 0x63, 0xc9, 0x5f, 0x17, 0xab, 0x1f, 0x20,
    218     0x8b, 0x86, 0x39, 0x57}},
    219   {D_STR_W_LEN ("Simple string."),
    220    {0xf1, 0x2b, 0x7c, 0xad, 0xa0, 0x41, 0xfe, 0xde, 0x4e, 0x68, 0x16, 0x63,
    221     0xb4, 0x60, 0x5d, 0x78}},
    222   {D_STR_W_LEN ("abcdefghijklmnopqrstuvwxyz"),
    223    {0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, 0x7d, 0xfb, 0x49, 0x6c,
    224     0xca, 0x67, 0xe1, 0x3b}},
    225   {D_STR_W_LEN ("zyxwvutsrqponMLKJIHGFEDCBA"),
    226    {0x05, 0x61, 0x3a, 0x6b, 0xde, 0x75, 0x3a, 0x45, 0x91, 0xa8, 0x81, 0xb0,
    227     0xa7, 0xe2, 0xe2, 0x0e}},
    228   {D_STR_W_LEN ("abcdefghijklmnopqrstuvwxyzzyxwvutsrqponMLKJIHGFEDCBA" \
    229                 "abcdefghijklmnopqrstuvwxyzzyxwvutsrqponMLKJIHGFEDCBA"),
    230    {0xaf, 0xab, 0xc7, 0xe9, 0xe7, 0x17, 0xbe, 0xd6, 0xc0, 0x0f, 0x78, 0x8c,
    231     0xde, 0xdd, 0x11, 0xd1}},
    232   {D_STR_W_LEN ("/long/long/long/long/long/long/long/long/long/long/long" \
    233                 "/long/long/long/long/long/long/long/long/long/long/long" \
    234                 "/long/long/long/long/long/long/long/long/long/long/long" \
    235                 "/long/long/long/long/long/long/long/long/long/long/long" \
    236                 "/long/long/long/long/long/long/long/long/long/long/long" \
    237                 "/long/long/long/long/long/long/long/long/long/long/long" \
    238                 "/long/long/long/long/path?with%20some=parameters"),
    239    {0x7e, 0xe6, 0xdb, 0xe2, 0x76, 0x49, 0x1a, 0xd8, 0xaf, 0xf3, 0x52, 0x2d,
    240     0xd8, 0xfc, 0x89, 0x1e}},
    241   {D_STR_W_LEN (""),
    242    {0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98,
    243     0xec, 0xf8, 0x42, 0x7e}},
    244   {D_STR_W_LEN ("a"),
    245    {0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, 0x31, 0xc3, 0x99, 0xe2,
    246     0x69, 0x77, 0x26, 0x61}},
    247   {D_STR_W_LEN ("abc"),
    248    {0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6, 0x96, 0x3f, 0x7d,
    249     0x28, 0xe1, 0x7f, 0x72}},
    250   {D_STR_W_LEN ("message digest"),
    251    {0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d, 0x52, 0x5a, 0x2f, 0x31,
    252     0xaa, 0xf1, 0x61, 0xd0}},
    253   {D_STR_W_LEN ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" \
    254                 "0123456789"),
    255    {0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5, 0xa5, 0x61, 0x1c, 0x2c,
    256     0x9f, 0x41, 0x9d, 0x9f}},
    257   {D_STR_W_LEN ("12345678901234567890123456789012345678901234567890" \
    258                 "123456789012345678901234567890"),
    259    {0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55, 0xac, 0x49, 0xda, 0x2e,
    260     0x21, 0x07, 0xb6, 0x7a}}
    261 };
    262 
    263 static const size_t units1_num = sizeof(data_units1) / sizeof(data_units1[0]);
    264 
    265 /* Calculated MD5 as one pass for whole data */
    266 static int
    267 test1_str (void)
    268 {
    269   unsigned int i;
    270   int num_failed = 0;
    271   struct mhd_Md5Ctx ctx;
    272 
    273   mhd_MD5_init_one_time (&ctx);
    274   for (i = 0; i < units1_num; i++)
    275   {
    276     uint8_t digest[mhd_MD5_DIGEST_SIZE];
    277 
    278     mhd_MD5_update (&ctx,
    279                     data_units1[i].str_l.len,
    280                     (const uint8_t *) data_units1[i].str_l.str);
    281     mhd_MD5_finish_reset (&ctx,
    282                           digest);
    283     if (mhd_MD5_has_err (&ctx))
    284     {
    285       fprintf (stderr,
    286                "External hashing error: %d.\n",
    287                ctx.ext_error);
    288       exit (99);
    289     }
    290     num_failed += check_result (MHD_FUNC_,
    291                                 i,
    292                                 digest,
    293                                 data_units1[i].digest);
    294   }
    295   mhd_MD5_deinit (&ctx);
    296   return num_failed;
    297 }
    298 
    299 
    300 struct bin_with_len
    301 {
    302   const uint8_t bin[512];
    303   const size_t len;
    304 };
    305 
    306 struct data_unit2
    307 {
    308   const struct bin_with_len bin_l;
    309   const uint8_t digest[mhd_MD5_DIGEST_SIZE];
    310 };
    311 
    312 
    313 static const struct data_unit2 data_units2[] = {
    314   { { {97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
    315        112, 113, 114, 115, 116,
    316        117, 118, 119, 120, 121, 122}, 26}, /* a..z ASCII sequence */
    317     {0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, 0x7d, 0xfb, 0x49, 0x6c,
    318      0xca, 0x67, 0xe1, 0x3b}},
    319   { { {65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
    320        65, 65, 65, 65, 65, 65,
    321        65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
    322        65, 65, 65, 65, 65, 65,
    323        65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
    324        65, 65, 65, 65, 65, 65}, 72 },/* 'A' x 72 times */
    325     {0x24, 0xa5, 0xef, 0x36, 0x82, 0x80, 0x3a, 0x06, 0x2f, 0xea, 0xad, 0xad,
    326      0x76, 0xda, 0xbd, 0xa8}},
    327   { { {19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
    328        37, 38, 39, 40, 41, 42,
    329        43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
    330        61, 62, 63, 64, 65, 66, 67,
    331        68, 69, 70, 71, 72, 73}, 55}, /* 19..73 sequence */
    332     {0x6d, 0x2e, 0x6e, 0xde, 0x5d, 0x64, 0x6a, 0x17, 0xf1, 0x09, 0x2c, 0xac,
    333      0x19, 0x10, 0xe3, 0xd6}},
    334   { { {7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
    335        26, 27, 28, 29, 30, 31,
    336        32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
    337        50, 51, 52, 53, 54, 55, 56,
    338        57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69}, 63}, /* 7..69 sequence */
    339     {0x88, 0x13, 0x48, 0x47, 0x73, 0xaa, 0x92, 0xf2, 0xc9, 0xdd, 0x69, 0xb3,
    340      0xac, 0xf4, 0xba, 0x6e}},
    341   { { {38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
    342        56, 57, 58, 59, 60, 61,
    343        62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
    344        80, 81, 82, 83, 84, 85, 86,
    345        87, 88, 89, 90, 91, 92}, 55}, /* 38..92 sequence */
    346     {0x80, 0xf0, 0x05, 0x7e, 0xa2, 0xf7, 0xc8, 0x43, 0x12, 0xd3, 0xb1, 0x61,
    347      0xab, 0x52, 0x3b, 0xaf}},
    348   { { {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
    349        21, 22, 23, 24, 25, 26, 27,
    350        28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
    351        46, 47, 48, 49, 50, 51, 52,
    352        53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
    353        71, 72},
    354       72},/* 1..72 sequence */
    355     {0xc3, 0x28, 0xc5, 0xad, 0xc9, 0x26, 0xa9, 0x99, 0x95, 0x4a, 0x5e, 0x25,
    356      0x50, 0x34, 0x51, 0x73}},
    357   { { {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
    358        21, 22, 23, 24, 25, 26,
    359        27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
    360        45, 46, 47, 48, 49, 50, 51,
    361        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
    362        70, 71, 72, 73, 74, 75, 76,
    363        77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
    364        95, 96, 97, 98, 99, 100,
    365        101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
    366        115, 116, 117, 118, 119, 120,
    367        121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
    368        135, 136, 137, 138, 139, 140,
    369        141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
    370        155, 156, 157, 158, 159, 160,
    371        161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174,
    372        175, 176, 177, 178, 179, 180,
    373        181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
    374        195, 196, 197, 198, 199, 200,
    375        201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214,
    376        215, 216, 217, 218, 219, 220,
    377        221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234,
    378        235, 236, 237, 238, 239, 240,
    379        241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
    380        255}, 256},                                                                        /* 0..255 sequence */
    381     {0xe2, 0xc8, 0x65, 0xdb, 0x41, 0x62, 0xbe, 0xd9, 0x63, 0xbf, 0xaa, 0x9e,
    382      0xf6, 0xac, 0x18, 0xf0}},
    383   { { {199, 198, 197, 196, 195, 194, 193, 192, 191, 190, 189, 188, 187, 186,
    384        185, 184, 183, 182, 181, 180,
    385        179, 178, 177, 176, 175, 174, 173, 172, 171, 170, 169, 168, 167, 166,
    386        165, 164, 163, 162, 161, 160,
    387        159, 158, 157, 156, 155, 154, 153, 152, 151, 150, 149, 148, 147, 146,
    388        145, 144, 143, 142, 141, 140,
    389        139}, 61},  /* 199..139 sequence */
    390     {0xbb, 0x3f, 0xdb, 0x4a, 0x96, 0x03, 0x36, 0x37, 0x38, 0x78, 0x5e, 0x44,
    391      0xbf, 0x3a, 0x85, 0x51}},
    392   { { {255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242,
    393        241, 240, 239, 238, 237, 236,
    394        235, 234, 233, 232, 231, 230, 229, 228, 227, 226, 225, 224, 223, 222,
    395        221, 220, 219, 218, 217, 216,
    396        215, 214, 213, 212, 211, 210, 209, 208, 207, 206, 205, 204, 203, 202,
    397        201, 200, 199, 198, 197, 196,
    398        195, 194, 193, 192, 191, 190, 189, 188, 187, 186, 185, 184, 183, 182,
    399        181, 180, 179, 178, 177, 176,
    400        175, 174, 173, 172, 171, 170, 169, 168, 167, 166, 165, 164, 163, 162,
    401        161, 160, 159, 158, 157, 156,
    402        155, 154, 153, 152, 151, 150, 149, 148, 147, 146, 145, 144, 143, 142,
    403        141, 140, 139, 138, 137, 136,
    404        135, 134, 133, 132, 131, 130, 129, 128, 127, 126, 125, 124, 123, 122,
    405        121, 120, 119, 118, 117, 116,
    406        115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102,
    407        101, 100, 99, 98, 97, 96, 95,
    408        94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77,
    409        76, 75, 74, 73, 72, 71, 70,
    410        69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52,
    411        51, 50, 49, 48, 47, 46, 45,
    412        44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27,
    413        26, 25, 24, 23, 22, 21, 20,
    414        19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, 255},  /* 255..1 sequence */
    415     {0x52, 0x21, 0xa5, 0x83, 0x4f, 0x38, 0x7c, 0x73, 0xba, 0x18, 0x22, 0xb1,
    416      0xf9, 0x7e, 0xae, 0x8b}},
    417   { { {41, 35, 190, 132, 225, 108, 214, 174, 82, 144, 73, 241, 241, 187, 233,
    418        235, 179, 166, 219, 60, 135,
    419        12, 62, 153, 36, 94, 13, 28, 6, 183, 71, 222, 179, 18, 77, 200, 67, 187,
    420        139, 166, 31, 3, 90, 125, 9,
    421        56, 37, 31, 93, 212, 203, 252, 150, 245, 69, 59, 19, 13, 137, 10, 28,
    422        219, 174, 50, 32, 154, 80, 238,
    423        64, 120, 54, 253, 18, 73, 50, 246, 158, 125, 73, 220, 173, 79, 20, 242,
    424        68, 64, 102, 208, 107, 196,
    425        48, 183, 50, 59, 161, 34, 246, 34, 145, 157, 225, 139, 31, 218, 176, 202,
    426        153, 2, 185, 114, 157, 73,
    427        44, 128, 126, 197, 153, 213, 233, 128, 178, 234, 201, 204, 83, 191, 103,
    428        214, 191, 20, 214, 126, 45,
    429        220, 142, 102, 131, 239, 87, 73, 97, 255, 105, 143, 97, 205, 209, 30,
    430        157, 156, 22, 114, 114, 230,
    431        29, 240, 132, 79, 74, 119, 2, 215, 232, 57, 44, 83, 203, 201, 18, 30, 51,
    432        116, 158, 12, 244, 213,
    433        212, 159, 212, 164, 89, 126, 53, 207, 50, 34, 244, 204, 207, 211, 144,
    434        45, 72, 211, 143, 117, 230,
    435        217, 29, 42, 229, 192, 247, 43, 120, 129, 135, 68, 14, 95, 80, 0, 212,
    436        97, 141, 190, 123, 5, 21, 7,
    437        59, 51, 130, 31, 24, 112, 146, 218, 100, 84, 206, 177, 133, 62, 105, 21,
    438        248, 70, 106, 4, 150, 115,
    439        14, 217, 22, 47, 103, 104, 212, 247, 74, 74, 208, 87, 104}, 255},  /* pseudo-random data */
    440     {0x55, 0x61, 0x2c, 0xeb, 0x29, 0xee, 0xa8, 0xb2, 0xf6, 0x10, 0x7b, 0xc1,
    441      0x5b, 0x0f, 0x01, 0x95}}
    442 };
    443 static const size_t units2_num = sizeof(data_units2) / sizeof(data_units2[0]);
    444 
    445 
    446 static int
    447 test1_bin (void)
    448 {
    449   unsigned int i;
    450   int num_failed = 0;
    451   struct mhd_Md5Ctx ctx;
    452 
    453   mhd_MD5_init_one_time (&ctx);
    454   for (i = 0; i < units2_num; i++)
    455   {
    456     uint8_t digest[mhd_MD5_DIGEST_SIZE];
    457 
    458     mhd_MD5_update (&ctx,
    459                     data_units2[i].bin_l.len,
    460                     data_units2[i].bin_l.bin);
    461     mhd_MD5_finish_reset (&ctx,
    462                           digest);
    463     if (mhd_MD5_has_err (&ctx))
    464     {
    465       fprintf (stderr,
    466                "External hashing error: %d.\n",
    467                ctx.ext_error);
    468       exit (99);
    469     }
    470     num_failed += check_result (MHD_FUNC_,
    471                                 i,
    472                                 digest,
    473                                 data_units2[i].digest);
    474   }
    475   mhd_MD5_deinit (&ctx);
    476   return num_failed;
    477 }
    478 
    479 
    480 /* Calculated MD5 as two iterations for whole data */
    481 static int
    482 test2_str (void)
    483 {
    484   unsigned int i;
    485   int num_failed = 0;
    486   struct mhd_Md5Ctx ctx;
    487 
    488   mhd_MD5_init_one_time (&ctx);
    489   for (i = 0; i < units1_num; i++)
    490   {
    491     uint8_t digest[mhd_MD5_DIGEST_SIZE];
    492     size_t part_s = data_units1[i].str_l.len / 4;
    493 
    494     mhd_MD5_update (&ctx,
    495                     0,
    496                     (const uint8_t *) "");
    497     mhd_MD5_update (&ctx,
    498                     part_s,
    499                     (const uint8_t *) data_units1[i].str_l.str);
    500     mhd_MD5_update (&ctx,
    501                     0,
    502                     (const uint8_t *) "");
    503     mhd_MD5_update (&ctx,
    504                     data_units1[i].str_l.len - part_s,
    505                     (const uint8_t *) data_units1[i].str_l.str + part_s);
    506     mhd_MD5_update (&ctx,
    507                     0,
    508                     (const uint8_t *) "");
    509     mhd_MD5_finish_reset (&ctx,
    510                           digest);
    511     if (mhd_MD5_has_err (&ctx))
    512     {
    513       fprintf (stderr,
    514                "External hashing error: %d.\n",
    515                ctx.ext_error);
    516       exit (99);
    517     }
    518     num_failed += check_result (MHD_FUNC_,
    519                                 i,
    520                                 digest,
    521                                 data_units1[i].digest);
    522   }
    523   mhd_MD5_deinit (&ctx);
    524   return num_failed;
    525 }
    526 
    527 
    528 static int
    529 test2_bin (void)
    530 {
    531   unsigned int i;
    532   int num_failed = 0;
    533   struct mhd_Md5Ctx ctx;
    534 
    535   mhd_MD5_init_one_time (&ctx);
    536 
    537   for (i = 0; i < units2_num; i++)
    538   {
    539     uint8_t digest[mhd_MD5_DIGEST_SIZE];
    540     size_t part_s = data_units2[i].bin_l.len * 2 / 3;
    541 
    542     mhd_MD5_update (&ctx,
    543                     part_s,
    544                     data_units2[i].bin_l.bin);
    545     mhd_MD5_update (&ctx,
    546                     0,
    547                     (const uint8_t *) "");
    548     mhd_MD5_update (&ctx,
    549                     data_units2[i].bin_l.len - part_s,
    550                     data_units2[i].bin_l.bin + part_s);
    551     mhd_MD5_finish_reset (&ctx,
    552                           digest);
    553     if (mhd_MD5_has_err (&ctx))
    554     {
    555       fprintf (stderr,
    556                "External hashing error: %d.\n",
    557                ctx.ext_error);
    558       exit (99);
    559     }
    560     num_failed += check_result (MHD_FUNC_,
    561                                 i,
    562                                 digest,
    563                                 data_units2[i].digest);
    564   }
    565   mhd_MD5_deinit (&ctx);
    566   return num_failed;
    567 }
    568 
    569 
    570 /* Use data set number 7 as it has the longest sequence */
    571 #define DATA_POS 6
    572 #define MAX_OFFSET 31
    573 
    574 static int
    575 test_unaligned (void)
    576 {
    577   const struct data_unit2 *const tdata = data_units2 + DATA_POS;
    578   int num_failed = 0;
    579   unsigned int offset;
    580   uint8_t *buf;
    581   uint8_t *digest_buf;
    582   struct mhd_Md5Ctx ctx;
    583 
    584   buf = malloc (tdata->bin_l.len + MAX_OFFSET);
    585   digest_buf = malloc (mhd_MD5_DIGEST_SIZE + MAX_OFFSET);
    586   if ( (NULL == buf) ||
    587        (NULL == digest_buf) )
    588     exit (99);
    589 
    590   mhd_MD5_init_one_time (&ctx);
    591 
    592   for (offset = MAX_OFFSET; offset >= 1; --offset)
    593   {
    594     uint8_t *unaligned_digest;
    595     uint8_t *unaligned_buf;
    596 
    597     unaligned_buf = buf + offset;
    598     memcpy (unaligned_buf,
    599             tdata->bin_l.bin,
    600             tdata->bin_l.len);
    601     unaligned_digest = digest_buf + MAX_OFFSET - offset;
    602     memset (unaligned_digest,
    603             0,
    604             mhd_MD5_DIGEST_SIZE);
    605     mhd_MD5_update (&ctx,
    606                     tdata->bin_l.len,
    607                     unaligned_buf);
    608     mhd_MD5_finish_reset (&ctx,
    609                           unaligned_digest);
    610     if (mhd_MD5_has_err (&ctx))
    611     {
    612       fprintf (stderr,
    613                "External hashing error: %d.\n",
    614                ctx.ext_error);
    615       exit (99);
    616     }
    617     num_failed += check_result (MHD_FUNC_,
    618                                 MAX_OFFSET - offset,
    619                                 unaligned_digest,
    620                                 tdata->digest);
    621   }
    622   mhd_MD5_deinit (&ctx);
    623   free (digest_buf);
    624   free (buf);
    625   return num_failed;
    626 }
    627 
    628 
    629 /* Helper function to compare digest with expected hex string */
    630 static int
    631 check_digest (const uint8_t *digest,
    632               size_t digest_len,
    633               const char *expected_hex,
    634               const char *test_name)
    635 {
    636   uint8_t expected[64];
    637   size_t expected_len = hex2bin (expected_hex,
    638                                  expected,
    639                                  sizeof(expected));
    640 
    641   if (expected_len != digest_len)
    642   {
    643     printf ("FAIL: %s - length mismatch\n",
    644             test_name);
    645     return 0;
    646   }
    647 
    648   if (0 !=
    649       memcmp (digest,
    650               expected,
    651               digest_len))
    652   {
    653     printf ("FAIL: %s\n",
    654             test_name);
    655     printf ("  Expected: %s\n",
    656             expected_hex);
    657     printf ("  Got:      ");
    658     for (size_t i = 0; i < digest_len; i++)
    659     {
    660       printf ("%02x",
    661               digest[i]);
    662     }
    663     printf ("\n");
    664     return 0;
    665   }
    666   return 1;
    667 }
    668 
    669 
    670 int
    671 main (int argc,
    672       char **argv)
    673 {
    674   struct Test
    675   {
    676     const char *name;
    677     const char *input;
    678     const char *digest;
    679   } tests[] = {
    680     { "Empty string (RFC 1321)",
    681       "",
    682       "d41d8cd98f00b204e9800998ecf8427e" },
    683     { "a (RFC 1321)",
    684       "61",
    685       "0cc175b9c0f1b6a831c399e269772661" },
    686     { "abc (RFC 1321)",
    687       "616263",
    688       "900150983cd24fb0d6963f7d28e17f72" },
    689     { "a (RFC 1321)",
    690       "61",
    691       "0cc175b9c0f1b6a831c399e269772661" },
    692     { "message digest (RFC 1321)",
    693       "6d65737361676520646967657374",
    694       "f96b697d7cb7938d525a2f31aaf161d0" },
    695     { "abcdefghijklmnopqrstuvwxyz (RFC 1321)",
    696       "6162636465666768696A6B6C6D6E6F707172737475767778797A",
    697       "c3fcd3d76192e4007dfb496cca67e13b" },
    698     { "A-Za-z0-9 (RFC 1321)",
    699       "4142434445464748494A4B4C4D4E4F505152535455565758595A6162636465666768696A6B6C6D6E6F707172737475767778797A30313233343536373839",
    700       "d174ab98d277d9f5a5611c2c9f419d9f" },
    701     { "8 repetitions of 1234567890 (RFC 1321)",
    702       "3132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930",
    703       "57edf4a22be3c955ac49da2e2107b67a" },
    704     { "The quick brown fox jumps over the lazy dog (Wikipedia MD5 article)",
    705       "54686520717569636B2062726F776E20666F78206A756D7073206F76657220746865206C617A7920646F67",
    706       "9e107d9d372bb6826bd81d3542a419d6" },
    707     { "0x00",
    708       "00",
    709       "93b885adfe0da089cdf634904fd59f71" },
    710     { "Two bytes 0x00 0x00",
    711       "0000",
    712       "c4103f122d27677c9db144cae1394a66" },
    713     { NULL, NULL, NULL }
    714   };
    715   struct mhd_Md5Ctx ctx;
    716   uint8_t digest[mhd_MD5_DIGEST_SIZE];
    717   uint8_t data[1024];
    718   size_t data_len;
    719   unsigned int passed = 0;
    720   unsigned int total = 0;
    721   unsigned int num_failed;
    722 
    723   if (has_param (argc, argv, "-v") ||
    724       has_param (argc, argv, "--verbose"))
    725     verbose = 1;
    726   while (NULL != tests[total].name)
    727   {
    728     const struct Test *t = &tests[total];
    729 
    730     mhd_MD5_init_one_time (&ctx);
    731     if (! mhd_MD5_has_err (&ctx))
    732     {
    733       data_len = hex2bin (t->input,
    734                           data,
    735                           sizeof(data));
    736       if (0 != data_len)
    737         mhd_MD5_update (&ctx,
    738                         data_len,
    739                         data);
    740       mhd_MD5_finish_deinit (&ctx,
    741                              digest);
    742       if (! mhd_MD5_has_err (&ctx))
    743       {
    744         if (check_digest (digest,
    745                           mhd_MD5_DIGEST_SIZE,
    746                           t->digest,
    747                           t->name))
    748           passed++;
    749       }
    750       else
    751       {
    752         printf ("FAIL: %s - error in finish\n",
    753                 t->name);
    754       }
    755     }
    756     else
    757     {
    758       printf ("FAIL: %s - error in init\n",
    759               t->name);
    760     }
    761     total++;
    762   }
    763 
    764   /*
    765    * Test update functionality
    766    */
    767   total++;
    768   mhd_MD5_init_one_time (&ctx);
    769   if (! mhd_MD5_has_err (&ctx))
    770   {
    771     data[0] = 'a';
    772     mhd_MD5_update (&ctx,
    773                     1,
    774                     data);
    775     data[0] = 'b';
    776     mhd_MD5_update (&ctx,
    777                     1,
    778                     data);
    779     data[0] = 'c';
    780     mhd_MD5_update (&ctx,
    781                     1,
    782                     data);
    783     mhd_MD5_finish_deinit (&ctx,
    784                            digest);
    785     if (! mhd_MD5_has_err (&ctx))
    786     {
    787       if (check_digest (digest,
    788                         mhd_MD5_DIGEST_SIZE,
    789                         "900150983cd24fb0d6963f7d28e17f72",
    790                         "Multi-update: a + b + c"))
    791         passed++;
    792     }
    793   }
    794 
    795   /*
    796    * Tests finish_reset and reuse of context
    797    */
    798   total++;
    799   mhd_MD5_init_one_time (&ctx);
    800   if (! mhd_MD5_has_err (&ctx))
    801   {
    802     /* First hash */
    803     data_len = hex2bin ("616263",
    804                         data,
    805                         sizeof(data)); /* "abc" */
    806     mhd_MD5_update (&ctx, data_len, data);
    807     mhd_MD5_finish_reset (&ctx, digest);
    808 
    809     /* Second hash on same context */
    810     data_len = hex2bin ("616263", data, sizeof(data)); /* "abc" again */
    811     mhd_MD5_update (&ctx, data_len, data);
    812     mhd_MD5_finish_deinit (&ctx, digest);
    813 
    814     if (! mhd_MD5_has_err (&ctx))
    815     {
    816       if (check_digest (digest,
    817                         mhd_MD5_DIGEST_SIZE,
    818                         "900150983cd24fb0d6963f7d28e17f72",
    819                         "Reset and reuse context"))
    820         passed++;
    821     }
    822   }
    823 
    824   num_failed = total - passed;
    825   num_failed += test1_str ();
    826   num_failed += test1_bin ();
    827   num_failed += test2_str ();
    828   num_failed += test2_bin ();
    829   num_failed += test_unaligned ();
    830 
    831   printf ("Results: %u tests failed\n",
    832           num_failed);
    833 
    834   return (0 == num_failed) ? 0 : 1;
    835 }