Home | History | Annotate | Line # | Download | only in isc
hash.c revision 1.2.2.2
      1 /*	$NetBSD: hash.c,v 1.2.2.2 2018/09/06 06:55:05 pgoyette Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * This Source Code Form is subject to the terms of the Mozilla Public
      7  * License, v. 2.0. If a copy of the MPL was not distributed with this
      8  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
      9  *
     10  * See the COPYRIGHT file distributed with this work for additional
     11  * information regarding copyright ownership.
     12  */
     13 
     14 /*! \file
     15  * Some portion of this code was derived from universal hash function
     16  * libraries of Rice University.
     17 \section license UH Universal Hashing Library
     18 
     19 Copyright ((c)) 2002, Rice University
     20 All rights reserved.
     21 
     22 Redistribution and use in source and binary forms, with or without
     23 modification, are permitted provided that the following conditions are
     24 met:
     25 
     26     * Redistributions of source code must retain the above copyright
     27     notice, this list of conditions and the following disclaimer.
     28 
     29     * Redistributions in binary form must reproduce the above
     30     copyright notice, this list of conditions and the following
     31     disclaimer in the documentation and/or other materials provided
     32     with the distribution.
     33 
     34     * Neither the name of Rice University (RICE) nor the names of its
     35     contributors may be used to endorse or promote products derived
     36     from this software without specific prior written permission.
     37 
     38 
     39 This software is provided by RICE and the contributors on an "as is"
     40 basis, without any representations or warranties of any kind, express
     41 or implied including, but not limited to, representations or
     42 warranties of non-infringement, merchantability or fitness for a
     43 particular purpose. In no event shall RICE or contributors be liable
     44 for any direct, indirect, incidental, special, exemplary, or
     45 consequential damages (including, but not limited to, procurement of
     46 substitute goods or services; loss of use, data, or profits; or
     47 business interruption) however caused and on any theory of liability,
     48 whether in contract, strict liability, or tort (including negligence
     49 or otherwise) arising in any way out of the use of this software, even
     50 if advised of the possibility of such damage.
     51 */
     52 
     53 #include <config.h>
     54 
     55 #include <isc/entropy.h>
     56 #include <isc/hash.h>
     57 #include <isc/mem.h>
     58 #include <isc/magic.h>
     59 #include <isc/mutex.h>
     60 #include <isc/once.h>
     61 #include <isc/random.h>
     62 #include <isc/refcount.h>
     63 #include <isc/string.h>
     64 #include <isc/util.h>
     65 
     66 #define HASH_MAGIC		ISC_MAGIC('H', 'a', 's', 'h')
     67 #define VALID_HASH(h)		ISC_MAGIC_VALID((h), HASH_MAGIC)
     68 
     69 /*%
     70  * A large 32-bit prime number that specifies the range of the hash output.
     71  */
     72 #define PRIME32 0xFFFFFFFB              /* 2^32 -  5 */
     73 
     74 /*@{*/
     75 /*%
     76  * Types of random seed and hash accumulator.  Perhaps they can be system
     77  * dependent.
     78  */
     79 typedef isc_uint32_t hash_accum_t;
     80 typedef isc_uint16_t hash_random_t;
     81 /*@}*/
     82 
     83 /*% isc hash structure */
     84 struct isc_hash {
     85 	unsigned int	magic;
     86 	isc_mem_t	*mctx;
     87 	isc_mutex_t	lock;
     88 	isc_boolean_t	initialized;
     89 	isc_refcount_t	refcnt;
     90 	isc_entropy_t	*entropy; /*%< entropy source */
     91 	size_t		limit;	/*%< upper limit of key length */
     92 	size_t		vectorlen; /*%< size of the vector below */
     93 	hash_random_t	*rndvector; /*%< random vector for universal hashing */
     94 };
     95 
     96 static isc_mutex_t createlock;
     97 static isc_once_t once = ISC_ONCE_INIT;
     98 
     99 LIBISC_EXTERNAL_DATA isc_hash_t *isc_hashctx = NULL;
    100 
    101 static unsigned char maptolower[] = {
    102 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    103 	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    104 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    105 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
    106 	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
    107 	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
    108 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
    109 	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
    110 	0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
    111 	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
    112 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
    113 	0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
    114 	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
    115 	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
    116 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
    117 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
    118 	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
    119 	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
    120 	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
    121 	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
    122 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
    123 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
    124 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
    125 	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
    126 	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
    127 	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
    128 	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
    129 	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
    130 	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
    131 	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
    132 	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
    133 	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
    134 };
    135 
    136 isc_result_t
    137 isc_hash_ctxcreate(isc_mem_t *mctx, isc_entropy_t *entropy,
    138 		   size_t limit, isc_hash_t **hctxp)
    139 {
    140 	isc_result_t result;
    141 	isc_hash_t *hctx;
    142 	size_t vlen;
    143 	hash_random_t *rv;
    144 	hash_accum_t overflow_limit;
    145 
    146 	REQUIRE(mctx != NULL);
    147 	REQUIRE(hctxp != NULL && *hctxp == NULL);
    148 
    149 	/*
    150 	 * Overflow check.  Since our implementation only does a modulo
    151 	 * operation at the last stage of hash calculation, the accumulator
    152 	 * must not overflow.
    153 	 */
    154 	overflow_limit =
    155 		1 << (((sizeof(hash_accum_t) - sizeof(hash_random_t))) * 8);
    156 	if (overflow_limit < (limit + 1) * 0xff)
    157 		return (ISC_R_RANGE);
    158 
    159 	hctx = isc_mem_get(mctx, sizeof(isc_hash_t));
    160 	if (hctx == NULL)
    161 		return (ISC_R_NOMEMORY);
    162 
    163 	vlen = sizeof(hash_random_t) * (limit + 1);
    164 	rv = isc_mem_get(mctx, vlen);
    165 	if (rv == NULL) {
    166 		result = ISC_R_NOMEMORY;
    167 		goto errout;
    168 	}
    169 
    170 	/*
    171 	 * We need a lock.
    172 	 */
    173 	result = isc_mutex_init(&hctx->lock);
    174 	if (result != ISC_R_SUCCESS)
    175 		goto errout;
    176 
    177 	/*
    178 	 * From here down, no failures will/can occur.
    179 	 */
    180 	hctx->magic = HASH_MAGIC;
    181 	hctx->mctx = NULL;
    182 	isc_mem_attach(mctx, &hctx->mctx);
    183 	hctx->initialized = ISC_FALSE;
    184 	result = isc_refcount_init(&hctx->refcnt, 1);
    185 	if (result != ISC_R_SUCCESS)
    186 		goto cleanup_lock;
    187 	hctx->entropy = NULL;
    188 	hctx->limit = limit;
    189 	hctx->vectorlen = vlen;
    190 	hctx->rndvector = rv;
    191 
    192 	if (entropy != NULL)
    193 		isc_entropy_attach(entropy, &hctx->entropy);
    194 
    195 	*hctxp = hctx;
    196 	return (ISC_R_SUCCESS);
    197 
    198  cleanup_lock:
    199 	DESTROYLOCK(&hctx->lock);
    200  errout:
    201 	isc_mem_put(mctx, hctx, sizeof(isc_hash_t));
    202 	if (rv != NULL)
    203 		isc_mem_put(mctx, rv, vlen);
    204 
    205 	return (result);
    206 }
    207 
    208 static void
    209 initialize_lock(void) {
    210 	RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS);
    211 }
    212 
    213 isc_result_t
    214 isc_hash_create(isc_mem_t *mctx, isc_entropy_t *entropy, size_t limit) {
    215 	isc_result_t result = ISC_R_SUCCESS;
    216 
    217 	REQUIRE(mctx != NULL);
    218 	INSIST(isc_hashctx == NULL);
    219 
    220 	RUNTIME_CHECK(isc_once_do(&once, initialize_lock) == ISC_R_SUCCESS);
    221 
    222 	LOCK(&createlock);
    223 
    224 	if (isc_hashctx == NULL)
    225 		result = isc_hash_ctxcreate(mctx, entropy, limit,
    226 					    &isc_hashctx);
    227 
    228 	UNLOCK(&createlock);
    229 
    230 	return (result);
    231 }
    232 
    233 void
    234 isc_hash_ctxinit(isc_hash_t *hctx) {
    235 	LOCK(&hctx->lock);
    236 
    237 	if (hctx->initialized == ISC_TRUE)
    238 		goto out;
    239 
    240 	if (hctx->entropy != NULL) {
    241 		isc_result_t result;
    242 
    243 		result = isc_entropy_getdata(hctx->entropy,
    244 					     hctx->rndvector,
    245 					     (unsigned int)hctx->vectorlen,
    246 					     NULL, 0);
    247 		INSIST(result == ISC_R_SUCCESS);
    248 	} else {
    249 		isc_uint32_t pr;
    250 		size_t i, copylen;
    251 		unsigned char *p;
    252 
    253 		p = (unsigned char *)hctx->rndvector;
    254 		for (i = 0; i < hctx->vectorlen; i += copylen, p += copylen) {
    255 			isc_random_get(&pr);
    256 			if (i + sizeof(pr) <= hctx->vectorlen)
    257 				copylen = sizeof(pr);
    258 			else
    259 				copylen = hctx->vectorlen - i;
    260 
    261 			memmove(p, &pr, copylen);
    262 		}
    263 		INSIST(p == (unsigned char *)hctx->rndvector +
    264 		       hctx->vectorlen);
    265 	}
    266 
    267 	hctx->initialized = ISC_TRUE;
    268 
    269  out:
    270 	UNLOCK(&hctx->lock);
    271 }
    272 
    273 void
    274 isc_hash_init(void) {
    275 	INSIST(isc_hashctx != NULL && VALID_HASH(isc_hashctx));
    276 
    277 	isc_hash_ctxinit(isc_hashctx);
    278 }
    279 
    280 void
    281 isc_hash_ctxattach(isc_hash_t *hctx, isc_hash_t **hctxp) {
    282 	REQUIRE(VALID_HASH(hctx));
    283 	REQUIRE(hctxp != NULL && *hctxp == NULL);
    284 
    285 	isc_refcount_increment(&hctx->refcnt, NULL);
    286 	*hctxp = hctx;
    287 }
    288 
    289 static void
    290 destroy(isc_hash_t **hctxp) {
    291 	isc_hash_t *hctx;
    292 	isc_mem_t *mctx;
    293 
    294 	REQUIRE(hctxp != NULL && *hctxp != NULL);
    295 	hctx = *hctxp;
    296 	*hctxp = NULL;
    297 
    298 	LOCK(&hctx->lock);
    299 
    300 	isc_refcount_destroy(&hctx->refcnt);
    301 
    302 	mctx = hctx->mctx;
    303 	if (hctx->entropy != NULL)
    304 		isc_entropy_detach(&hctx->entropy);
    305 	if (hctx->rndvector != NULL)
    306 		isc_mem_put(mctx, hctx->rndvector, hctx->vectorlen);
    307 
    308 	UNLOCK(&hctx->lock);
    309 
    310 	DESTROYLOCK(&hctx->lock);
    311 
    312 	memset(hctx, 0, sizeof(isc_hash_t));
    313 	isc_mem_put(mctx, hctx, sizeof(isc_hash_t));
    314 	isc_mem_detach(&mctx);
    315 }
    316 
    317 void
    318 isc_hash_ctxdetach(isc_hash_t **hctxp) {
    319 	isc_hash_t *hctx;
    320 	unsigned int refs;
    321 
    322 	REQUIRE(hctxp != NULL && VALID_HASH(*hctxp));
    323 	hctx = *hctxp;
    324 
    325 	isc_refcount_decrement(&hctx->refcnt, &refs);
    326 	if (refs == 0)
    327 		destroy(&hctx);
    328 
    329 	*hctxp = NULL;
    330 }
    331 
    332 void
    333 isc_hash_destroy(void) {
    334 	unsigned int refs;
    335 
    336 	INSIST(isc_hashctx != NULL && VALID_HASH(isc_hashctx));
    337 
    338 	isc_refcount_decrement(&isc_hashctx->refcnt, &refs);
    339 	INSIST(refs == 0);
    340 
    341 	destroy(&isc_hashctx);
    342 }
    343 
    344 static inline unsigned int
    345 hash_calc(isc_hash_t *hctx, const unsigned char *key, unsigned int keylen,
    346 	  isc_boolean_t case_sensitive)
    347 {
    348 	hash_accum_t partial_sum = 0;
    349 	hash_random_t *p = hctx->rndvector;
    350 	unsigned int i = 0;
    351 
    352 	/* Make it sure that the hash context is initialized. */
    353 	if (hctx->initialized == ISC_FALSE)
    354 		isc_hash_ctxinit(hctx);
    355 
    356 	if (case_sensitive) {
    357 		for (i = 0; i < keylen; i++)
    358 			partial_sum += key[i] * (hash_accum_t)p[i];
    359 	} else {
    360 		for (i = 0; i < keylen; i++)
    361 			partial_sum += maptolower[key[i]] * (hash_accum_t)p[i];
    362 	}
    363 
    364 	partial_sum += p[i];
    365 
    366 	return ((unsigned int)(partial_sum % PRIME32));
    367 }
    368 
    369 unsigned int
    370 isc_hash_ctxcalc(isc_hash_t *hctx, const unsigned char *key,
    371 		 unsigned int keylen, isc_boolean_t case_sensitive)
    372 {
    373 	REQUIRE(hctx != NULL && VALID_HASH(hctx));
    374 	REQUIRE(keylen <= hctx->limit);
    375 
    376 	return (hash_calc(hctx, key, keylen, case_sensitive));
    377 }
    378 
    379 unsigned int
    380 isc_hash_calc(const unsigned char *key, unsigned int keylen,
    381 	      isc_boolean_t case_sensitive)
    382 {
    383 	INSIST(isc_hashctx != NULL && VALID_HASH(isc_hashctx));
    384 	REQUIRE(keylen <= isc_hashctx->limit);
    385 
    386 	return (hash_calc(isc_hashctx, key, keylen, case_sensitive));
    387 }
    388 
    389 void
    390 isc__hash_setvec(const isc_uint16_t *vec) {
    391 	int i;
    392 	hash_random_t *p;
    393 
    394 	if (isc_hashctx == NULL)
    395 		return;
    396 
    397 	p = isc_hashctx->rndvector;
    398 	for (i = 0; i < 256; i++) {
    399 		p[i] = vec[i];
    400 	}
    401 }
    402 
    403 static isc_uint32_t fnv_offset_basis;
    404 static isc_once_t fnv_once = ISC_ONCE_INIT;
    405 static isc_boolean_t fnv_initialized = ISC_FALSE;
    406 
    407 static void
    408 fnv_initialize(void) {
    409 	/*
    410 	 * This function should not leave fnv_offset_basis set to
    411 	 * 0. Also, after this function has been called, if it is called
    412 	 * again, it should not change fnv_offset_basis.
    413 	 */
    414 	while (fnv_offset_basis == 0) {
    415 		isc_random_get(&fnv_offset_basis);
    416 	}
    417 
    418 	fnv_initialized = ISC_TRUE;
    419 }
    420 
    421 const void *
    422 isc_hash_get_initializer(void) {
    423 	if (ISC_UNLIKELY(!fnv_initialized))
    424 		RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
    425 
    426 	return (&fnv_offset_basis);
    427 }
    428 
    429 void
    430 isc_hash_set_initializer(const void *initializer) {
    431 	REQUIRE(initializer != NULL);
    432 
    433 	/*
    434 	 * Ensure that fnv_initialize() is not called after
    435 	 * isc_hash_set_initializer() is called.
    436 	 */
    437 	if (ISC_UNLIKELY(!fnv_initialized))
    438 		RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
    439 
    440 	fnv_offset_basis = *((const unsigned int *) initializer);
    441 }
    442 
    443 isc_uint32_t
    444 isc_hash_function(const void *data, size_t length,
    445 		  isc_boolean_t case_sensitive,
    446 		  const isc_uint32_t *previous_hashp)
    447 {
    448 	isc_uint32_t hval;
    449 	const unsigned char *bp;
    450 	const unsigned char *be;
    451 
    452 	REQUIRE(length == 0 || data != NULL);
    453 
    454 	if (ISC_UNLIKELY(!fnv_initialized))
    455 		RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
    456 
    457 	hval = ISC_UNLIKELY(previous_hashp != NULL) ?
    458 		*previous_hashp : fnv_offset_basis;
    459 
    460 	if (length == 0)
    461 		return (hval);
    462 
    463 	bp = (const unsigned char *) data;
    464 	be = bp + length;
    465 
    466 	/*
    467 	 * Fowler-Noll-Vo FNV-1a hash function.
    468 	 *
    469 	 * NOTE: A random FNV offset basis is used by default to avoid
    470 	 * collision attacks as the hash function is reversible. This
    471 	 * makes the mapping non-deterministic, but the distribution in
    472 	 * the domain is still uniform.
    473 	 */
    474 
    475 	if (case_sensitive) {
    476 		while (bp <= be - 4) {
    477 			hval ^= bp[0];
    478 			hval *= 16777619;
    479 			hval ^= bp[1];
    480 			hval *= 16777619;
    481 			hval ^= bp[2];
    482 			hval *= 16777619;
    483 			hval ^= bp[3];
    484 			hval *= 16777619;
    485 			bp += 4;
    486 		}
    487 		while (bp < be) {
    488 			hval ^= *bp++;
    489 			hval *= 16777619;
    490 		}
    491 	} else {
    492 		while (bp <= be - 4) {
    493 			hval ^= maptolower[bp[0]];
    494 			hval *= 16777619;
    495 			hval ^= maptolower[bp[1]];
    496 			hval *= 16777619;
    497 			hval ^= maptolower[bp[2]];
    498 			hval *= 16777619;
    499 			hval ^= maptolower[bp[3]];
    500 			hval *= 16777619;
    501 			bp += 4;
    502 		}
    503 		while (bp < be) {
    504 			hval ^= maptolower[*bp++];
    505 			hval *= 16777619;
    506 		}
    507 	}
    508 
    509 	return (hval);
    510 }
    511 
    512 isc_uint32_t
    513 isc_hash_function_reverse(const void *data, size_t length,
    514 			  isc_boolean_t case_sensitive,
    515 			  const isc_uint32_t *previous_hashp)
    516 {
    517 	isc_uint32_t hval;
    518 	const unsigned char *bp;
    519 	const unsigned char *be;
    520 
    521 	REQUIRE(length == 0 || data != NULL);
    522 
    523 	if (ISC_UNLIKELY(!fnv_initialized))
    524 		RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
    525 
    526 	hval = ISC_UNLIKELY(previous_hashp != NULL) ?
    527 		*previous_hashp : fnv_offset_basis;
    528 
    529 	if (length == 0)
    530 		return (hval);
    531 
    532 	bp = (const unsigned char *) data;
    533 	be = bp + length;
    534 
    535 	/*
    536 	 * Fowler-Noll-Vo FNV-1a hash function.
    537 	 *
    538 	 * NOTE: A random FNV offset basis is used by default to avoid
    539 	 * collision attacks as the hash function is reversible. This
    540 	 * makes the mapping non-deterministic, but the distribution in
    541 	 * the domain is still uniform.
    542 	 */
    543 
    544 	if (case_sensitive) {
    545 		while (be >= bp + 4) {
    546 			be -= 4;
    547 			hval ^= be[3];
    548 			hval *= 16777619;
    549 			hval ^= be[2];
    550 			hval *= 16777619;
    551 			hval ^= be[1];
    552 			hval *= 16777619;
    553 			hval ^= be[0];
    554 			hval *= 16777619;
    555 		}
    556 		while (--be >= bp) {
    557 			hval ^= *be;
    558 			hval *= 16777619;
    559 		}
    560 	} else {
    561 		while (be >= bp + 4) {
    562 			be -= 4;
    563 			hval ^= maptolower[be[3]];
    564 			hval *= 16777619;
    565 			hval ^= maptolower[be[2]];
    566 			hval *= 16777619;
    567 			hval ^= maptolower[be[1]];
    568 			hval *= 16777619;
    569 			hval ^= maptolower[be[0]];
    570 			hval *= 16777619;
    571 		}
    572 		while (--be >= bp) {
    573 			hval ^= maptolower[*be];
    574 			hval *= 16777619;
    575 		}
    576 	}
    577 
    578 	return (hval);
    579 }
    580