libmicrohttpd2

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

unit_md5.c (26513B)


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