totp

Simple cli tool for storing TOTP secrets and generating tokens
git clone https://git.inz.fi/totp/
Log | Files | Refs | Submodules

algotest.c (14192B)


      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <stdint.h>
      4 #include <inttypes.h>
      5 
      6 #include "util.h"
      7 #include "sha1.h"
      8 #include "sha256.h"
      9 #include "sha512.h"
     10 
     11 void hexdump(FILE *f, const void *data, size_t len)
     12 {
     13 	const uint8_t *d;
     14 
     15 	for (d = data; len--; d++)
     16 		fprintf(f, "%02x", *d);
     17 }
     18 
     19 void test_sha1(void)
     20 {
     21 	const char *test_datas[] = {
     22 		"abc",
     23 		"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
     24 	};
     25 
     26 	const uint8_t test_hashes[][SHA1_HASHSIZE] = {
     27 		{ 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E,
     28 		  0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D, },
     29 		{ 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE,
     30 		  0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1, },
     31 	};
     32 
     33 	struct sha1 s;
     34 	size_t i;
     35 
     36 	for (i = 0; i < sizeof(test_datas) / sizeof(*test_datas); i++) {
     37 		sha1_init(&s);
     38 		sha1_update(&s, test_datas[i], strlen(test_datas[i]));
     39 		sha1_finish(&s);
     40 
     41 		if (memcmp(s.h, test_hashes[i], sizeof(s.h))) {
     42 			fprintf(stderr, "%s: hash %zu mismatch, got:\n\t",
     43 				__func__, i);
     44 			hexdump(stderr, s.h, sizeof(s.h));
     45 			fprintf(stderr, "\n, expected:\n\t");
     46 			hexdump(stderr,
     47 				test_hashes[i], sizeof(test_hashes[i]));
     48 			fprintf(stderr, "\n");
     49 		}
     50 	}
     51 }
     52 
     53 void test_hmac_sha1(void)
     54 {
     55 	const char *test_datas[] = {
     56 		"Sample message for keylen=blocklen",
     57 		"Sample message for keylen<blocklen",
     58 		"Sample message for keylen=blocklen",
     59 		"Sample message for keylen<blocklen, with truncated tag"
     60 	};
     61 
     62 	uint8_t keybuf[128];
     63 	const size_t keylens[] = {
     64 		64, 20, 100, 49
     65 	};
     66 
     67 	const size_t taglens[] = {
     68 		20, 20, 20, 12
     69 	};
     70 
     71 	const uint8_t test_tags[][SHA1_HASHSIZE] = {
     72 		{ 0x5F, 0xD5, 0x96, 0xEE, 0x78, 0xD5, 0x55, 0x3C, 0x8F, 0xF4,
     73 		  0xE7, 0x2D, 0x26, 0x6D, 0xFD, 0x19, 0x23, 0x66, 0xDA, 0x29, },
     74 		{ 0x4C, 0x99, 0xFF, 0x0C, 0xB1, 0xB3, 0x1B, 0xD3, 0x3F, 0x84,
     75 		  0x31, 0xDB, 0xAF, 0x4D, 0x17, 0xFC, 0xD3, 0x56, 0xA8, 0x07, },
     76 		{ 0x2D, 0x51, 0xB2, 0xF7, 0x75, 0x0E, 0x41, 0x05, 0x84, 0x66,
     77 		  0x2E, 0x38, 0xF1, 0x33, 0x43, 0x5F, 0x4C, 0x4F, 0xD4, 0x2A, },
     78 		{ 0xFE, 0x35, 0x29, 0x56, 0x5C, 0xD8, 0xE2, 0x8C, 0x5F, 0xA7,
     79 		  0x9E, 0xAC, },
     80 	};
     81 
     82 	size_t i;
     83 
     84 	for (i = 0; i < sizeof(keybuf); i++)
     85 		keybuf[i] = i;
     86 
     87 	for (i = 0; i < sizeof(test_datas) / sizeof(*test_datas); i++) {
     88 		uint8_t hmacbuf[SHA1_HASHSIZE];
     89 		sha1_hmac(keybuf, keylens[i], test_datas[i], strlen(test_datas[i]), hmacbuf);
     90 
     91 		if (memcmp(hmacbuf, test_tags[i], taglens[i])) {
     92 			fprintf(stderr, "%s: HMAC %zu mismatch, got:\n\t", __func__, i);
     93 			hexdump(stderr, hmacbuf, taglens[i]);
     94 			fprintf(stderr, "\n, expected:\n\t");
     95 			hexdump(stderr, test_tags[i], taglens[i]);
     96 			fprintf(stderr, "\n");
     97 		}
     98 	}
     99 }
    100 
    101 void test_sha224(void)
    102 {
    103 	const char *test_datas[] = {
    104 		"abc",
    105 		"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
    106 	};
    107 
    108 	const uint8_t test_hashes[][SHA224_HASHSIZE] = {
    109 		{ 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22, 0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2,
    110 		  0x55, 0xB3, 0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7, 0xE3, 0x6C, 0x9D, 0xA7, },
    111 		{ 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC, 0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89,
    112 		  0x01, 0x50, 0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19, 0x52, 0x52, 0x25, 0x25, },
    113 	};
    114 
    115 	struct sha224 s;
    116 	size_t i;
    117 
    118 	for (i = 0; i < sizeof(test_datas) / sizeof(*test_datas); i++) {
    119 		sha224_init(&s);
    120 		sha224_update(&s, test_datas[i], strlen(test_datas[i]));
    121 		sha224_finish(&s);
    122 
    123 		if (memcmp(s.h, test_hashes[i], sizeof(s.h))) {
    124 			fprintf(stderr, "%s: hash %zu mismatch, got:\n\t", __func__, i);
    125 			hexdump(stderr, s.h, sizeof(s.h));
    126 			fprintf(stderr, "\n, expected:\n\t");
    127 			hexdump(stderr, test_hashes[i], sizeof(test_hashes[i]));
    128 			fprintf(stderr, "\n");
    129 		}
    130 	}
    131 }
    132 
    133 void test_sha256(void)
    134 {
    135 	const char *test_datas[] = {
    136 		"abc",
    137 		"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
    138 	};
    139 
    140 	const uint8_t test_hashes[][SHA256_HASHSIZE] = {
    141 		{ 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA, 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
    142 		  0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C, 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD, },
    143 		{ 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8, 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
    144 		  0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67, 0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1, },
    145 	};
    146 
    147 	struct sha256 s;
    148 	size_t i;
    149 
    150 	for (i = 0; i < sizeof(test_datas) / sizeof(*test_datas); i++) {
    151 		sha256_init(&s);
    152 		sha256_update(&s, test_datas[i], strlen(test_datas[i]));
    153 		sha256_finish(&s);
    154 
    155 		if (memcmp(s.h, test_hashes[i], sizeof(s.h)))
    156 			fprintf(stderr, "%s: hash %zu mismatch\n", __func__, i);
    157 	}
    158 }
    159 
    160 void test_hmac_sha256(void)
    161 {
    162 	const char *test_datas[] = {
    163 		"Sample message for keylen=blocklen",
    164 		"Sample message for keylen<blocklen",
    165 		"Sample message for keylen=blocklen",
    166 		"Sample message for keylen<blocklen, with truncated tag"
    167 	};
    168 
    169 	uint8_t keybuf[128];
    170 	const size_t keylens[] = {
    171 		64, 32, 100, 49
    172 	};
    173 
    174 	const size_t taglens[] = {
    175 		32, 32, 32, 16
    176 	};
    177 
    178 	const uint8_t test_tags[][SHA256_HASHSIZE] = {
    179 		{ 0x8B, 0xB9, 0xA1, 0xDB, 0x98, 0x06, 0xF2, 0x0D, 0xF7, 0xF7, 0x7B, 0x82, 0x13, 0x8C, 0x79, 0x14, 0xD1, 0x74, 0xD5, 0x9E, 0x13, 0xDC, 0x4D, 0x01, 0x69, 0xC9, 0x05, 0x7B, 0x13, 0x3E, 0x1D, 0x62, },
    180 		{ 0xA2, 0x8C, 0xF4, 0x31, 0x30, 0xEE, 0x69, 0x6A, 0x98, 0xF1, 0x4A, 0x37, 0x67, 0x8B, 0x56, 0xBC, 0xFC, 0xBD, 0xD9, 0xE5, 0xCF, 0x69, 0x71, 0x7F, 0xEC, 0xF5, 0x48, 0x0F, 0x0E, 0xBD, 0xF7, 0x90, },
    181 		{ 0xBD, 0xCC, 0xB6, 0xC7, 0x2D, 0xDE, 0xAD, 0xB5, 0x00, 0xAE, 0x76, 0x83, 0x86, 0xCB, 0x38, 0xCC, 0x41, 0xC6, 0x3D, 0xBB, 0x08, 0x78, 0xDD, 0xB9, 0xC7, 0xA3, 0x8A, 0x43, 0x1B, 0x78, 0x37, 0x8D,  },
    182 		{ 0x27, 0xA8, 0xB1, 0x57, 0x83, 0x9E, 0xFE, 0xAC, 0x98, 0xDF, 0x07, 0x0B, 0x33, 0x1D, 0x59, 0x36, },
    183 	};
    184 
    185 	size_t i;
    186 
    187 	for (i = 0; i < sizeof(keybuf); i++)
    188 		keybuf[i] = i;
    189 
    190 	for (i = 0; i < sizeof(test_datas) / sizeof(*test_datas); i++) {
    191 		uint8_t hmacbuf[SHA256_HASHSIZE];
    192 		sha256_hmac(keybuf, keylens[i], test_datas[i], strlen(test_datas[i]), hmacbuf);
    193 
    194 		if (memcmp(hmacbuf, test_tags[i], taglens[i])) {
    195 			fprintf(stderr, "%s: HMAC %zu mismatch, got:\n\t", __func__, i);
    196 			hexdump(stderr, hmacbuf, taglens[i]);
    197 			fprintf(stderr, "\n, expected:\n\t");
    198 			hexdump(stderr, test_tags[i], taglens[i]);
    199 			fprintf(stderr, "\n");
    200 		}
    201 	}
    202 }
    203 
    204 void test_sha384(void)
    205 {
    206 	const char *test_datas[] = {
    207 		"abc",
    208 		"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
    209 	};
    210 
    211 	const uint8_t test_hashes[][SHA384_HASHSIZE] = {
    212 		{ 0xCB, 0x00, 0x75, 0x3F, 0x45, 0xA3, 0x5E, 0x8B, 0xB5, 0xA0, 0x3D, 0x69, 0x9A, 0xC6, 0x50, 0x07,
    213 		  0x27, 0x2C, 0x32, 0xAB, 0x0E, 0xDE, 0xD1, 0x63, 0x1A, 0x8B, 0x60, 0x5A, 0x43, 0xFF, 0x5B, 0xED,
    214 		  0x80, 0x86, 0x07, 0x2B, 0xA1, 0xE7, 0xCC, 0x23, 0x58, 0xBA, 0xEC, 0xA1, 0x34, 0xC8, 0x25, 0xA7, },
    215 		{ 0x09, 0x33, 0x0C, 0x33, 0xF7, 0x11, 0x47, 0xE8, 0x3D, 0x19, 0x2F, 0xC7, 0x82, 0xCD, 0x1B, 0x47,
    216 		  0x53, 0x11, 0x1B, 0x17, 0x3B, 0x3B, 0x05, 0xD2, 0x2F, 0xA0, 0x80, 0x86, 0xE3, 0xB0, 0xF7, 0x12,
    217 		  0xFC, 0xC7, 0xC7, 0x1A, 0x55, 0x7E, 0x2D, 0xB9, 0x66, 0xC3, 0xE9, 0xFA, 0x91, 0x74, 0x60, 0x39, },
    218 	};
    219 
    220 	struct sha384 s;
    221 	size_t i;
    222 
    223 	for (i = 0; i < sizeof(test_datas) / sizeof(*test_datas); i++) {
    224 		sha384_init(&s);
    225 		sha384_update(&s, test_datas[i], strlen(test_datas[i]));
    226 		sha384_finish(&s);
    227 
    228 		if (memcmp(s.h, test_hashes[i], sizeof(s.h)))
    229 			fprintf(stderr, "%s: hash %zu mismatch\n", __func__, i);
    230 	}
    231 }
    232 
    233 void test_sha512(void)
    234 {
    235 	const char *test_datas[] = {
    236 		"abc",
    237 		"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
    238 	};
    239 
    240 	const uint8_t test_hashes[][SHA512_HASHSIZE] = {
    241 		{ 0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA, 0xCC, 0x41, 0x73, 0x49, 0xAE, 0x20, 0x41, 0x31,
    242 		  0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2, 0x0A, 0x9E, 0xEE, 0xE6, 0x4B, 0x55, 0xD3, 0x9A,
    243 		  0x21, 0x92, 0x99, 0x2A, 0x27, 0x4F, 0xC1, 0xA8, 0x36, 0xBA, 0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD,
    244 		  0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E, 0x2A, 0x9A, 0xC9, 0x4F, 0xA5, 0x4C, 0xA4, 0x9F, },
    245 		{ 0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA, 0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F,
    246 		  0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1, 0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18,
    247 		  0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4, 0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A,
    248 		  0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54, 0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09, },
    249 	};
    250 
    251 	struct sha512 s;
    252 	size_t i;
    253 
    254 	for (i = 0; i < sizeof(test_datas) / sizeof(*test_datas); i++) {
    255 		sha512_init(&s);
    256 		sha512_update(&s, test_datas[i], strlen(test_datas[i]));
    257 		sha512_finish(&s);
    258 
    259 		if (memcmp(s.h, test_hashes[i], sizeof(s.h)))
    260 			fprintf(stderr, "%s: hash %zu mismatch\n", __func__, i);
    261 	}
    262 }
    263 
    264 void test_hmac_sha512(void)
    265 {
    266 	const char *test_datas[] = {
    267 		"Sample message for keylen=blocklen",
    268 		"Sample message for keylen<blocklen",
    269 		"Sample message for keylen=blocklen",
    270 		"Sample message for keylen<blocklen, with truncated tag"
    271 	};
    272 
    273 	uint8_t keybuf[256];
    274 	const size_t keylens[] = {
    275 		128, 64, 200, 49
    276 	};
    277 
    278 	const size_t taglens[] = {
    279 		64, 64, 64, 32
    280 	};
    281 
    282 	const uint8_t test_tags[][SHA512_HASHSIZE] = {
    283 		{ 0xFC, 0x25, 0xE2, 0x40, 0x65, 0x8C, 0xA7, 0x85, 0xB7, 0xA8, 0x11, 0xA8, 0xD3, 0xF7, 0xB4, 0xCA, 0x48, 0xCF, 0xA2, 0x6A, 0x8A, 0x36, 0x6B, 0xF2, 0xCD, 0x1F, 0x83, 0x6B, 0x05, 0xFC, 0xB0, 0x24, 0xBD, 0x36, 0x85, 0x30, 0x81, 0x81, 0x1D, 0x6C, 0xEA, 0x42, 0x16, 0xEB, 0xAD, 0x79, 0xDA, 0x1C, 0xFC, 0xB9, 0x5E, 0xA4, 0x58, 0x6B, 0x8A, 0x0C, 0xE3, 0x56, 0x59, 0x6A, 0x55, 0xFB, 0x13, 0x47, },
    284 		{ 0xFD, 0x44, 0xC1, 0x8B, 0xDA, 0x0B, 0xB0, 0xA6, 0xCE, 0x0E, 0x82, 0xB0, 0x31, 0xBF, 0x28, 0x18, 0xF6, 0x53, 0x9B, 0xD5, 0x6E, 0xC0, 0x0B, 0xDC, 0x10, 0xA8, 0xA2, 0xD7, 0x30, 0xB3, 0x63, 0x4D, 0xE2, 0x54, 0x5D, 0x63, 0x9B, 0x0F, 0x2C, 0xF7, 0x10, 0xD0, 0x69, 0x2C, 0x72, 0xA1, 0x89, 0x6F, 0x1F, 0x21, 0x1C, 0x2B, 0x92, 0x2D, 0x1A, 0x96, 0xC3, 0x92, 0xE0, 0x7E, 0x7E, 0xA9, 0xFE, 0xDC, },
    285 		{ 0xD9, 0x3E, 0xC8, 0xD2, 0xDE, 0x1A, 0xD2, 0xA9, 0x95, 0x7C, 0xB9, 0xB8, 0x3F, 0x14, 0xE7, 0x6A, 0xD6, 0xB5, 0xE0, 0xCC, 0xE2, 0x85, 0x07, 0x9A, 0x12, 0x7D, 0x3B, 0x14, 0xBC, 0xCB, 0x7A, 0xA7, 0x28, 0x6D, 0x4A, 0xC0, 0xD4, 0xCE, 0x64, 0x21, 0x5F, 0x2B, 0xC9, 0xE6, 0x87, 0x0B, 0x33, 0xD9, 0x74, 0x38, 0xBE, 0x4A, 0xAA, 0x20, 0xCD, 0xA5, 0xC5, 0xA9, 0x12, 0xB4, 0x8B, 0x8E, 0x27, 0xF3, },
    286 		{ 0x00, 0xF3, 0xE9, 0xA7, 0x7B, 0xB0, 0xF0, 0x6D, 0xE1, 0x5F, 0x16, 0x06, 0x03, 0xE4, 0x2B, 0x50, 0x28, 0x75, 0x88, 0x08, 0x59, 0x66, 0x64, 0xC0, 0x3E, 0x1A, 0xB8, 0xFB, 0x2B, 0x07, 0x67, 0x78, },
    287 	};
    288 
    289 	size_t i;
    290 
    291 	for (i = 0; i < sizeof(keybuf); i++)
    292 		keybuf[i] = i;
    293 
    294 	for (i = 0; i < sizeof(test_datas) / sizeof(*test_datas); i++) {
    295 		uint8_t hmacbuf[SHA512_HASHSIZE];
    296 		sha512_hmac(keybuf, keylens[i], test_datas[i], strlen(test_datas[i]), hmacbuf);
    297 
    298 		if (memcmp(hmacbuf, test_tags[i], taglens[i])) {
    299 			fprintf(stderr, "%s: HMAC %zu mismatch, got:\n\t", __func__, i);
    300 			hexdump(stderr, hmacbuf, taglens[i]);
    301 			fprintf(stderr, "\n, expected:\n\t");
    302 			hexdump(stderr, test_tags[i], taglens[i]);
    303 			fprintf(stderr, "\n");
    304 		}
    305 	}
    306 }
    307 
    308 void test_totp_sha1(void)
    309 {
    310 	/* Test vectors from RFC 6238 appendix B */
    311 	const char *key = "12345678901234567890";
    312 	const uint8_t period = 30;
    313 	const time_t t0 = 0;
    314 
    315 	const time_t times[] = {
    316 		59, 1111111109, 1111111111, 1234567890, 2000000000, 20000000000
    317 	};
    318 	const uint32_t totps[] = {
    319 		94287082, /*0*/7081804, 14050471, 89005924, 69279037, 65353130
    320 	};
    321 	const uint32_t modulo = 100000000;
    322 	size_t i;
    323 
    324 	for (i = 0; i < sizeof(times) / sizeof(*times); i++) {
    325 		uint32_t token = totp(key, strlen(key), times[i], period, t0, sha1_hmac, SHA1_HASHSIZE);
    326 
    327 		if (token % modulo != totps[i])
    328 			fprintf(stderr, "%s: token %zu mismatch, got %08" PRIu32 ", expected %08" PRIu32 "\n",
    329 				__func__, i, token % modulo, totps[i]);
    330 	}
    331 }
    332 
    333 void test_totp_sha256(void)
    334 {
    335 	/* Test vectors from RFC 6238 appendix B but key/seed from appendix A */
    336 	const char *key = "12345678901234567890123456789012";
    337 	const uint8_t period = 30;
    338 	const time_t t0 = 0;
    339 
    340 	const time_t times[] = {
    341 		59, 1111111109, 1111111111, 1234567890, 2000000000, 20000000000
    342 	};
    343 	const uint32_t totps[] = {
    344 		46119246, 68084774, 67062674, 91819424, 90698825, 77737706
    345 	};
    346 	const uint32_t modulo = 100000000;
    347 	size_t i;
    348 
    349 	for (i = 0; i < sizeof(times) / sizeof(*times); i++) {
    350 		uint32_t token = totp(key, strlen(key), times[i], period, t0, sha256_hmac, SHA256_HASHSIZE);
    351 
    352 		if (token % modulo != totps[i])
    353 			fprintf(stderr, "%s: token %zu mismatch, got %08" PRIu32 ", expected %08" PRIu32 "\n",
    354 				__func__, i, token % modulo, totps[i]);
    355 	}
    356 }
    357 
    358 void test_totp_sha512(void)
    359 {
    360 	/* Test vectors from RFC 6238 appendix B but key/seed from appendix A */
    361 	const char *key = "1234567890123456789012345678901234567890123456789012345678901234";
    362 	const uint8_t period = 30;
    363 	const time_t t0 = 0;
    364 
    365 	const time_t times[] = {
    366 		59, 1111111109, 1111111111, 1234567890, 2000000000, 20000000000
    367 	};
    368 	const uint32_t totps[] = {
    369 		90693936, 25091201, 99943326, 93441116, 38618901, 47863826
    370 	};
    371 	const uint32_t modulo = 100000000;
    372 	size_t i;
    373 
    374 	for (i = 0; i < sizeof(times) / sizeof(*times); i++) {
    375 		uint32_t token = totp(key, strlen(key), times[i], period, t0, sha512_hmac, SHA512_HASHSIZE);
    376 
    377 		if (token % modulo != totps[i])
    378 			fprintf(stderr, "%s: token %zu mismatch, got %08" PRIu32 ", expected %08" PRIu32 "\n",
    379 				__func__, i, token % modulo, totps[i]);
    380 	}
    381 }
    382 
    383 void test_debase32(void)
    384 {
    385 	const char *base32s[] = {
    386 		"MFRGG",
    387 		"MFRGGZDFMZTWQ2LKNM",
    388 		"MFRGGZDF",
    389 	};
    390 
    391 	const char *plaintext[] = {
    392 		"abc",
    393 		"abcdefghijk",
    394 		"abcde"
    395 	};
    396 
    397 	size_t i;
    398 
    399 	for (i = 0; i < sizeof(base32s) / sizeof(*base32s); i++) {
    400 		char buffer[64];
    401 		int len = sprintf(buffer, "%s", base32s[i]);
    402 		*(char *)debase32(bytesnc(buffer, len)).end = '\0';
    403 
    404 		if (strcmp(buffer, plaintext[i]))
    405 			fprintf(stderr, "%s: plaintext mismatch, got %s, expected %s\n",
    406 				__func__, buffer, plaintext[i]);
    407 	}
    408 }
    409 
    410 int main(int argc, char **argv)
    411 {
    412 	(void)argc;
    413 	(void)argv;
    414 
    415 	test_sha1();
    416 	test_sha224();
    417 	test_sha256();
    418 	test_sha384();
    419 	test_sha512();
    420 
    421 	test_hmac_sha1();
    422 	test_hmac_sha256();
    423 	test_hmac_sha512();
    424 
    425 	test_totp_sha1();
    426 	test_totp_sha256();
    427 	test_totp_sha512();
    428 
    429 	test_debase32();
    430 }