xref: /dflybsd-src/usr.sbin/mtree/hash.c (revision a512a68cfd0a387f2f0cd67487cee6e85014fc84)
1*a512a68cSzrj /*
2*a512a68cSzrj  * Copyright (c) 2019 The DragonFly Project.  All rights reserved.
3*a512a68cSzrj  *
4*a512a68cSzrj  * Redistribution and use in source and binary forms, with or without
5*a512a68cSzrj  * modification, are permitted provided that the following conditions
6*a512a68cSzrj  * are met:
7*a512a68cSzrj  * 1. Redistributions of source code must retain the above copyright
8*a512a68cSzrj  *    notice, this list of conditions and the following disclaimer.
9*a512a68cSzrj  * 2. Redistributions in binary form must reproduce the above copyright
10*a512a68cSzrj  *    notice, this list of conditions and the following disclaimer in the
11*a512a68cSzrj  *    documentation and/or other materials provided with the distribution.
12*a512a68cSzrj  *
13*a512a68cSzrj  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
14*a512a68cSzrj  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
15*a512a68cSzrj  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
16*a512a68cSzrj  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
17*a512a68cSzrj  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
18*a512a68cSzrj  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
19*a512a68cSzrj  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20*a512a68cSzrj  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
21*a512a68cSzrj  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22*a512a68cSzrj  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
23*a512a68cSzrj  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*a512a68cSzrj  * SUCH DAMAGE.
25*a512a68cSzrj  */
26*a512a68cSzrj 
27*a512a68cSzrj #include <sys/types.h>
28*a512a68cSzrj #include <sys/stat.h>
29*a512a68cSzrj #include <errno.h>
30*a512a68cSzrj #include <fcntl.h>
31*a512a68cSzrj #include <stdlib.h>
32*a512a68cSzrj #include <unistd.h>
33*a512a68cSzrj #include <openssl/md5.h>
34*a512a68cSzrj #include <openssl/sha.h>
35*a512a68cSzrj #include <openssl/ripemd.h>
36*a512a68cSzrj 
37*a512a68cSzrj #include <stdio.h>		/* for FILE in mtree.h */
38*a512a68cSzrj #include "extern.h"
39*a512a68cSzrj 
40*a512a68cSzrj /* max(MD5_DIGEST_LENGTH, SHA_DIGEST_LENGTH,
41*a512a68cSzrj 	SHA256_DIGEST_LENGTH, SHA512_DIGEST_LENGTH,
42*a512a68cSzrj 	RIPEMD160_DIGEST_LENGTH) * 2 + 1 */
43*a512a68cSzrj #define	HEX_DIGEST_LENGTH 129
44*a512a68cSzrj 
45*a512a68cSzrj typedef union {
46*a512a68cSzrj 	MD5_CTX md5;
47*a512a68cSzrj 	SHA_CTX sha1;
48*a512a68cSzrj 	SHA256_CTX sha256;
49*a512a68cSzrj 	SHA512_CTX sha512;
50*a512a68cSzrj 	RIPEMD160_CTX ripemd160;
51*a512a68cSzrj } DIGEST_CTX;
52*a512a68cSzrj 
53*a512a68cSzrj char *
dohash(int flag,const char * filename)54*a512a68cSzrj dohash(int flag, const char *filename)
55*a512a68cSzrj {
56*a512a68cSzrj 	unsigned char digest[HEX_DIGEST_LENGTH];
57*a512a68cSzrj 	static const char hex[]="0123456789abcdef";
58*a512a68cSzrj 	DIGEST_CTX context;
59*a512a68cSzrj 	void *ctx;
60*a512a68cSzrj 	unsigned char buffer[4096];
61*a512a68cSzrj 	char *buf;
62*a512a68cSzrj 	struct stat st;
63*a512a68cSzrj 	off_t size;
64*a512a68cSzrj 	int fd, bytes, i, digest_len;
65*a512a68cSzrj 
66*a512a68cSzrj 	ctx = &context;
67*a512a68cSzrj 
68*a512a68cSzrj 	if (flag == F_MD5)
69*a512a68cSzrj 		digest_len = MD5_DIGEST_LENGTH;
70*a512a68cSzrj 	else if (flag == F_RMD160)
71*a512a68cSzrj 		digest_len = RIPEMD160_DIGEST_LENGTH;
72*a512a68cSzrj 	else if (flag == F_SHA1)
73*a512a68cSzrj 		digest_len = SHA_DIGEST_LENGTH;
74*a512a68cSzrj 	else if (flag == F_SHA256)
75*a512a68cSzrj 		digest_len = SHA256_DIGEST_LENGTH;
76*a512a68cSzrj 	else if (flag == F_SHA384)
77*a512a68cSzrj 		digest_len = SHA384_DIGEST_LENGTH;
78*a512a68cSzrj 	else if (flag == F_SHA512)
79*a512a68cSzrj 		digest_len = SHA512_DIGEST_LENGTH;
80*a512a68cSzrj 	else
81*a512a68cSzrj 		return NULL;
82*a512a68cSzrj 
83*a512a68cSzrj 	buf = malloc(digest_len * 2 + 1);
84*a512a68cSzrj 	if (!buf)
85*a512a68cSzrj 		return NULL;
86*a512a68cSzrj 
87*a512a68cSzrj 	fd = open(filename, O_RDONLY);
88*a512a68cSzrj 	if (fd < 0)
89*a512a68cSzrj 		return NULL;
90*a512a68cSzrj 	if (fstat(fd, &st) < 0) {
91*a512a68cSzrj 		bytes = -1;
92*a512a68cSzrj 		goto err;
93*a512a68cSzrj 	}
94*a512a68cSzrj 
95*a512a68cSzrj 	if (flag == F_MD5)
96*a512a68cSzrj 		MD5_Init(ctx);
97*a512a68cSzrj 	else if (flag == F_RMD160)
98*a512a68cSzrj 		RIPEMD160_Init(ctx);
99*a512a68cSzrj 	else if (flag == F_SHA1)
100*a512a68cSzrj 		SHA1_Init(ctx);
101*a512a68cSzrj 	else if (flag == F_SHA256)
102*a512a68cSzrj 		SHA256_Init(ctx);
103*a512a68cSzrj 	else if (flag == F_SHA384)
104*a512a68cSzrj 		SHA384_Init(ctx);
105*a512a68cSzrj 	else if (flag == F_SHA512)
106*a512a68cSzrj 		SHA512_Init(ctx);
107*a512a68cSzrj 
108*a512a68cSzrj 	size = st.st_size;
109*a512a68cSzrj 	bytes = 0;
110*a512a68cSzrj 	while (size > 0) {
111*a512a68cSzrj 		if ((size_t)size > sizeof(buffer))
112*a512a68cSzrj 			bytes = read(fd, buffer, sizeof(buffer));
113*a512a68cSzrj 		else
114*a512a68cSzrj 			bytes = read(fd, buffer, size);
115*a512a68cSzrj 		if (bytes < 0)
116*a512a68cSzrj 			break;
117*a512a68cSzrj 
118*a512a68cSzrj 		if (flag == F_MD5)
119*a512a68cSzrj 			MD5_Update(ctx, buffer, bytes);
120*a512a68cSzrj 		else if (flag == F_RMD160)
121*a512a68cSzrj 			RIPEMD160_Update(ctx, buffer, bytes);
122*a512a68cSzrj 		else if (flag == F_SHA1)
123*a512a68cSzrj 			SHA1_Update(ctx, buffer, bytes);
124*a512a68cSzrj 		else if (flag == F_SHA256)
125*a512a68cSzrj 			SHA256_Update(ctx, buffer, bytes);
126*a512a68cSzrj 		else if (flag == F_SHA384)
127*a512a68cSzrj 			SHA384_Update(ctx, buffer, bytes);
128*a512a68cSzrj 		else if (flag == F_SHA512)
129*a512a68cSzrj 			SHA512_Update(ctx, buffer, bytes);
130*a512a68cSzrj 
131*a512a68cSzrj 		size -= bytes;
132*a512a68cSzrj 	}
133*a512a68cSzrj 
134*a512a68cSzrj err:
135*a512a68cSzrj 	close(fd);
136*a512a68cSzrj 
137*a512a68cSzrj 	if (bytes < 0)
138*a512a68cSzrj 		return NULL;
139*a512a68cSzrj 
140*a512a68cSzrj 	if (flag == F_MD5)
141*a512a68cSzrj 		MD5_Final(digest, ctx);
142*a512a68cSzrj 	else if (flag == F_RMD160)
143*a512a68cSzrj 		RIPEMD160_Final(digest, ctx);
144*a512a68cSzrj 	else if (flag == F_SHA1)
145*a512a68cSzrj 		SHA1_Final(digest, ctx);
146*a512a68cSzrj 	else if (flag == F_SHA256)
147*a512a68cSzrj 		SHA256_Final(digest, ctx);
148*a512a68cSzrj 	else if (flag == F_SHA384)
149*a512a68cSzrj 		SHA384_Final(digest, ctx);
150*a512a68cSzrj 	else if (flag == F_SHA512)
151*a512a68cSzrj 		SHA512_Final(digest, ctx);
152*a512a68cSzrj 
153*a512a68cSzrj 	for (i = 0; i < digest_len; i++) {
154*a512a68cSzrj 		buf[2*i] = hex[digest[i] >> 4];
155*a512a68cSzrj 		buf[2*i+1] = hex[digest[i] & 0x0f];
156*a512a68cSzrj 	}
157*a512a68cSzrj 	buf[digest_len * 2] = '\0';
158*a512a68cSzrj 
159*a512a68cSzrj 	return buf;
160*a512a68cSzrj }
161