xref: /netbsd-src/external/mpl/bind/dist/lib/isc/iterated_hash.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: iterated_hash.c,v 1.9 2025/01/26 16:25:37 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 #include <stdbool.h>
17 #include <stdio.h>
18 
19 #include <openssl/err.h>
20 #include <openssl/opensslv.h>
21 
22 #include <isc/iterated_hash.h>
23 #include <isc/thread.h>
24 #include <isc/util.h>
25 
26 #if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000
27 
28 #include <openssl/sha.h>
29 
30 int
31 isc_iterated_hash(unsigned char *out, const unsigned int hashalg,
32 		  const int iterations, const unsigned char *salt,
33 		  const int saltlength, const unsigned char *in,
34 		  const int inlength) {
35 	REQUIRE(out != NULL);
36 
37 	int n = 0;
38 	size_t len;
39 	const unsigned char *buf;
40 	SHA_CTX ctx;
41 
42 	if (hashalg != 1) {
43 		return 0;
44 	}
45 
46 	buf = in;
47 	len = inlength;
48 
49 	do {
50 		if (SHA1_Init(&ctx) != 1) {
51 			ERR_clear_error();
52 			return 0;
53 		}
54 
55 		if (SHA1_Update(&ctx, buf, len) != 1) {
56 			ERR_clear_error();
57 			return 0;
58 		}
59 
60 		if (SHA1_Update(&ctx, salt, saltlength) != 1) {
61 			ERR_clear_error();
62 			return 0;
63 		}
64 
65 		if (SHA1_Final(out, &ctx) != 1) {
66 			ERR_clear_error();
67 			return 0;
68 		}
69 
70 		buf = out;
71 		len = SHA_DIGEST_LENGTH;
72 	} while (n++ < iterations);
73 
74 	return SHA_DIGEST_LENGTH;
75 }
76 
77 void
78 isc__iterated_hash_initialize(void) {
79 	/* empty */
80 }
81 
82 void
83 isc__iterated_hash_shutdown(void) {
84 	/* empty */
85 }
86 
87 #else /* HAVE_SHA1_INIT */
88 
89 #include <openssl/evp.h>
90 
91 static thread_local bool initialized = false;
92 static thread_local EVP_MD_CTX *mdctx = NULL;
93 static thread_local EVP_MD_CTX *basectx = NULL;
94 static thread_local EVP_MD *md = NULL;
95 
96 int
97 isc_iterated_hash(unsigned char *out, const unsigned int hashalg,
98 		  const int iterations, const unsigned char *salt,
99 		  const int saltlength, const unsigned char *in,
100 		  const int inlength) {
101 	REQUIRE(out != NULL);
102 	REQUIRE(mdctx != NULL);
103 	REQUIRE(basectx != NULL);
104 
105 	int n = 0;
106 	size_t len;
107 	unsigned int outlength = 0;
108 	const unsigned char *buf;
109 
110 	if (hashalg != 1) {
111 		return 0;
112 	}
113 
114 	buf = in;
115 	len = inlength;
116 	do {
117 		if (EVP_MD_CTX_copy_ex(mdctx, basectx) != 1) {
118 			goto fail;
119 		}
120 
121 		if (EVP_DigestUpdate(mdctx, buf, len) != 1) {
122 			goto fail;
123 		}
124 
125 		if (EVP_DigestUpdate(mdctx, salt, saltlength) != 1) {
126 			goto fail;
127 		}
128 
129 		if (EVP_DigestFinal_ex(mdctx, out, &outlength) != 1) {
130 			goto fail;
131 		}
132 
133 		buf = out;
134 		len = outlength;
135 	} while (n++ < iterations);
136 
137 	return outlength;
138 
139 fail:
140 	ERR_clear_error();
141 	return 0;
142 }
143 
144 void
145 isc__iterated_hash_initialize(void) {
146 	if (initialized) {
147 		return;
148 	}
149 
150 	basectx = EVP_MD_CTX_new();
151 	INSIST(basectx != NULL);
152 	mdctx = EVP_MD_CTX_new();
153 	INSIST(mdctx != NULL);
154 	md = EVP_MD_fetch(NULL, "SHA1", NULL);
155 	INSIST(md != NULL);
156 
157 	RUNTIME_CHECK(EVP_DigestInit_ex(basectx, md, NULL) == 1);
158 	initialized = true;
159 }
160 
161 void
162 isc__iterated_hash_shutdown(void) {
163 	if (!initialized) {
164 		return;
165 	}
166 
167 	REQUIRE(mdctx != NULL);
168 	EVP_MD_CTX_free(mdctx);
169 	mdctx = NULL;
170 	REQUIRE(basectx != NULL);
171 	EVP_MD_CTX_free(basectx);
172 	basectx = NULL;
173 	EVP_MD_free(md);
174 	md = NULL;
175 
176 	initialized = false;
177 }
178 
179 #endif /* HAVE_SHA1_INIT */
180