参考 Link

另外,这篇文章也提到了利用Hash碰撞而产生DOS攻击的案例: http://www.cnblogs.com/charlesblc/p/5990475.html

DJB的算法实现核心是通过给哈希值(Key)乘以33(即左移5位再加上哈希值)计算哈希值

Zend HashTable的哈希算法异常简单:hashKey = key & nTableMask;
概况来说只要保证后16位均为0,则与掩码位于后得到的哈希值全部碰撞在位置0。

一 加法Hash

所谓的加法Hash就是把输入元素一个一个的加起来构成最后的结果。
标准的加法Hash的构造如下:

static int additiveHash(String key, int prime)
{

int hash, i;
   for (hash = key.length(), i = 0; i < key.length(); i++)
   hash += key.charAt(i);
  return (hash % prime);
}
这里的prime是任意的质数,看得出,结果的值域为[0,prime-1]。

二 位运算Hash

这类型Hash函数通过利用各种位运算(常见的是移位和异或)来充分的混合输入元素。比如,标准的旋转Hash的构造如下:

static int rotatingHash(String key, int prime)

{

    int hash, i;

    for (hash=key.length(), i=0; i<key.length(); ++i)

        hash = (hash<<4)^(hash>>28)^key.charAt(i);

    return (hash % prime);

}

先移位,然后再进行各种位运算是这种类型Hash函数的主要特点。比如,以上的那段计算hash的代码还可以有如下几种变形: 

1. hash = (hash<<5)^(hash>>27)^key.charAt(i);

2. hash += key.charAt(i);

hash += (hash << 10);

hash ^= (hash >> 6);

3.

if((i&1) == 0)

{

hash ^= (hash<<7) ^ key.charAt(i) ^ (hash>>3);

}

else

{

hash ^= ~((hash<<11) ^ key.charAt(i) ^ (hash >>5));

}

4. hash += (hash<<5) + key.charAt(i);

5. hash = key.charAt(i) + (hash<<6) + (hash>>16) – hash;

6. hash ^= ((hash<<5) + key.charAt(i) + (hash>>2));

三 乘法Hash

这种类型的Hash函数利用了乘法的不相关性(乘法的这种性质,最有名的莫过于平方取头尾的随机数生成算法,虽然这种算法效果并不好)。比如,

static int bernstein(String key)

{

    int hash = 0;

    int i;

    for (i=0; i<key.length(); ++i) hash = 33*hash + key.charAt(i);

    return hash;

}

jdk5.0里面的String类的hashCode()方法也使用乘法Hash。不过,它使用的乘数是31。推荐的乘数还有:131, 1313, 13131, 131313等等。

使用这种方式的著名Hash函数还有:

// 32位FNV算法

int M_SHIFT = 0;

public int FNVHash(byte[] data)

{

    int hash = (int)2166136261L;

    for(byte b : data)

        hash = (hash * 16777619) ^ b;

    if (M_SHIFT == 0)

        return hash;

    return (hash ^ (hash >> M_SHIFT)) & M_MASK;

}

以及改进的FNV算法:

public static int FNVHash1(String data)

{

    final int p = 16777619;

    int hash = (int)2166136261L;

    for(int i=0;i<data.length();i++)

        hash = (hash ^ data.charAt(i)) * p;

    hash += hash << 13;

    hash ^= hash >> 7;

    hash += hash << 3;

    hash ^= hash >> 17;

    hash += hash << 5;

    return hash;

}

除了乘以一个固定的数,常见的还有乘以一个不断改变的数,比如:

static int RSHash(String str)

{

    int b = 378551;

    int a = 63689;

    int hash = 0;



    for(int i = 0; i < str.length(); i++)

    {

        hash = hash * a + str.charAt(i);

        a = a * b;

    }

    return (hash & 0x7FFFFFFF);

}

虽然Adler32算法的应用没有CRC32广泛,不过,它可能是乘法Hash里面最有名的一个了。关于它的介绍,大家可以去看RFC 1950规范。

四 除法Hash

除 法和乘法一样,同样具有表面上看起来的不相关性。不过,因为除法太慢,这种方式几乎找不到真正的应用。需要注意的是,

我们在前面看到的hash的结果除以 一个prime的目的只是为了保证结果的范围。如果你不需要它限制一个范围的话,

可以使用如下的代码替代”hash%prime”: hash = hash ^ (hash>>10) ^ (hash>>20)。

五 查表Hash

查表Hash最有名的例子莫过于CRC系列算法。虽然CRC系列算法本身并不是查表,但是,查表是它的一种最快的实现方式。下面是CRC32的实现:

static int crctab[256] = {

0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,

0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,

0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,

0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,

0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,

0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,

0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,

0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,

0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,

0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,

0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,

0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,

0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,

0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,

0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,

0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,

0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,

0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,

0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,

0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,

0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,

0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,

0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,

0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,

0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,

0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,

0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,

0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,

0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,

0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,

0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,

0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,

0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,

0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,

0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,

0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,

0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,

0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,

0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,

0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,

0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,

0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,

0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d

};



int crc32(String key, int hash)

{

    int i;

    for (hash=key.length(), i=0; i<key.length(); ++i)

        hash = (hash >> 8) ^ crctab[(hash & 0xff) ^ k.charAt(i)];

    return hash;

}

查表Hash中有名的例子有:Universal Hashing和Zobrist Hashing。他们的表格都是随机生成的。


六 混合Hash

混合Hash算法利用了以上各种方式。各种常见的Hash算法,比如MD5、Tiger都属于这个范围。它们一般很少在面向查找的Hash函数里面使用。

Tiger号称是最快的哈希算法,对64位机器做了优化。


七 对Hash算法的评价

http://www.burtleburtle.net/bob/hash/doobs.html 这个页面提供了对几种流行Hash算法的评价。我们对Hash函数的建议如下:

1. 字符串的Hash。最简单可以使用基本的乘法Hash,当乘数为33时,对于英文单词有很好的散列效果(小于6个的小写形式可以保证没有冲突)。

复杂一点可以使用FNV算法(及其改进形式),它对于比较长的字符串,在速度和效果上都不错。

2. 长数组的Hash。可以使用http://burtleburtle.net/bob/c/lookup3.c这种算法,它一次运算多个字节,速度还算不错。


八 后记

本 文简略的介绍了一番实际应用中的用于查找的Hash算法。Hash算法除了应用于这个方面以外,另外一个著名的应用是巨型字符串匹配(这时的Hash算法 叫做:rolling hash,因为它必须可以滚动的计算)。设计一个真正好的Hash算法并不是一件容易的事情。做为应用来说,选择一个适合的算法是最重要的。

碰撞处理,一种是open hashing,也称为拉链法;另一种就是closed hashing,也称开地址法。

MD5

参考这篇文章:http://blog.csdn.net/forgotaboutgirl/article/details/7258109

MD5(单向散列算法)的全称是Message-Digest Algorithm 5(信息-摘要算法),经MD2、MD3和MD4发展而来。MD5算法的使用不需要支付任何版权费用。

    MD5功能:
    输入任意长度的信息,经过处理,输出为128位的信息(数字指纹);
    不同的输入得到的不同的结果(唯一性);
    根据128位的输出结果不可能反推出输入的信息(不可逆); 

    MD5属不属于加密算法:
    认为不属于的人是因为他们觉得不能从密文(散列值)反过来得到原文,即没有解密算法,所以这部分人认为MD5只能属于算法,不能称为加密算法;
    认为属于的人是因为他们觉得经过MD5处理后看不到原文,即已经将原文加密,所以认为MD5属于加密算法;我个人支持后者。

防止抵赖(数字签名):
    这需要一个第三方认证机构。例如A写了一个文件,认证机构对此文件用MD5算法产生摘要信息并做好记录。若以后A说这文件不是他写的,权威机构只需对此文件重新产生摘要信息,然后跟记录在册的摘要信息进行比对,相同的话,就证明是A写的了。这就是所谓的“数字签名”。

MD5算法过程:
    对MD5算法简要的叙述可以为:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。

     第一步、填充:如果输入信息的长度(bit)对512求余的结果不等于448,就需要填充使得对512求余的结果等于448。填充的方法是填充一个1和n个0。填充完后,信息的长度就为N*512+448(bit);

     第二步、记录信息长度:用64位来存储填充前信息长度。这64位加在第一步结果的后面,这样信息长度就变为N*512+448+64=(N+1)*512位。

     第三步、装入标准的幻数(四个整数):标准的幻数(物理顺序)是(A=(01234567)16,B=(89ABCDEF)16,C=(FEDCBA98)16,D=(76543210)16)。如果在程序中定义应该是(A=0X67452301L,B=0XEFCDAB89L,C=0X98BADCFEL,D=0X10325476L)。有点晕哈,其实想一想就明白了。

     第四步、四轮循环运算:循环的次数是分组的个数(N+1) 

     1)将每一512字节细分成16个小组,每个小组64位(8个字节)
     
     2)先认识四个线性函数(&是与,|是或,~是非,^是异或)

1)将每一512字节细分成16个小组,每个小组64位(8个字节)

     2)先认识四个线性函数(&是与,|是或,~是非,^是异或)
  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)=Y^(X|(~Z))

    3)设Mj表示消息的第j个子分组(从0到15),<<<s表示循环左移s位,则四种操作为:
  FF(a,b,c,d,Mj,s,ti)表示a=b+((a+F(b,c,d)+Mj+ti)<<<s)
  GG(a,b,c,d,Mj,s,ti)表示a=b+((a+G(b,c,d)+Mj+ti)<<<s)
  HH(a,b,c,d,Mj,s,ti)表示a=b+((a+H(b,c,d)+Mj+ti)<<<s)
  II(a,b,c,d,Mj,s,ti)表示a=b+((a+I(b,c,d)+Mj+ti)<<<s)

    4)四轮运算
第一轮
a=FF(a,b,c,d,M0,7,0xd76aa478)
b=FF(d,a,b,c,M1,12,0xe8c7b756)
c=FF(c,d,a,b,M2,17,0x242070db)
d=FF(b,c,d,a,M3,22,0xc1bdceee)
a=FF(a,b,c,d,M4,7,0xf57c0faf)
b=FF(d,a,b,c,M5,12,0x4787c62a)
c=FF(c,d,a,b,M6,17,0xa8304613)
d=FF(b,c,d,a,M7,22,0xfd469501)
a=FF(a,b,c,d,M8,7,0x698098d8)
b=FF(d,a,b,c,M9,12,0x8b44f7af)
c=FF(c,d,a,b,M10,17,0xffff5bb1)
d=FF(b,c,d,a,M11,22,0x895cd7be)
a=FF(a,b,c,d,M12,7,0x6b901122)
b=FF(d,a,b,c,M13,12,0xfd987193)
c=FF(c,d,a,b,M14,17,0xa679438e)
d=FF(b,c,d,a,M15,22,0x49b40821)

第二轮
a=GG(a,b,c,d,M1,5,0xf61e2562)
b=GG(d,a,b,c,M6,9,0xc040b340)
c=GG(c,d,a,b,M11,14,0x265e5a51)
d=GG(b,c,d,a,M0,20,0xe9b6c7aa)
a=GG(a,b,c,d,M5,5,0xd62f105d)
b=GG(d,a,b,c,M10,9,0x02441453)
c=GG(c,d,a,b,M15,14,0xd8a1e681)
d=GG(b,c,d,a,M4,20,0xe7d3fbc8)
a=GG(a,b,c,d,M9,5,0x21e1cde6)
b=GG(d,a,b,c,M14,9,0xc33707d6)
c=GG(c,d,a,b,M3,14,0xf4d50d87)
d=GG(b,c,d,a,M8,20,0x455a14ed)
a=GG(a,b,c,d,M13,5,0xa9e3e905)
b=GG(d,a,b,c,M2,9,0xfcefa3f8)
c=GG(c,d,a,b,M7,14,0x676f02d9)
d=GG(b,c,d,a,M12,20,0x8d2a4c8a)

第三轮
a=HH(a,b,c,d,M5,4,0xfffa3942)
b=HH(d,a,b,c,M8,11,0x8771f681)
c=HH(c,d,a,b,M11,16,0x6d9d6122)
d=HH(b,c,d,a,M14,23,0xfde5380c)
a=HH(a,b,c,d,M1,4,0xa4beea44)
b=HH(d,a,b,c,M4,11,0x4bdecfa9)
c=HH(c,d,a,b,M7,16,0xf6bb4b60)
d=HH(b,c,d,a,M10,23,0xbebfbc70)
a=HH(a,b,c,d,M13,4,0x289b7ec6)
b=HH(d,a,b,c,M0,11,0xeaa127fa)
c=HH(c,d,a,b,M3,16,0xd4ef3085)
d=HH(b,c,d,a,M6,23,0x04881d05)
a=HH(a,b,c,d,M9,4,0xd9d4d039)
b=HH(d,a,b,c,M12,11,0xe6db99e5)
c=HH(c,d,a,b,M15,16,0x1fa27cf8)
d=HH(b,c,d,a,M2,23,0xc4ac5665)

第四轮
a=II(a,b,c,d,M0,6,0xf4292244)
b=II(d,a,b,c,M7,10,0x432aff97)
c=II(c,d,a,b,M14,15,0xab9423a7)
d=II(b,c,d,a,M5,21,0xfc93a039)
a=II(a,b,c,d,M12,6,0x655b59c3)
b=II(d,a,b,c,M3,10,0x8f0ccc92)
c=II(c,d,a,b,M10,15,0xffeff47d)
d=II(b,c,d,a,M1,21,0x85845dd1)
a=II(a,b,c,d,M8,6,0x6fa87e4f)
b=II(d,a,b,c,M15,10,0xfe2ce6e0)
c=II(c,d,a,b,M6,15,0xa3014314)
d=II(b,c,d,a,M13,21,0x4e0811a1)
a=II(a,b,c,d,M4,6,0xf7537e82)
b=II(d,a,b,c,M11,10,0xbd3af235)
c=II(c,d,a,b,M2,15,0x2ad7d2bb)
d=II(b,c,d,a,M9,21,0xeb86d391)

  5)每轮循环后,将A,B,C,D分别加上a,b,c,d,然后进入下一循环。

最后,A,B,C,D拼接起来,组成128位。

MD5安全性:
    普遍认为MD5是很安全,因为暴力解破的时间是一般人无法接受的。实际上如果把用户的密码MD5处理后再存储到数据库,其实是很不安全的。

因为用户的密码是比较短的,而且很多用户的密码都使用生日,手机号码,身份证号码,电话号码等等。或者使用常用的一些吉利的数字,或者某个英文单词。如果我把常用的密码先MD5处理,把数据存储起来,然后再跟你的MD5结果匹配,这时我就有可能得到明文。比如某个MD5解破网站http://www.cmd5.com/default.aspx,我把其网站下的公告复制如下

md5解破、动网论坛密码解破等不再需要用穷举法,本站共有md5记录235亿条,还在不断增长中,已包含10位及10位以下数字、7位字母、部分7位字母+数字,全部6位及以下字母加数字等组合,并针对国内用户做了大量优化,例如已经包含所有手机号码、全国部分大中城市固定电话号码、百家姓、常用拼音等大量组合,另加入了某大型网站真实会员密码数据10万条。本站数据量大,查询速度快,同时支持16位及32位密码查询。通过对10万会员的真实动网论坛样本数据的测试,本站对于动网论坛密码的命中率达到83%。
  本站4T的硬盘已经上线,正在生成数据,预计需要2个月左右时间,到时候本站能查询到12位数字和9位字母。


有可能,只需要将上面我写的MD5的标准幻数A,B,C,D的值修改一下,修改后也不是MD5算法了,因为不能保证唯一性。这样就算别人得到32位的值,他如果不知道幻数的值是无法还原明文的。就算得到了幻数,也是很难解破的。

AVA实现MD5
    在java中实现MD5是很简单的,在包java.security有个类MessageDigest。官方文档如下

MessageDigest 类为应用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。信息摘要是安全的单向哈希函数,它接收任意大小的数据,输出固定长度的哈希值。

    MessageDigest 对象开始被初始化。该对象通过使用 update 方法处理数据。任何时候都可以调用 reset 方法重置摘要。
一旦所有需要更新的数据都已经被更新了,应该调用 digest 方法之一完成哈希计算。

    对于给定数量的更新数据,digest 方法只能被调用一次。digest 被调用后,MessageDigest 对象被重新设置成其初始状态。


import java.security.MessageDigest;

public class MyMD5 {

    static char[] hex = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};

    public static void main(String[] args) {
        try{
            MessageDigest md5 = MessageDigest.getInstance("MD5");//申明使用MD5算法
            md5.update("a".getBytes());//
            System.out.println("md5(a)="+byte2str(md5.digest()));
            md5.update("a".getBytes());
            md5.update("bc".getBytes());
            System.out.println("md5(abc)="+byte2str(md5.digest()));
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 将字节数组转换成十六进制字符串
     * @param bytes
     * @return
     */
    private static String byte2str(byte []bytes){
        int len = bytes.length;
        StringBuffer result = new StringBuffer();
        for (int i = 0; i < len; i++) {
            byte byte0 = bytes[i];
            result.append(hex[byte0 >>> 4 & 0xf]);   // 见下面解释。
            result.append(hex[byte0 & 0xf]);
        }
        return result.toString();
    }
}

其中,>>> 是无符号右移,忽略符号位,空位都以0补齐.
上面两句位移的解释:md5是128位的。一个byte是8个字节。所以一共是16个byte。而md5结果一般是以32个ascii字符出现的。所以每个byte会表示成2个字符。
这就是上面每个byte会处理两次,分别进行hex的原因。

"ABC" MD5(902fbdd2b1df0c4f70b4a5d23525e932)和"ABC "(多了一空格)MD5(12c774468f981a9487c30773d8093561)差别非常大,而且之间没有任何关系,也就是说产生的MD5 码是不可预测的。 

一般是32个ascii字符。

SHA1 是 160bit的。

CRC

计算CRC的过程,就是用一个特殊的“除法”,来得到余数,这个余数就是CRC。  它不是真正的算术上的除法!过程和算术除法过程一样,只是加减运算变成了XOR(异或)运算。

关于CRC校验:(16位二进制数),CRC码由发送设备计算,放置于所发送信息帧的尾部。接收信息的设备重新计算所接收信息(除RCR部分)的CRC,比较计算得到的
CRC是否与接收到的CRC相符,如果两者不相符,则认为数据传输出错,如果相符说明数据传输正确。

(1)预1个16位的寄存器为0xFFFF,称此寄存器为CRC寄存器
(2)把分i一个8位二进制数据(即通信信息帧的第一个字节)与16位的CRC寄存器的低8位相异或,把结果存放于CRC寄存器
(3)把CRC寄存器的内容右移一位,用0填补最高位,并检查右移后的移出位。
(4)如果移出位为0,重复(3),如果移出位为1,CRC寄存器与0xA001进行异或
(5)重复(3)(4),直到右移8次,这样整个8位数据就全部进行了处理
(6)重复(2)到(5),进行通信信息帧下一个字节的处理
(7)将该通信信息帧所有字节按上述步骤计算完成后,得到的16位CRC寄存器的高、低位已经交换
(8)最后得到的CRC寄存器内容即为CRC码

哈希或加密,分类有:

信息摘要 对称加密 非对称加密

信息摘要,常用方法有:MD5, SHA-1

对称密钥(私钥加密)

DES(数据加密标准)

AES(高级加密标准)取代 DES 成为美国标准

非对称密钥(公共密钥)

RSA:这个算法是最流行的公钥密码算法,使用长度可以变化的密钥。

用私钥加密的东西只有对应的公钥才能进行解密,这种算法经常被应用在数字签名上。其实在现实中你可以将公钥技术和私钥技术结合起来完成信息保密,因为公钥的计算速度相当慢,比私钥慢大约100-1000倍。

关于 公钥、私钥、数字签名证书,会单独再开一篇文章:http://www.cnblogs.com/charlesblc/p/6130433.html

SSL/TLS等信息也可以看上面这篇文章,里面也有包含。

海明码

参考这篇文章:http://blog.csdn.net/lycb_gz/article/details/35976723

(1)将有效信息按某种规律分成若干组,每组安排一个校验位通过异或运算进行校验,得出具体的校验码

(2)在接收端同样通过异或运算看各组校验结果是否正确,并观察出错的校校组,或者多个出错的校验组的共同校验位,得出具体的出错比特位

(3)对错误位取反来将其纠正

海明码只能检查一位出错。

04-28 15:54