libmicrohttpd2

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

unit_md5.c (29962B)


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