1/*
2 * Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* $Id: t_hashes.c,v 1.5 2010/10/04 22:27:41 marka Exp $ */
18
19/*
20 * -d1 or larger shows hash or HMAC result even if correct
21 */
22
23#include <config.h>
24
25#include <stdlib.h>
26
27#include <isc/hmacmd5.h>
28#include <isc/hmacsha.h>
29#include <isc/md5.h>
30#include <isc/print.h>
31#include <isc/sha1.h>
32#include <isc/string.h>
33#include <isc/util.h>
34
35#include <tests/t_api.h>
36
37
38static int	    nprobs;
39
40typedef void(*HASH_INIT)(void *);
41typedef void(*HMAC_INIT)(void *, const unsigned char *, unsigned int);
42typedef void(*UPDATE)(void *, const unsigned char *, unsigned int);
43typedef void(*FINAL)(void *, const unsigned char *);
44typedef void(*SIGN)(void *, const unsigned char *, unsigned int);
45
46typedef struct {
47    const char *name;
48    const unsigned char	*key;
49    const unsigned int	key_len;
50    const unsigned char	*str;
51    const unsigned int	str_len;
52} IN;
53#define STR_INIT(s)	(const unsigned char *)(s), sizeof(s)-1
54
55
56union {
57    unsigned char b[1024];
58    unsigned char md5[16];
59    unsigned char sha1[ISC_SHA1_DIGESTLENGTH];
60    unsigned char sha224[ISC_SHA224_DIGESTLENGTH];
61    unsigned char sha256[ISC_SHA256_DIGESTLENGTH];
62    unsigned char sha384[ISC_SHA384_DIGESTLENGTH];
63    unsigned char sha512[ISC_SHA512_DIGESTLENGTH];
64} dbuf;
65#define DIGEST_FILL 0xdf
66
67typedef struct {
68    const char		*str;
69    const unsigned int	digest_len;
70} OUT;
71
72
73/*
74 * two ad hoc hash examples
75 */
76static IN abc = { "\"abc\"", NULL, 0, STR_INIT("abc")};
77static OUT abc_sha1 = {
78	"a9993e364706816aba3e25717850c26c9cd0d89d",
79	ISC_SHA1_DIGESTLENGTH};
80static OUT abc_sha224 = {
81	"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7",
82	ISC_SHA224_DIGESTLENGTH};
83static OUT abc_md5 = {
84	"900150983cd24fb0d6963f7d28e17f72",
85	16};
86
87static IN abc_blah = { "\"abcdbc...\"", NULL, 0,
88	STR_INIT("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")};
89static OUT abc_blah_sha1 =  {
90	"84983e441c3bd26ebaae4aa1f95129e5e54670f1",
91	ISC_SHA1_DIGESTLENGTH};
92static OUT abc_blah_sha224 = {
93	"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525",
94	ISC_SHA224_DIGESTLENGTH};
95static OUT abc_blah_md5 = {
96	"8215ef0796a20bcaaae116d3876c664a",
97	16};
98
99/*
100 * three HMAC-md5 examples from RFC 2104
101 */
102static const unsigned char rfc2104_1_key[16] = {
103	0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
104	0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b};
105static IN rfc2104_1 = {"RFC 2104 #1", rfc2104_1_key, sizeof(rfc2104_1_key),
106	STR_INIT("Hi There")};
107static OUT rfc2104_1_hmac = {
108	"9294727a3638bb1c13f48ef8158bfc9d",
109	16};
110
111static IN rfc2104_2 = {"RFC 2104 #2", STR_INIT("Jefe"),
112	STR_INIT("what do ya want for nothing?")};
113static OUT rfc2104_2_hmac = {
114	"750c783e6ab0b503eaa86e310a5db738",
115	16};
116
117static const unsigned char rfc2104_3_key[16] = {
118	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
119	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
120static const unsigned char rfc2104_3_s[50] = {
121	0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
122	0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
123	0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
124	0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
125	0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
126	0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
127	0xDD, 0xDD};
128static IN rfc2104_3 = {"RFC 2104 #3", rfc2104_3_key, sizeof(rfc2104_3_key),
129	rfc2104_3_s, sizeof(rfc2104_3_s)};
130static OUT rfc2104_3_hmac = {
131	"56be34521d144c88dbb8c733f0e8b3f6",
132	16};
133
134/*
135 * four three HMAC-SHA tests cut-and-pasted from RFC 4634 starting on page 86
136 */
137static const unsigned char rfc4634_1_key[20] = {
138      0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
139      0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
140};
141static IN rfc4634_1 = {"RFC 4634 #1", rfc4634_1_key, sizeof(rfc4634_1_key),
142	STR_INIT("Hi There")};
143static OUT rfc4634_1_sha1 = {
144	"B617318655057264E28BC0B6FB378C8EF146BE00",
145	ISC_SHA1_DIGESTLENGTH};
146static OUT rfc4634_1_sha224 = {
147	"896FB1128ABBDF196832107CD49DF33F47B4B1169912BA4F53684B22",
148	ISC_SHA224_DIGESTLENGTH};
149static OUT rfc4634_1_sha256 = {
150	"B0344C61D8DB38535CA8AFCEAF0BF12B881DC200C9833DA726E9376C2E32"
151	"CFF7",
152	ISC_SHA256_DIGESTLENGTH};
153static OUT rfc4634_1_sha384 = {
154	"AFD03944D84895626B0825F4AB46907F15F9DADBE4101EC682AA034C7CEB"
155	"C59CFAEA9EA9076EDE7F4AF152E8B2FA9CB6",
156	ISC_SHA384_DIGESTLENGTH};
157static OUT rfc4634_1_sha512 = {
158	"87AA7CDEA5EF619D4FF0B4241A1D6CB02379F4E2CE4EC2787AD0B30545E1"
159	"7CDEDAA833B7D6B8A702038B274EAEA3F4E4BE9D914EEB61F1702E696C20"
160	"3A126854",
161	ISC_SHA512_DIGESTLENGTH};
162
163static IN rfc4634_2 = {"RFC 4634 #2", STR_INIT("Jefe"),
164	STR_INIT("what do ya want for nothing?")};
165static OUT rfc4634_2_sha1 = {
166	"EFFCDF6AE5EB2FA2D27416D5F184DF9C259A7C79",
167	ISC_SHA1_DIGESTLENGTH};
168static OUT rfc4634_2_sha224 = {
169	"A30E01098BC6DBBF45690F3A7E9E6D0F8BBEA2A39E6148008FD05E44",
170	ISC_SHA224_DIGESTLENGTH};
171static OUT rfc4634_2_sha256 = {
172	"5BDCC146BF60754E6A042426089575C75A003F089D2739839DEC58B964EC"
173	"3843",
174	ISC_SHA256_DIGESTLENGTH};
175static OUT rfc4634_2_sha384 = {
176	"AF45D2E376484031617F78D2B58A6B1B9C7EF464F5A01B47E42EC3736322"
177	"445E8E2240CA5E69E2C78B3239ECFAB21649",
178	ISC_SHA384_DIGESTLENGTH};
179static OUT rfc4634_2_sha512 = {
180	"164B7A7BFCF819E2E395FBE73B56E0A387BD64222E831FD610270CD7EA25"
181	"05549758BF75C05A994A6D034F65F8F0E6FDCAEAB1A34D4A6B4B636E070A"
182	"38BCE737",
183	ISC_SHA512_DIGESTLENGTH};
184
185static const unsigned char rfc4634_3_key[20] = {
186	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
187	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
188};
189static const unsigned char rfc4634_3_s[50] = {
190	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
191	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
192	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
193	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
194	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd
195};
196static IN rfc4634_3 = {"RFC 4634 #3", rfc4634_3_key, sizeof(rfc4634_3_key),
197	rfc4634_3_s, sizeof(rfc4634_3_s)};
198static OUT rfc4634_3_sha1 = {
199	"125D7342B9AC11CD91A39AF48AA17B4F63F175D3",
200	ISC_SHA1_DIGESTLENGTH};
201static OUT rfc4634_3_sha224 = {
202	"7FB3CB3588C6C1F6FFA9694D7D6AD2649365B0C1F65D69D1EC8333EA",
203	ISC_SHA224_DIGESTLENGTH};
204static OUT rfc4634_3_sha256 = {
205	"773EA91E36800E46854DB8EBD09181A72959098B3EF8C122D9635514CED5"
206	"65FE",
207	ISC_SHA256_DIGESTLENGTH};
208static OUT rfc4634_3_sha384 = {
209	"88062608D3E6AD8A0AA2ACE014C8A86F0AA635D947AC9FEBE83EF4E55966"
210	"144B2A5AB39DC13814B94E3AB6E101A34F27",
211	ISC_SHA384_DIGESTLENGTH};
212static OUT rfc4634_3_sha512 = {
213	"FA73B0089D56A284EFB0F0756C890BE9B1B5DBDD8EE81A3655F83E33B227"
214	"9D39BF3E848279A722C806B485A47E67C807B946A337BEE8942674278859"
215	"E13292FB",
216	ISC_SHA512_DIGESTLENGTH};
217
218static const unsigned char rfc4634_4_key[25] = {
219	0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
220	0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
221	0x15, 0x16, 0x17, 0x18, 0x19
222};
223static const unsigned char rfc4634_4_s[50] = {
224	0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
225	0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
226	0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
227	0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
228	0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd
229};
230static IN rfc4634_4 = {"RFC 4634 #3", rfc4634_4_key, sizeof(rfc4634_4_key),
231	rfc4634_4_s, sizeof(rfc4634_4_s)};
232static OUT rfc4634_4_sha1 = {
233	"4C9007F4026250C6BC8414F9BF50C86C2D7235DA",
234	ISC_SHA1_DIGESTLENGTH};
235static OUT rfc4634_4_sha224 = {
236	"6C11506874013CAC6A2ABC1BB382627CEC6A90D86EFC012DE7AFEC5A",
237	ISC_SHA224_DIGESTLENGTH};
238static OUT rfc4634_4_sha256 = {
239	"82558A389A443C0EA4CC819899F2083A85F0FAA3E578F8077A2E3FF46729"
240	"665B",
241	ISC_SHA256_DIGESTLENGTH};
242static OUT rfc4634_4_sha384 = {
243	"3E8A69B7783C25851933AB6290AF6CA77A9981480850009CC5577C6E1F57"
244	"3B4E6801DD23C4A7D679CCF8A386C674CFFB",
245	ISC_SHA384_DIGESTLENGTH};
246static OUT rfc4634_4_sha512 = {
247	"B0BA465637458C6990E5A8C5F61D4AF7E576D97FF94B872DE76F8050361E"
248	"E3DBA91CA5C11AA25EB4D679275CC5788063A5F19741120C4F2DE2ADEBEB"
249	"10A298DD",
250	ISC_SHA512_DIGESTLENGTH};
251
252
253
254static const char *
255d2str(char *buf, unsigned int buf_len,
256      const unsigned char *d, unsigned int d_len)
257{
258	unsigned int i, l;
259
260	l = 0;
261	for (i = 0; i < d_len && l < buf_len-4; ++i) {
262		l += snprintf(&buf[l], buf_len-l, "%02x", d[i]);
263	}
264	if (l >= buf_len-3) {
265		REQUIRE(buf_len > sizeof("..."));
266		strcpy(&buf[l-sizeof(" ...")], " ...");
267	}
268	return buf;
269}
270
271
272
273/*
274 * Compare binary digest or HMAC to string of hex digits from an RFC
275 */
276static void
277ck(const char *name, const IN *in, const OUT *out)
278{
279	char buf[sizeof(dbuf)*2+1];
280	const char *str_name;
281	unsigned int l;
282
283	d2str(buf, sizeof(buf), dbuf.b, out->digest_len);
284	str_name = in->name != NULL ? in->name : (const char *)in->str;
285
286	if (T_debug != 0)
287		t_info("%s(%s) = %s\n", name, str_name, buf);
288
289	if (strcasecmp(buf, out->str)) {
290		t_info("%s(%s)\n%9s %s\n%9s %s\n",
291		       name, str_name,
292		       "is", buf,
293		       "should be", out->str);
294		++nprobs;
295		return;
296	}
297
298	/*
299	 * check that the hash or HMAC is no longer than we think it is
300	 */
301	for (l = out->digest_len; l < sizeof(dbuf); ++l) {
302		if (dbuf.b[l] != DIGEST_FILL) {
303			t_info("byte #%d after end of %s(%s) changed to %02x\n",
304			       l-out->digest_len, name, str_name, dbuf.b[l]);
305			++nprobs;
306			break;
307		}
308	}
309}
310
311
312
313static void
314t_hash(const char *hname, HASH_INIT init, UPDATE update, FINAL final,
315      IN *in, OUT *out)
316{
317	union {
318	    unsigned char b[1024];
319	    isc_sha1_t sha1;
320	    isc_md5_t md5;
321	} ctx;
322
323	init(&ctx);
324	update(&ctx, in->str, in->str_len);
325	memset(dbuf.b, DIGEST_FILL, sizeof(dbuf));
326	final(&ctx, dbuf.b);
327	ck(hname, in, out);
328}
329
330
331
332/*
333 * isc_sha224_final has a different calling sequence
334 */
335static void
336t_sha224(IN *in, OUT *out)
337{
338	isc_sha224_t ctx;
339
340	memset(dbuf.b, DIGEST_FILL, sizeof(dbuf));
341	isc_sha224_init(&ctx);
342	isc_sha224_update(&ctx, in->str, in->str_len);
343	memset(dbuf.b, DIGEST_FILL, sizeof(dbuf));
344	isc_sha224_final(dbuf.b, &ctx);
345	ck("SHA224", in, out);
346}
347
348
349
350static void
351t_hashes(IN *in, OUT *out_sha1, OUT *out_sha224, OUT *out_md5)
352{
353	t_hash("SHA1", (HASH_INIT)isc_sha1_init, (UPDATE)isc_sha1_update,
354	       (FINAL)isc_sha1_final, in, out_sha1);
355	t_sha224(in, out_sha224);
356	t_hash("md5", (HASH_INIT)isc_md5_init, (UPDATE)isc_md5_update,
357	       (FINAL)isc_md5_final, in, out_md5);
358}
359
360
361
362/*
363 * isc_hmacmd5_sign has a different calling sequence
364 */
365static void
366t_md5hmac(IN *in, OUT *out)
367{
368	isc_hmacmd5_t ctx;
369
370	isc_hmacmd5_init(&ctx, in->key, in->key_len);
371	isc_hmacmd5_update(&ctx, in->str, in->str_len);
372	memset(dbuf.b, DIGEST_FILL, sizeof(dbuf));
373	isc_hmacmd5_sign(&ctx, dbuf.b);
374	ck("HMAC-md5", in, out);
375}
376
377
378
379static void
380t_hmac(const char *hname, HMAC_INIT init, UPDATE update, SIGN sign,
381      IN *in, OUT *out)
382{
383	union {
384	    unsigned char b[1024];
385	    isc_hmacmd5_t hmacmd5;
386	    isc_hmacsha1_t hmacsha1;
387	    isc_hmacsha224_t hmacsha224;
388	    isc_hmacsha256_t hmacsha256;
389	    isc_hmacsha384_t hmacsha384;
390	    isc_hmacsha512_t hmacsha512;
391	} ctx;
392
393	init(&ctx, in->key, in->key_len);
394	update(&ctx, in->str, in->str_len);
395	memset(dbuf.b, DIGEST_FILL, sizeof(dbuf));
396	sign(&ctx, dbuf.b, out->digest_len);
397	ck(hname, in, out);
398}
399
400
401
402static void
403t_hmacs(IN *in, OUT *out_sha1, OUT *out_sha224, OUT *out_sha256,
404	OUT *out_sha384, OUT *out_sha512)
405{
406	t_hmac("HMAC-SHA1", (HMAC_INIT)isc_hmacsha1_init,
407	       (UPDATE)isc_hmacsha1_update, (SIGN)isc_hmacsha1_sign,
408	       in, out_sha1);
409	t_hmac("HMAC-SHA224", (HMAC_INIT)isc_hmacsha224_init,
410	       (UPDATE)isc_hmacsha224_update, (SIGN)isc_hmacsha224_sign,
411	       in, out_sha224);
412	t_hmac("HMAC-SHA256", (HMAC_INIT)isc_hmacsha256_init,
413	       (UPDATE)isc_hmacsha256_update, (SIGN)isc_hmacsha256_sign,
414	       in, out_sha256);
415	t_hmac("HMAC-SHA384", (HMAC_INIT)isc_hmacsha384_init,
416	       (UPDATE)isc_hmacsha384_update, (SIGN)isc_hmacsha384_sign,
417	       in, out_sha384);
418	t_hmac("HMAC-SHA512", (HMAC_INIT)isc_hmacsha512_init,
419	       (UPDATE)isc_hmacsha512_update, (SIGN)isc_hmacsha512_sign,
420	       in, out_sha512);
421}
422
423
424
425/*
426 * This will almost never fail, and so there is no need for the extra noise
427 * that would come from breaking it into several tests.
428 */
429static void
430t1(void)
431{
432	/*
433	 * two ad hoc hash examples
434	 */
435	t_hashes(&abc, &abc_sha1, &abc_sha224, &abc_md5);
436	t_hashes(&abc_blah, &abc_blah_sha1, &abc_blah_sha224, &abc_blah_md5);
437
438	/*
439	 * three HMAC-md5 examples from RFC 2104
440	 */
441	t_md5hmac(&rfc2104_1, &rfc2104_1_hmac);
442	t_md5hmac(&rfc2104_2, &rfc2104_2_hmac);
443	t_md5hmac(&rfc2104_3, &rfc2104_3_hmac);
444
445	/*
446	 * four HMAC-SHA tests from RFC 4634 starting on page 86
447	 */
448	t_hmacs(&rfc4634_1, &rfc4634_1_sha1, &rfc4634_1_sha224,
449		&rfc4634_1_sha256, &rfc4634_1_sha384, &rfc4634_1_sha512);
450	t_hmacs(&rfc4634_2, &rfc4634_2_sha1, &rfc4634_2_sha224,
451		&rfc4634_2_sha256, &rfc4634_2_sha384, &rfc4634_2_sha512);
452	t_hmacs(&rfc4634_3, &rfc4634_3_sha1, &rfc4634_3_sha224,
453		&rfc4634_3_sha256, &rfc4634_3_sha384, &rfc4634_3_sha512);
454	t_hmacs(&rfc4634_4, &rfc4634_4_sha1, &rfc4634_4_sha224,
455		&rfc4634_4_sha256, &rfc4634_4_sha384, &rfc4634_4_sha512);
456
457	if (nprobs != 0)
458		t_result(T_FAIL);
459	else
460		t_result(T_PASS);
461}
462
463
464testspec_t	T_testlist[] = {
465	{	t1,		"hashes"		},
466	{	NULL,		NULL			}
467};
468