Home | History | Annotate | Line # | Download | only in isc
      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