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