1/*-
2 * Copyright (c) 2012 Alistair Crooks <agc@NetBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25#include "config.h"
26
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <sys/param.h>
30
31#include <arpa/inet.h>
32#include <ctype.h>
33#include <inttypes.h>
34#include <stdarg.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <time.h>
39#include <unistd.h>
40
41#include "md5.h"
42#include "rmd160.h"
43#include "sha1.h"
44#include "sha2.h"
45
46#include "digest.h"
47
48#ifndef USE_ARG
49#define	USE_ARG(x)	/*LINTED*/(void)&(x)
50#endif
51
52static uint8_t prefix_md5[] = {
53	0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86,
54	0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10
55};
56
57static uint8_t prefix_sha1[] = {
58	0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E, 0x03, 0x02,
59	0x1A, 0x05, 0x00, 0x04, 0x14
60};
61
62static uint8_t prefix_sha256[] = {
63	0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
64	0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
65};
66
67static uint8_t prefix_rmd160[] = {
68	0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24,
69	0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14
70};
71
72static uint8_t prefix_sha512[] = {
73	0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
74	0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40
75};
76
77#define V4_SIGNATURE		4
78
79/*************************************************************************/
80
81/* algorithm size (raw) */
82int
83digest_alg_size(unsigned alg)
84{
85	switch(alg) {
86	case MD5_HASH_ALG:
87		return 16;
88	case SHA1_HASH_ALG:
89		return 20;
90	case RIPEMD_HASH_ALG:
91		return RMD160_DIGEST_LENGTH;
92	case SHA256_HASH_ALG:
93		return 32;
94	case SHA512_HASH_ALG:
95		return 64;
96	default:
97		printf("hash_any: bad algorithm\n");
98		return 0;
99	}
100}
101
102/* initialise the hash structure */
103int
104digest_init(digest_t *hash, const uint32_t hashalg)
105{
106	if (hash == NULL) {
107		return 0;
108	}
109	switch(hash->alg = hashalg) {
110	case MD5_HASH_ALG:
111		netpgpv_MD5Init(&hash->u.md5ctx);
112		hash->size = 16;
113		hash->prefix = prefix_md5;
114		hash->len = sizeof(prefix_md5);
115		hash->ctx = &hash->u.md5ctx;
116		return 1;
117	case SHA1_HASH_ALG:
118		netpgpv_SHA1Init(&hash->u.sha1ctx);
119		hash->size = 20;
120		hash->prefix = prefix_sha1;
121		hash->len = sizeof(prefix_sha1);
122		hash->ctx = &hash->u.sha1ctx;
123		return 1;
124	case RIPEMD_HASH_ALG:
125		netpgpv_RMD160Init(&hash->u.rmd160ctx);
126		hash->size = 20;
127		hash->prefix = prefix_rmd160;
128		hash->len = sizeof(prefix_rmd160);
129		hash->ctx = &hash->u.rmd160ctx;
130		return 1;
131	case SHA256_HASH_ALG:
132		netpgpv_SHA256_Init(&hash->u.sha256ctx);
133		hash->size = 32;
134		hash->prefix = prefix_sha256;
135		hash->len = sizeof(prefix_sha256);
136		hash->ctx = &hash->u.sha256ctx;
137		return 1;
138	case SHA512_HASH_ALG:
139		netpgpv_SHA512_Init(&hash->u.sha512ctx);
140		hash->size = 64;
141		hash->prefix = prefix_sha512;
142		hash->len = sizeof(prefix_sha512);
143		hash->ctx = &hash->u.sha512ctx;
144		return 1;
145	default:
146		printf("hash_any: bad algorithm\n");
147		return 0;
148	}
149}
150
151typedef struct rec_t {
152	const char	*s;
153	const unsigned	 alg;
154} rec_t;
155
156static rec_t	hashalgs[] = {
157	{	"md5",		MD5_HASH_ALG	},
158	{	"sha1",		SHA1_HASH_ALG	},
159	{	"ripemd",	RIPEMD_HASH_ALG	},
160	{	"sha256",	SHA256_HASH_ALG	},
161	{	"sha512",	SHA512_HASH_ALG	},
162	{	NULL,		0		}
163};
164
165/* initialise by string alg name */
166unsigned
167digest_get_alg(const char *hashalg)
168{
169	rec_t	*r;
170
171	for (r = hashalgs ; hashalg && r->s ; r++) {
172		if (strcasecmp(r->s, hashalg) == 0) {
173			return r->alg;
174		}
175	}
176	return 0;
177}
178
179int
180digest_update(digest_t *hash, const uint8_t *data, size_t length)
181{
182	if (hash == NULL || data == NULL) {
183		return 0;
184	}
185	switch(hash->alg) {
186	case MD5_HASH_ALG:
187		netpgpv_MD5Update(hash->ctx, data, (unsigned)length);
188		return 1;
189	case SHA1_HASH_ALG:
190		netpgpv_SHA1Update(hash->ctx, data, (unsigned)length);
191		return 1;
192	case RIPEMD_HASH_ALG:
193		netpgpv_RMD160Update(hash->ctx, data, (unsigned)length);
194		return 1;
195	case SHA256_HASH_ALG:
196		netpgpv_SHA256_Update(hash->ctx, data, length);
197		return 1;
198	case SHA512_HASH_ALG:
199		netpgpv_SHA512_Update(hash->ctx, data, length);
200		return 1;
201	default:
202		printf("hash_any: bad algorithm\n");
203		return 0;
204	}
205}
206
207unsigned
208digest_final(uint8_t *out, digest_t *hash)
209{
210	if (hash == NULL || out == NULL) {
211		return 0;
212	}
213	switch(hash->alg) {
214	case MD5_HASH_ALG:
215		netpgpv_MD5Final(out, hash->ctx);
216		break;
217	case SHA1_HASH_ALG:
218		netpgpv_SHA1Final(out, hash->ctx);
219		break;
220	case RIPEMD_HASH_ALG:
221		netpgpv_RMD160Final(out, hash->ctx);
222		break;
223	case SHA256_HASH_ALG:
224		netpgpv_SHA256_Final(out, hash->ctx);
225		break;
226	case SHA512_HASH_ALG:
227		netpgpv_SHA512_Final(out, hash->ctx);
228		break;
229	default:
230		printf("hash_any: bad algorithm\n");
231		return 0;
232	}
233	(void) memset(hash->ctx, 0x0, hash->size);
234	return (unsigned)hash->size;
235}
236
237int
238digest_length(digest_t *hash, unsigned hashedlen)
239{
240	uint8_t		 trailer[6];
241
242	if (hash == NULL) {
243		return 0;
244	}
245	trailer[0] = V4_SIGNATURE;
246	trailer[1] = 0xFF;
247	trailer[2] = (uint8_t)((hashedlen >> 24) & 0xff);
248	trailer[3] = (uint8_t)((hashedlen >> 16) & 0xff);
249	trailer[4] = (uint8_t)((hashedlen >> 8) & 0xff);
250	trailer[5] = (uint8_t)(hashedlen & 0xff);
251	digest_update(hash, trailer, sizeof(trailer));
252	return 1;
253}
254
255unsigned
256digest_get_prefix(unsigned hashalg, uint8_t *prefix, size_t size)
257{
258	USE_ARG(size);
259	if (prefix == NULL) {
260		return 0;
261	}
262	switch (hashalg) {
263	case MD5_HASH_ALG:
264		memcpy(prefix, prefix_md5, sizeof(prefix_md5));
265		return sizeof(prefix_md5);
266	case SHA1_HASH_ALG:
267		memcpy(prefix, prefix_sha1, sizeof(prefix_sha1));
268		return sizeof(prefix_sha1);
269	case SHA256_HASH_ALG:
270		memcpy(prefix, prefix_sha256, sizeof(prefix_sha256));
271		return sizeof(prefix_sha256);
272	case SHA512_HASH_ALG:
273		memcpy(prefix, prefix_sha512, sizeof(prefix_sha512));
274		return sizeof(prefix_sha512);
275	default:
276		printf("digest_get_prefix: unknown hash algorithm: %d\n", hashalg);
277		return 0;
278	}
279}
280
281