aboutsummaryrefslogblamecommitdiffstats
path: root/test.c
blob: 38b0d85aca01b31822982ab7219103aad67ed313 (plain) (tree)




















































































































































































































































































































                                                                                                                                                                                                                             
/* See LICENSE file for copyright and license details. */
#include "libsha1.h"

#include <sys/wait.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>


#define test(EXPR)\
	do {\
		if (EXPR)\
			break;\
		fprintf(stderr, "Failure at line %i: %s\n", __LINE__, #EXPR);\
		exit(1);\
	} while (0)

#define test_str(HAVE, EXPECTED)\
	do {\
		if (!strcmp(HAVE, EXPECTED))\
			break;\
		fprintf(stderr, "Failure at line %i: expected \"%s\", got \"%s\"\n", __LINE__, EXPECTED, HAVE);\
		exit(1);\
	} while (0)

#define test_repeated(CHR, N, ALGO, EXPECTED)\
	do {\
		memset(buf, CHR, N);\
		test(!libsha1_init(&s, ALGO));\
		libsha1_digest(&s, buf, (N) * 8, buf);\
		libsha1_behex_lower(str, buf, libsha1_state_output_size(&s));\
		test_str(str, EXPECTED);\
	} while (0)

#define test_repeated_huge(CHR, N, ALGO, EXPECTED)\
	do {\
		size_t n__ = N;\
		if (skip_huge)\
			break;\
		memset(buf, CHR, sizeof(buf));\
		test(!libsha1_init(&s, ALGO));\
		fprintf(stderr, "processing huge message: 0 %%\n");\
		for (; n__ > sizeof(buf); n__ -= sizeof(buf)) {\
			libsha1_update(&s, buf, sizeof(buf) * 8);\
			fprintf(stderr, "\033[A\033[Kprocessing huge message: %zu %%\n", ((N) - n__) * 100 / (N));\
		}\
		libsha1_update(&s, buf, n__ * 8);\
		fprintf(stderr, "\033[A\033[K");\
		fflush(stderr);\
		libsha1_digest(&s, NULL, 0, buf);\
		libsha1_behex_lower(str, buf, libsha1_state_output_size(&s));\
		test_str(str, EXPECTED);\
	} while (0)

#define test_custom(S, ALGO, EXPECTED)\
	do {\
		test(!libsha1_init(&s, ALGO));\
		libsha1_digest(&s, S, (sizeof(S) - 1) * 8, buf);\
		libsha1_behex_lower(str, buf, libsha1_state_output_size(&s));\
		test_str(str, EXPECTED);\
	} while (0)

#define test_bits(S, N, ALGO, EXPECTED)\
	do {\
		libsha1_unhex(buf, S);\
		test(!libsha1_init(&s, ALGO));\
		libsha1_digest(&s, buf, N, buf);\
		libsha1_behex_lower(str, buf, libsha1_state_output_size(&s));\
		test_str(str, EXPECTED);\
	} while (0)

#define test_hmac(ALGO, TEXT, KEY, MAC)\
	do {\
		libsha1_unhex(buf, KEY);\
		test(!libsha1_hmac_init(&hs, ALGO, buf, (sizeof(KEY) - 1) << 2));\
		libsha1_unhex(buf, TEXT);\
		libsha1_hmac_digest(&hs, buf, (sizeof(TEXT) - 1) << 2, buf);\
		libsha1_behex_lower(str, buf, libsha1_hmac_state_output_size(&hs));\
		test_str(str, MAC);\
	} while (0)


int
main(int argc, char *argv[])
{
	char buf[8096], str[2048];
	struct libsha1_state s;
	struct libsha1_hmac_state hs;
	int skip_huge, fds[2], status;
	size_t i, j, n, len;
	ssize_t r;
	pid_t pid;

	skip_huge = (argc == 2 && !strcmp(argv[1], "skip-huge"));

	libsha1_behex_lower(buf, "", 0);
	test_str(buf, "");

	libsha1_behex_lower(buf, "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF", 16);
	test_str(buf, "00112233445566778899aabbccddeeff");

	libsha1_behex_lower(buf, "\x1E\x5A\xC0", 3);
	test_str(buf, "1e5ac0");

	libsha1_behex_upper(buf, "", 0);
	test_str(buf, "");

	libsha1_behex_upper(buf, "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF", 16);
	test_str(buf, "00112233445566778899AABBCCDDEEFF");

	libsha1_behex_upper(buf, "\x1E\x5A\xC0", 3);
	test_str(buf, "1E5AC0");

	libsha1_unhex(buf, "");
	test(!memcmp(buf, "", 0));

	libsha1_unhex(buf, "00112233445566778899AABBCCDDEEFF");
	test(!memcmp(buf, "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF", 16));

	libsha1_unhex(buf, "1E5AC0");
	test(!memcmp(buf, "\x1E\x5A\xC0", 3));

	libsha1_unhex(buf, "00112233445566778899aabbccddeeff");
	test(!memcmp(buf, "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF", 16));

	libsha1_unhex(buf, "1e5ac0");
	test(!memcmp(buf, "\x1E\x5A\xC0", 3));

	libsha1_unhex(buf, "AAbbCcdD");
	test(!memcmp(buf, "\xAA\xBB\xCC\xDD", 4));

	test(libsha1_algorithm_output_size(LIBSHA1_0) == 20);
	test(libsha1_algorithm_output_size(LIBSHA1_1) == 20);
	test(!errno);
	test(libsha1_algorithm_output_size(~0) == 0); /* should test `errno == EINVAL`, optimising compiler breaks it */

	errno = 0;
	test(libsha1_init(&s, ~0) == -1 && errno == EINVAL);
	errno = 0;

#ifdef TODO
	test(!libsha1_init(&s, LIBSHA1_0));
	test(libsha1_state_output_size(&s) == 20);
	libsha1_digest(&s, "", 0, buf);
	libsha1_behex_lower(str, buf, libsha1_state_output_size(&s));
	test_str(str, "");
#endif

	test(!libsha1_init(&s, LIBSHA1_1));
	test(libsha1_state_output_size(&s) == 20);
	libsha1_digest(&s, "", 0, buf);
	libsha1_behex_lower(str, buf, libsha1_state_output_size(&s));
	test_str(str, "da39a3ee5e6b4b0d3255bfef95601890afd80709");

#ifdef TODO
	test_repeated(0xFF, 1, LIBSHA1_0, "");
	test_custom("\xE5\xE0\x99\x24", LIBSHA1_0, "");
	test_repeated(0x00, 56, LIBSHA1_0, "");
	test_repeated(0x51, 1000, LIBSHA1_0, "");
	test_repeated(0x41, 1000, LIBSHA1_0, "");
	test_repeated(0x99, 1005, LIBSHA1_0, "");
	test_repeated_huge(0x00, 1000000UL, LIBSHA1_0, "");
	test_repeated_huge(0x41, 0x20000000UL, LIBSHA1_0, "");
	test_repeated_huge(0x00, 0x41000000UL, LIBSHA1_0, "");
	test_repeated_huge(0x84, 0x6000003FUL, LIBSHA1_0, "");
	test_custom("abc", LIBSHA1_0, "");
	test_custom("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", LIBSHA1_1,
	            "");
#endif

	test_repeated(0xFF, 1, LIBSHA1_1, "85e53271e14006f0265921d02d4d736cdc580b0b");
	test_custom("\xE5\xE0\x99\x24", LIBSHA1_1, "d1dffbc8a175dd8eebe0da87b1792b6dc1018e82");
	test_repeated(0x00, 56, LIBSHA1_1, "9438e360f578e12c0e0e8ed28e2c125c1cefee16");
	test_repeated(0x51, 1000, LIBSHA1_1, "49f1cfe3829963158e2b2b2cb5df086cee2e3bb0");
	test_repeated(0x41, 1000, LIBSHA1_1, "3ae3644d6777a1f56a1defeabc74af9c4b313e49");
	test_repeated(0x99, 1005, LIBSHA1_1, "18685d56c8bf67c3cee4443e9a78f65c30752f5d");
	test_repeated_huge(0x00, 1000000UL, LIBSHA1_1, "bef3595266a65a2ff36b700a75e8ed95c68210b6");
	test_repeated_huge(0x41, 0x20000000UL, LIBSHA1_1, "df3f26fce8fa7bec2c61d0506749a320ac7dc942");
	test_repeated_huge(0x00, 0x41000000UL, LIBSHA1_1, "320c617b0b6ee1b6f9c3271eae135f40cae22c10");
	test_repeated_huge(0x84, 0x6000003FUL, LIBSHA1_1, "b20aa99b62e6a480fd93b4d24b2c19ffac649bb8");
	test_custom("abc", LIBSHA1_1, "a9993e364706816aba3e25717850c26c9cd0d89d");
	test_custom("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", LIBSHA1_1,
	            "84983e441c3bd26ebaae4aa1f95129e5e54670f1");

	for (i = 0; i < 1000; i++) {
#ifdef TODO
		for (j = 0; j < 2; j++) {
#else
		for (j = 1; j < 2; j++) {
#endif
			memset(buf, 0x41, 1000);
			test(!libsha1_init(&s, (enum libsha1_algorithm)j));
			libsha1_update(&s, buf, i * 8);
			libsha1_digest(&s, buf, (1000 - i) * 8, buf);
			libsha1_behex_lower(str, buf, libsha1_state_output_size(&s));
			test_str(str, ((const char *[]){
				"",
				"3ae3644d6777a1f56a1defeabc74af9c4b313e49"
			})[j]);

			memset(buf, 0x41, 1000);
			test(!libsha1_init(&s, (enum libsha1_algorithm)j));
			libsha1_update(&s, buf, i * 8);
			libsha1_update(&s, buf, (1000 - i) * 8);
			libsha1_digest(&s, NULL, 0, buf);
			libsha1_behex_lower(str, buf, libsha1_state_output_size(&s));
			test_str(str, ((const char *[]){
				"",
				"3ae3644d6777a1f56a1defeabc74af9c4b313e49"
			})[j]);

			if (!i)
				continue;

			memset(buf, 0x41, 1000);
			test(!libsha1_init(&s, (enum libsha1_algorithm)j));
			for (n = 0; n + i < 1000; n += i) {
				libsha1_update(&s, buf, i * 8);
				test((len = libsha1_marshal(&s, NULL)) && len <= sizeof(str));
				test(libsha1_marshal(&s, str) == len);
				memset(&s, 0, sizeof(s));
				test(libsha1_unmarshal(&s, str, sizeof(str)) == len);
			}
			libsha1_digest(&s, buf, (1000 - n) * 8, buf);
			libsha1_behex_lower(str, buf, libsha1_state_output_size(&s));
			test_str(str, ((const char *[]){
				"",
				"3ae3644d6777a1f56a1defeabc74af9c4b313e49"
			})[j]);
		}
	}

	test(!errno);

	test(!pipe(fds));
	test((pid = fork()) >= 0);
	if (!pid) {
		close(fds[0]);
		memset(buf, 0x41, 1000);
		for (n = 1000; n; n -= (size_t)r)
			test((r = write(fds[1], buf, n < 8 ? n : 8)) > 0);
		exit(0);
	}
	close(fds[1]);
	test(!libsha1_sum_fd(fds[0], LIBSHA1_1, buf));
	test(waitpid(pid, &status, 0) == pid);
	test(!status);
	close(fds[0]);
	libsha1_behex_lower(str, buf, libsha1_algorithm_output_size(LIBSHA1_1));
	test_str(str, "3ae3644d6777a1f56a1defeabc74af9c4b313e49");

	test_bits("00", 1, LIBSHA1_1, "bb6b3e18f0115b57925241676f5b1ae88747b08a");
	test_bits("01", 2, LIBSHA1_1, "ec6b39952e1a3ec3ab3507185cf756181c84bbe2");
	test_bits("04", 3, LIBSHA1_1, "a37596ec13a0d2f9e6c0b8b96f9112823aa6d961");
	test_bits("0d", 4, LIBSHA1_1, "ba582f5967911beb91599684c2eb2baeefb78da7");
	test_bits("09", 5, LIBSHA1_1, "3320540d1c28b96ddd03eee1b186a8f2ae883fbe");
	test_bits("08", 6, LIBSHA1_1, "b372bd120957ebc3392cd060e131699d1fee6059");
	test_bits("22", 7, LIBSHA1_1, "04f31807151181ad0db278a1660526b0aeef64c2");

	test(!libsha1_hmac_init(&hs, LIBSHA1_1, "", 0));
	test(libsha1_hmac_state_output_size(&hs) == 20);
	libsha1_hmac_digest(&hs, "", 0, buf);
	libsha1_behex_lower(str, buf, libsha1_hmac_state_output_size(&hs));
	test_str(str, "fbdb1d1b18aa6c08324b7d64b71fb76370690e1d");

	test(!libsha1_hmac_init(&hs, LIBSHA1_1, "key", 3 << 3));
	test(libsha1_hmac_state_output_size(&hs) == 20);
	libsha1_hmac_digest(&hs, "The quick brown fox jumps over the lazy dog",
	                    (sizeof("The quick brown fox jumps over the lazy dog") - 1) << 3, buf);
	libsha1_behex_lower(str, buf, libsha1_hmac_state_output_size(&hs));
	test_str(str, "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9");

	n = sizeof("The quick brown fox jumps over the lazy dog") - 1;
	for (i = 1; i < n; i++) {
		test(!libsha1_hmac_init(&hs, LIBSHA1_1, "key", 3 << 3));
		test(libsha1_hmac_state_output_size(&hs) == 20);
		for (j = 0; j + i < n; j += i) {
			libsha1_hmac_update(&hs, &"The quick brown fox jumps over the lazy dog"[j], i << 3);
			test((len = libsha1_hmac_marshal(&hs, NULL)) && len <= sizeof(str));
			test(libsha1_hmac_marshal(&hs, str) == len);
			memset(&hs, 0, sizeof(hs));
			test(libsha1_hmac_unmarshal(&hs, str, sizeof(str)) == len);
		}
		libsha1_hmac_digest(&hs, &"The quick brown fox jumps over the lazy dog"[j], (n - j) << 3, buf);
		libsha1_behex_lower(str, buf, libsha1_hmac_state_output_size(&hs));
		test_str(str, "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9");
	}

	test(!errno);

	test_hmac(LIBSHA1_1,
	          "53616d706c65206d65737361676520666f72206b65796c656e3d626c6f636b6c656e",
	          "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f",
	          "5fd596ee78d5553c8ff4e72d266dfd192366da29");

	test_hmac(LIBSHA1_1,
	          "53616d706c65206d65737361676520666f72206b65796c656e3c626c6f636b6c656e",
	          "000102030405060708090a0b0c0d0e0f10111213",
	          "4c99ff0cb1b31bd33f8431dbaf4d17fcd356a807");

	test_hmac(LIBSHA1_1,
	          "53616d706c65206d65737361676520666f72206b65796c656e3d626c6f636b6c656e",
	          "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f60616263",
	          "2d51b2f7750e410584662e38f133435f4c4fd42a");

	return 0;
}