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 }