zoukankan      html  css  js  c++  java
  • hash算法和常见的hash函数 [转]

       Hash,就是把任意长度的输入,通过散列算法,变换成固定长度的输出,该输出就是散列值。
    这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能
    会散列成相同的输出,而不可能从散列值来唯一的确定输入值。数学表述为:h = H(M) ,
    其中H( )--单向散列函数,M--任意长度明文,h--固定长度散列值。   
     在信息安全领域中应用的Hash算法,还需要满足其他关键特性:   
       第一当然是单向性(one-way),从预映射,能够简单迅速的得到散列值,而在计算上不可能构造一个预映
    射,使其散列结果等于某个特定的散列值,即构造相应的M=H-1(h)不可行。这样,散列值就能在统计上唯一的
    表征输入值,因此,密码学上的 Hash 又被称为"消息摘要(messagedigest)",就是要求能方便的将"消息"进
    行"摘要",但在"摘要"中无法得到比"摘要"本身更多的关于"消息"的信息。
          第二是抗冲突性(collision-resistant),即在统计上无法产生2个散列值相同的预映射。给定M,计算上
    无法找到M',满足H(M)=H(M') ,此谓弱抗冲突性;计算上也难以寻找一对任意的M和M',使满足H(M)=H(M') ,此谓强抗冲突性。要求"强抗冲突性"主要是为了防范 所谓"生日攻击(birthdayattack)",在一个10人的团
    体中,你能找到和你生日相同的人的概率是2.4%,而在同一团体中,有2人生日相同的概率是11.7%。类似的,
    当预映射的空间很大的情况下,算法必须有足够的强度来保证不能轻易找到"相同生日"的人。   

       第三是映射分布均匀性和差分分布均匀性,散列结果中,为 0 的 bit 和为 1 的 bit ,其总数应该大致
    相等;输入中一个 bit的变化,散列结果中将有一半以上的 bit 改变,这又叫做"雪崩效应(avalanche effect)";
    要实现使散列结果中出现 1bit的变化,则输入中至少有一半以上的 bit 必须发生变化。其实质是必须使输入
    中每一个 bit 的信息, 尽量均匀的反映到输出的每一个 bit上去;输出中的每一个 bit,都是输入中尽可能
    多 bit 的信息一起作用的结果。Damgard 和 Merkle定义了所谓“压缩函数(compression function)”,就是
    将一个固定长度输入,变换成较短的固定长度的输出,这对密码学实践上Hash函数的设计产生了很大的影响。
    Hash函数就是被设计为基于通过特定压缩函数的不断重复“压缩”输入的分组和前一次压缩处理的结果的过程,
    直到整个消息都被压缩完毕,最后的输出作为整个消息的散列值。尽管还缺乏严格的证明,但绝大多数业界的
    研究者都同意,如果压缩函数是安全的,那么以上述形式散列任意长度的消息也将是安全的。任意长度的消息
    被分拆成符合压缩函数输入要求的分组,最后一个分组可能需要在末尾添上特定的填充字节,这些分组将被顺
    序处理,除了第一个消息分组将与散列初始化值一起作为压缩函数的输入外,当前分组将和前一个分组的压缩
    函数输出一起被作为这一次压缩的输入,而其输出又将被作为下一个分组压缩函数输入的一部分,直到最后一
    个压缩函数的输出,将被作为整个消息散列的结果。MD5 和 SHA1 可以说是目前应用最广泛的Hash算法,而它
    们都是以MD4 为基础设计的。
    设计高效算法往往需要使用Hash链表,常数级的查找速度是任何别的算法无法比拟的,Hash链表的构造和冲突
    的不同实现方法对效率当然有一定的影响,然而Hash函数是Hash链表最核心的部分,下面是几款经典软件中使
    用到的字符串Hash函数实现,通过阅读这些代码,我们可以在Hash算法的执行效率、离散性、空间利用率等方
    面有比较深刻的了解。
    下面分别介绍几个经典软件中出现的字符串Hash函数。

    ●PHP中出现的字符串Hash函数
    static unsigned long hashpjw(char *arKey, unsigned int nKeyLength)
    {
    unsigned long h = 0, g;
    char *arEnd=arKey+nKeyLength;

    while (arKey < arEnd) {
    h = (h << 4) + *arKey++;
    if ((g = (h & 0xF0000000))) {
    h = h ^ (g >> 24);
    h = h ^ g;
    }
    }

    return h;
    }


    OpenSSL中出现的字符串Hash函数

    unsigned long lh_strhash(char *str)
    {
    int i,l;
    unsigned long ret=0;
    unsigned short *s;

    if (str == NULL) return(0);
    l=(strlen(str)+1)/2;
    s=(unsigned short *)str;

    for (i=0; i<l; i++)
    ret^=(s[i]<<(i&0×0f));

    return(ret);
    }



    /* The following hash seems to work very well on normal text strings
    * no collisions on /usr/dict/words and it distributes on %2^n quite
    * well, not as good as MD5, but still good.
    */
    unsigned long lh_strhash(const char *c)
    {
    unsigned long ret=0;
    long n;
    unsigned long v;
    int r;

    if ((c == NULL) || (*c == ‘′))
    return(ret);

    /*
    unsigned char b[16];
    MD5(c,strlen(c),b);
    return(b[0]|(b[1]<<8)|(b[2]<<16)|(b[3]<<24));
    */

    n=0×100;
    while (*c)
    {
    v=n|(*c);
    n+=0×100;
    r= (int)((v>>2)^v)&0×0f;
    ret=(ret(32-r));
    ret&=0xFFFFFFFFL;
    ret^=v*v;
    c++;
    }

    return((ret>>16)^ret);
    }
    
    

    MySql中出现的字符串Hash函数

     
    #ifndef NEW_HASH_FUNCTION 

    /* Calc hashvalue for a key (区分大小写)*/
    static uint calc_hashnr(const byte *key,uint length)
    {
    register uint nr=1, nr2=4;

    while (length––)
    {
    nr^= (((nr & 63)+nr2)*((uint) (uchar) *key++))+ (nr << 8);
    nr2+=3;
    }

    return((uint) nr);
    }

    /* Calc hashvalue for a key, case indepenently (不区分大小写) */
    static uint calc_hashnr_caseup(const byte *key,uint length)
    {
    register uint nr=1, nr2=4;

    while (length–)
    {
    nr^= (((nr & 63)+nr2)*((uint) (uchar) toupper(*key++)))+ (nr << 8);
    nr2+=3;
    }

    return((uint) nr);
    }

    #else
    /*
    * Fowler/Noll/Vo hash
    *
    * The basis of the hash algorithm was taken from an idea sent by email to the
    * IEEE Posix P1003.2 mailing list from Phong Vo (kpv@research.att.com) and
    * Glenn Fowler (gsf@research.att.com). Landon Curt Noll (chongo@toad.com)
    * later improved on their algorithm.
    *
    * The magic is in the interesting relationship between the special prime
    * 16777619 (2^24 + 403) and 2^32 and 2^8.
    *
    * This hash produces the fewest collisions of any function that we’ve seen so
    * far, and works well on both numbers and strings.
    */

    //(区分大小写)
    uint calc_hashnr(const byte *key, uint len)
    {
    const byte *end=key+len;
    uint hash;

    for (hash = 0; key < end; key++)
    {
    hash *= 16777619;
    hash ^= (uint) *(uchar*) key;
    }

    return (hash);
    }

    //(不区分大小写)
    uint calc_hashnr_caseup(const byte *key, uint len)
    {
    const byte *end=key+len;
    uint hash;

    for (hash = 0; key < end; key++)
    {
    hash *= 16777619;
    hash ^= (uint) (uchar) toupper(*key);
    }

    return (hash);
    }
    #endif

    另一个经典字符串Hash函数

     
    unsigned int hash(char *str)
    {
    register unsigned int h;
    register unsigned char *p;

    for(h=0, p = (unsigned char *)str; *p ; p++)
    h = 31 * h + *p;

    return h;
    }

  • 相关阅读:
    常见 PL.SQL 数据库操作
    PL/SQL常见设置--Kevin的专栏
    pl/sql编程
    添加List集合覆盖问题
    程序猿感情生活的那些事
    表达式树-理解与进阶
    白话神经网络
    EF Core 数据验证
    c#8内插逐字字符串增强功能
    我的新博客
  • 原文地址:https://www.cnblogs.com/jluzhsai/p/4546054.html
Copyright © 2011-2022 走看看