Hash 算法及其应用

 

转贴来自:http://hi.baidu.com/shankou/blog/item/2c8787d4653bbf02a08bb77b.html

Hash 算法及其应用
  
  ---------------
  什么是 Hash
  Hash 的重要特性
  Hash 函数的实现
  主要的 Hash 算法
  Hash 算法的安全问题
  Hash 算法的应用
  结 论
  ---------------
  
  
  Hash,一般翻译做“散列”,也有直接音译为"哈希"的,就是把任意长度的输入(又叫做
  预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这
  种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能
  会散列成相同的输出,而不可能从散列值来唯一的确定输入值。
  
  数学表述为:h = H(M) ,其中H( )--单向散列函数,M--任意长度明文,h--固定长度散列
  值。
  
  
  在信息安全领域中应用的Hash算法,还需要满足其他关键特性:
  
  第一当然是单向性(one-way),从预映射,能够简单迅速的得到散列值,而在计算上不可能
  构造一个预映射,使其散列结果等于某个特定的散列值,即构造相应的M=H-1(h)不可行。
  这样,散列值就能在统计上唯一的表征输入值,因此,密码学上的 Hash 又被称为"消息摘
  要(message digest)",就是要求能方便的将"消息"进行"摘要",但在"摘要"中无法得到比
  "摘要"本身更多的关于"消息"的信息。
  
  第二是抗冲突性(collision-resistant),即在统计上无法产生2个散列值相同的预映射。
  给定M,计算上无法找到M',满足H(M)=H(M') ,此谓弱抗冲突性;计算上也难以寻找一对
  任意的M和M',使满足H(M)=H(M') ,此谓强抗冲突性。要求"强抗冲突性"主要是为了防范
  所谓"生日攻击(birthday attack)",在一个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函数就是被设计为基于通过特定压缩函数的不断重复“压缩”输入的分组
  和前一次压缩处理的结果的过程,直到整个消息都被压缩完毕,最后的输出作为整个消息
  的散列值。尽管还缺乏严格的证明,但绝大多数业界的研究者都同意,如果压缩函数是安
  全的,那么以上述形式散列任意长度的消息也将是安全的。这就是所谓 Damgard/Merkle
  结构:
  
  在下图中,任意长度的消息被分拆成符合压缩函数输入要求的分组,最后一个分组可能需
  要在末尾添上特定的填充字节,这些分组将被顺序处理,除了第一个消息分组将与散列初
  始化值一起作为压缩函数的输入外,当前分组将和前一个分组的压缩函数输出一起被作为
  这一次压缩的输入,而其输出又将被作为下一个分组压缩函数输入的一部分,直到最后一
  个压缩函数的输出,将被作为整个消息散列的结果。
  
  
  MD5 和 SHA1 可以说是目前应用最广泛的Hash算法,而它们都是以 MD4 为基础设计的。
  
  
  1) MD4
  MD4(RFC 1320)是 MIT 的 Ronald L. Rivest 在 1990 年设计的,MD 是 Message Digest
  的缩写。它适用在32位字长的处理器上用高速软件实现--它是基于 32 位操作数的位操作
  来实现的。它的安全性不像RSA那样基于数学假设,尽管 Den Boer、Bosselaers 和 Dobb
  ertin 很快就用分析和差分成功的攻击了它3轮变换中的 2 轮,证明了它并不像期望的那
  样安全,但它的整个算法并没有真正被破解过,Rivest 也很快进行了改进。
  
  下面是一些MD4散列结果的例子:
  
  MD4 ("") = 31d6cfe0d16ae931b73c59d7e0c089c0
  MD4 ("a") = bde52cb31de33e46245e05fbdbd6fb24
  MD4 ("abc") = a448017aaf21d8525fc10ae87aa6729d
  MD4 ("message digest") = d9130a8164549fe818874806e1c7014b
  MD4 ("abcdefghijklmnopqrstuvwxyz") = d79e1c308aa5bbcdeea8ed63df412da9
  MD4 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = 043f8
  582f241db351ce627e153e7f0e4
  MD4 ("123456789012345678901234567890123456789012345678901234567890123456789012
  34567890") = e33b4ddc9c38f2199c3e7b164fcc0536
  
  
  2) MD5
  MD5(RFC 1321)是 Rivest 于1991年对MD4的改进版本。它对输入仍以512位分组,其输出是
  4个32位字的级联,与 MD4 相同。它较MD4所做的改进是:
  
  1) 加入了第四轮
  2) 每一步都有唯一的加法常数;
  3) 第二轮中的G函数从((X ∧ Y) ∨ (X ∧ Z) ∨ (Y ∧ Z)) 变为 ((X ∧ Z) ∨ (Y ∧
  ~Z))以减小其对称性;
  4) 每一步都加入了前一步的结果,以加快"雪崩效应";
  5) 改变了第2轮和第3轮中访问输入子分组的顺序,减小了形式的相似程度;
  6) 近似优化了每轮的循环左移位移量,以期加快"雪崩效应",各轮的循环左移都不同。
  
  尽管MD5比MD4来得复杂,并且速度较之要慢一点,但更安全,在抗分析和抗差分方面表现
  更好。
  
  消息首先被拆成若干个512位的分组,其中最后512位一个分组是“消息尾+填充字节(100…
  0)+64 位消息长度”,以确保对于不同长度的消息,该分组不相同。64位消息长度的限制
  导致了MD5安全的输入长度必须小于264bit,因为大于64位的长度信息将被忽略。而4个32
  位寄存器字初始化为A=0x01234567,B=0x89abcdef,C=0xfedcba98,D=0x76543210,它们
  将始终参与运算并形成最终的散列结果。
  
  接着各个512位消息分组以16个32位字的形式进入算法的主循环,512位消息分组的个数据
  决定了循环的次数。主循环有4轮,每轮分别用到了非线性函数
  
  F(X, Y, Z) = (X ∧ Y) ∨ (~X ∧ Z)
  G(X, Y, Z) = (X ∧ Z) ∨ (Y ∧ ~Z)
  H(X, Y, Z) =X ⊕ Y ⊕ Z
  I(X, Y, Z) = X ⊕ (Y ∨ ~Z)
  这4轮变换是对进入主循环的512位消息分组的16个32位字分别进行如下操作:将A、B、C、
  D的副本a、b、c、d中的3个经F、G、H、I运算后的结果与第4个相加,再加上32位字和一个
  32位字的加法常数,并将所得之值循环左移若干位,最后将所得结果加上a、b、c、d之一
  ,并回送至ABCD,由此完成一次循环。
  
  所用的加法常数由这样一张表T[i]来定义,其中i为1…64,T[i]是i的正弦绝对值之42949
  67296次方的整数部分,这样做是为了通过正弦函数和幂函数来进一步消除变换中的线性性
  。
  
  当所有512位分组都运算完毕后,ABCD的级联将被输出为MD5散列的结果。下面是一些MD5散
  列结果的例子:
  
  MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
  MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
  MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
  MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
  MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
  MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = d174a
  b98d277d9f5a5611c2c9f419d9f
  MD5 ("123456789012345678901234567890123456789012345678901234567890123456789012
  34567890") = 57edf4a22be3c955ac49da2e2107b67a
  参考相应RFC文档可以得到MD4、MD5算法的详细描述和算法的C源代码。http://www.douban.com/group/topic/1391942/

--------------------------------------

Hash算法

hash算法的意义在于提供了一种快速存取数据的方法,它用一种算法建立键值与真实值之间的对应关系,(每一个真实值只能有一个键值,但是一个键值可以对应多个真实值),这样可以快速在数组等   
   里面存取数据.   
   例如:   
   //HashTable.h   
    
   template    <class    T>   
   class    HashTable   
   {   
   public    :   
           HashTable(    int    count    )    ;   
           void    put(    T*    t    ,int    key    )    ;   
           T*    get(    int    key    )    ;   
   private    :   
             T**    tArray    ;   
   }   
    
    
   //HashTable.cpp   
   template    <Class    T>   
   HashTable::HashTable(    int    count    )   
   {   
         tArray    =    new    T*[count]    ;   
   }         
    
   template    <Class    T>   
   void    HashTable::put(    T*    t    ,    int    key    )   
   {   
         this->tArray[    key    ]    =    t    ;   
   }   
    
   template    <Class    T>   
   T*    HashTable::get(    int    key    )   
   {   
         return    this->tArray[    key    ]    ;   
   }   
    
   这样,我们只要知道key值,就可以快速存取T类型的数据,而不用像在链表等数据结构中查找一样,   
   要找来找去的.至于key值,一般都是用某种算法(所谓的Hash算法)算出来的.例如:字符串的Hash算法,    char*    value    =    "hello";    int    key    =      (((((((27*    (int)'h'+27)*    (int)'e')    +    27)     
   *    (int)'l')    +    27)    *    (int)'l'    +27)    *    27    )    +    (int)'o'    ;

你可能感兴趣的:(数据结构,c,算法,Class,64bit,compression)