hash.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2007, 2009, 2013-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id: hash.c,v 1.16 2009/09/01 00:22:28 jinmei Exp $ */
00019 
00020 /*! \file
00021  * Some portion of this code was derived from universal hash function
00022  * libraries of Rice University.
00023 \section license UH Universal Hashing Library
00024 
00025 Copyright ((c)) 2002, Rice University
00026 All rights reserved.
00027 
00028 Redistribution and use in source and binary forms, with or without
00029 modification, are permitted provided that the following conditions are
00030 met:
00031 
00032     * Redistributions of source code must retain the above copyright
00033     notice, this list of conditions and the following disclaimer.
00034 
00035     * Redistributions in binary form must reproduce the above
00036     copyright notice, this list of conditions and the following
00037     disclaimer in the documentation and/or other materials provided
00038     with the distribution.
00039 
00040     * Neither the name of Rice University (RICE) nor the names of its
00041     contributors may be used to endorse or promote products derived
00042     from this software without specific prior written permission.
00043 
00044 
00045 This software is provided by RICE and the contributors on an "as is"
00046 basis, without any representations or warranties of any kind, express
00047 or implied including, but not limited to, representations or
00048 warranties of non-infringement, merchantability or fitness for a
00049 particular purpose. In no event shall RICE or contributors be liable
00050 for any direct, indirect, incidental, special, exemplary, or
00051 consequential damages (including, but not limited to, procurement of
00052 substitute goods or services; loss of use, data, or profits; or
00053 business interruption) however caused and on any theory of liability,
00054 whether in contract, strict liability, or tort (including negligence
00055 or otherwise) arising in any way out of the use of this software, even
00056 if advised of the possibility of such damage.
00057 */
00058 
00059 #include <config.h>
00060 
00061 #include <isc/entropy.h>
00062 #include <isc/hash.h>
00063 #include <isc/mem.h>
00064 #include <isc/magic.h>
00065 #include <isc/mutex.h>
00066 #include <isc/once.h>
00067 #include <isc/random.h>
00068 #include <isc/refcount.h>
00069 #include <isc/string.h>
00070 #include <isc/util.h>
00071 
00072 #define HASH_MAGIC              ISC_MAGIC('H', 'a', 's', 'h')
00073 #define VALID_HASH(h)           ISC_MAGIC_VALID((h), HASH_MAGIC)
00074 
00075 /*%
00076  * A large 32-bit prime number that specifies the range of the hash output.
00077  */
00078 #define PRIME32 0xFFFFFFFB              /* 2^32 -  5 */
00079 
00080 /*@{*/
00081 /*%
00082  * Types of random seed and hash accumulator.  Perhaps they can be system
00083  * dependent.
00084  */
00085 typedef isc_uint32_t hash_accum_t;
00086 typedef isc_uint16_t hash_random_t;
00087 /*@}*/
00088 
00089 /*% isc hash structure */
00090 struct isc_hash {
00091         unsigned int    magic;
00092         isc_mem_t       *mctx;
00093         isc_mutex_t     lock;
00094         isc_boolean_t   initialized;
00095         isc_refcount_t  refcnt;
00096         isc_entropy_t   *entropy; /*%< entropy source */
00097         size_t          limit;  /*%< upper limit of key length */
00098         size_t          vectorlen; /*%< size of the vector below */
00099         hash_random_t   *rndvector; /*%< random vector for universal hashing */
00100 };
00101 
00102 static isc_mutex_t createlock;
00103 static isc_once_t once = ISC_ONCE_INIT;
00104 static isc_hash_t *hash = NULL;
00105 
00106 static unsigned char maptolower[] = {
00107         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
00108         0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
00109         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
00110         0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
00111         0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
00112         0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
00113         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
00114         0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
00115         0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
00116         0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
00117         0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
00118         0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
00119         0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
00120         0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
00121         0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
00122         0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
00123         0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
00124         0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
00125         0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
00126         0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
00127         0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
00128         0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
00129         0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
00130         0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
00131         0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
00132         0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
00133         0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
00134         0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
00135         0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
00136         0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
00137         0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
00138         0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
00139 };
00140 
00141 isc_result_t
00142 isc_hash_ctxcreate(isc_mem_t *mctx, isc_entropy_t *entropy,
00143                    size_t limit, isc_hash_t **hctxp)
00144 {
00145         isc_result_t result;
00146         isc_hash_t *hctx;
00147         size_t vlen;
00148         hash_random_t *rv;
00149         hash_accum_t overflow_limit;
00150 
00151         REQUIRE(mctx != NULL);
00152         REQUIRE(hctxp != NULL && *hctxp == NULL);
00153 
00154         /*
00155          * Overflow check.  Since our implementation only does a modulo
00156          * operation at the last stage of hash calculation, the accumulator
00157          * must not overflow.
00158          */
00159         overflow_limit =
00160                 1 << (((sizeof(hash_accum_t) - sizeof(hash_random_t))) * 8);
00161         if (overflow_limit < (limit + 1) * 0xff)
00162                 return (ISC_R_RANGE);
00163 
00164         hctx = isc_mem_get(mctx, sizeof(isc_hash_t));
00165         if (hctx == NULL)
00166                 return (ISC_R_NOMEMORY);
00167 
00168         vlen = sizeof(hash_random_t) * (limit + 1);
00169         rv = isc_mem_get(mctx, vlen);
00170         if (rv == NULL) {
00171                 result = ISC_R_NOMEMORY;
00172                 goto errout;
00173         }
00174 
00175         /*
00176          * We need a lock.
00177          */
00178         result = isc_mutex_init(&hctx->lock);
00179         if (result != ISC_R_SUCCESS)
00180                 goto errout;
00181 
00182         /*
00183          * From here down, no failures will/can occur.
00184          */
00185         hctx->magic = HASH_MAGIC;
00186         hctx->mctx = NULL;
00187         isc_mem_attach(mctx, &hctx->mctx);
00188         hctx->initialized = ISC_FALSE;
00189         result = isc_refcount_init(&hctx->refcnt, 1);
00190         if (result != ISC_R_SUCCESS)
00191                 goto cleanup_lock;
00192         hctx->entropy = NULL;
00193         hctx->limit = limit;
00194         hctx->vectorlen = vlen;
00195         hctx->rndvector = rv;
00196 
00197         if (entropy != NULL)
00198                 isc_entropy_attach(entropy, &hctx->entropy);
00199 
00200         *hctxp = hctx;
00201         return (ISC_R_SUCCESS);
00202 
00203  cleanup_lock:
00204         DESTROYLOCK(&hctx->lock);
00205  errout:
00206         isc_mem_put(mctx, hctx, sizeof(isc_hash_t));
00207         if (rv != NULL)
00208                 isc_mem_put(mctx, rv, vlen);
00209 
00210         return (result);
00211 }
00212 
00213 static void
00214 initialize_lock(void) {
00215         RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS);
00216 }
00217 
00218 isc_result_t
00219 isc_hash_create(isc_mem_t *mctx, isc_entropy_t *entropy, size_t limit) {
00220         isc_result_t result = ISC_R_SUCCESS;
00221 
00222         REQUIRE(mctx != NULL);
00223         INSIST(hash == NULL);
00224 
00225         RUNTIME_CHECK(isc_once_do(&once, initialize_lock) == ISC_R_SUCCESS);
00226 
00227         LOCK(&createlock);
00228 
00229         if (hash == NULL)
00230                 result = isc_hash_ctxcreate(mctx, entropy, limit, &hash);
00231 
00232         UNLOCK(&createlock);
00233 
00234         return (result);
00235 }
00236 
00237 void
00238 isc_hash_ctxinit(isc_hash_t *hctx) {
00239         LOCK(&hctx->lock);
00240 
00241         if (hctx->initialized == ISC_TRUE)
00242                 goto out;
00243 
00244         if (hctx->entropy != NULL) {
00245                 isc_result_t result;
00246 
00247                 result = isc_entropy_getdata(hctx->entropy,
00248                                              hctx->rndvector,
00249                                              (unsigned int)hctx->vectorlen,
00250                                              NULL, 0);
00251                 INSIST(result == ISC_R_SUCCESS);
00252         } else {
00253                 isc_uint32_t pr;
00254                 size_t i, copylen;
00255                 unsigned char *p;
00256 
00257                 p = (unsigned char *)hctx->rndvector;
00258                 for (i = 0; i < hctx->vectorlen; i += copylen, p += copylen) {
00259                         isc_random_get(&pr);
00260                         if (i + sizeof(pr) <= hctx->vectorlen)
00261                                 copylen = sizeof(pr);
00262                         else
00263                                 copylen = hctx->vectorlen - i;
00264 
00265                         memmove(p, &pr, copylen);
00266                 }
00267                 INSIST(p == (unsigned char *)hctx->rndvector +
00268                        hctx->vectorlen);
00269         }
00270 
00271         hctx->initialized = ISC_TRUE;
00272 
00273  out:
00274         UNLOCK(&hctx->lock);
00275 }
00276 
00277 void
00278 isc_hash_init(void) {
00279         INSIST(hash != NULL && VALID_HASH(hash));
00280 
00281         isc_hash_ctxinit(hash);
00282 }
00283 
00284 void
00285 isc_hash_ctxattach(isc_hash_t *hctx, isc_hash_t **hctxp) {
00286         REQUIRE(VALID_HASH(hctx));
00287         REQUIRE(hctxp != NULL && *hctxp == NULL);
00288 
00289         isc_refcount_increment(&hctx->refcnt, NULL);
00290         *hctxp = hctx;
00291 }
00292 
00293 static void
00294 destroy(isc_hash_t **hctxp) {
00295         isc_hash_t *hctx;
00296         isc_mem_t *mctx;
00297 
00298         REQUIRE(hctxp != NULL && *hctxp != NULL);
00299         hctx = *hctxp;
00300         *hctxp = NULL;
00301 
00302         LOCK(&hctx->lock);
00303 
00304         isc_refcount_destroy(&hctx->refcnt);
00305 
00306         mctx = hctx->mctx;
00307         if (hctx->entropy != NULL)
00308                 isc_entropy_detach(&hctx->entropy);
00309         if (hctx->rndvector != NULL)
00310                 isc_mem_put(mctx, hctx->rndvector, hctx->vectorlen);
00311 
00312         UNLOCK(&hctx->lock);
00313 
00314         DESTROYLOCK(&hctx->lock);
00315 
00316         memset(hctx, 0, sizeof(isc_hash_t));
00317         isc_mem_put(mctx, hctx, sizeof(isc_hash_t));
00318         isc_mem_detach(&mctx);
00319 }
00320 
00321 void
00322 isc_hash_ctxdetach(isc_hash_t **hctxp) {
00323         isc_hash_t *hctx;
00324         unsigned int refs;
00325 
00326         REQUIRE(hctxp != NULL && VALID_HASH(*hctxp));
00327         hctx = *hctxp;
00328 
00329         isc_refcount_decrement(&hctx->refcnt, &refs);
00330         if (refs == 0)
00331                 destroy(&hctx);
00332 
00333         *hctxp = NULL;
00334 }
00335 
00336 void
00337 isc_hash_destroy(void) {
00338         unsigned int refs;
00339 
00340         INSIST(hash != NULL && VALID_HASH(hash));
00341 
00342         isc_refcount_decrement(&hash->refcnt, &refs);
00343         INSIST(refs == 0);
00344 
00345         destroy(&hash);
00346 }
00347 
00348 static inline unsigned int
00349 hash_calc(isc_hash_t *hctx, const unsigned char *key, unsigned int keylen,
00350           isc_boolean_t case_sensitive)
00351 {
00352         hash_accum_t partial_sum = 0;
00353         hash_random_t *p = hctx->rndvector;
00354         unsigned int i = 0;
00355 
00356         /* Make it sure that the hash context is initialized. */
00357         if (hctx->initialized == ISC_FALSE)
00358                 isc_hash_ctxinit(hctx);
00359 
00360         if (case_sensitive) {
00361                 for (i = 0; i < keylen; i++)
00362                         partial_sum += key[i] * (hash_accum_t)p[i];
00363         } else {
00364                 for (i = 0; i < keylen; i++)
00365                         partial_sum += maptolower[key[i]] * (hash_accum_t)p[i];
00366         }
00367 
00368         partial_sum += p[i];
00369 
00370         return ((unsigned int)(partial_sum % PRIME32));
00371 }
00372 
00373 unsigned int
00374 isc_hash_ctxcalc(isc_hash_t *hctx, const unsigned char *key,
00375                  unsigned int keylen, isc_boolean_t case_sensitive)
00376 {
00377         REQUIRE(hctx != NULL && VALID_HASH(hctx));
00378         REQUIRE(keylen <= hctx->limit);
00379 
00380         return (hash_calc(hctx, key, keylen, case_sensitive));
00381 }
00382 
00383 unsigned int
00384 isc_hash_calc(const unsigned char *key, unsigned int keylen,
00385               isc_boolean_t case_sensitive)
00386 {
00387         INSIST(hash != NULL && VALID_HASH(hash));
00388         REQUIRE(keylen <= hash->limit);
00389 
00390         return (hash_calc(hash, key, keylen, case_sensitive));
00391 }
00392 
00393 void
00394 isc__hash_setvec(const isc_uint16_t *vec) {
00395         int i;
00396         hash_random_t *p;
00397 
00398         if (hash == NULL)
00399                 return;
00400 
00401         p = hash->rndvector;
00402         for (i = 0; i < 256; i++) {
00403                 p[i] = vec[i];
00404         }
00405 }

Generated on Tue Apr 28 17:41:04 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha