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