精华内容
下载资源
问答
  • Hash算法

    2019-07-23 06:21:37
    Hash算法是什么? 是将将任意长度二进制串映射为固低昂长度的二进制值串,二通过原始数据映射之后得到的二进制值串就是hash值,套想设计一个优秀的hash算法,并不容易,我有以下总结 a:从hash值不能反向推导出数据...

    Hash算法是什么?

    是将将任意长度二进制串映射为固低昂长度的二进制值串,二通过原始数据映射之后得到的二进制值串就是hash值,套想设计一个优秀的hash算法,并不容易,我有以下总结

    a:从hash值不能反向推导出数据(所以hash算法也被叫做单向hash算法)

    b:对输入的数据非常敏感,只要稍微修改了一个bit,得到的hash值完全不同

    c:散列冲突非常小,对于不同的原始数据,得到的hash值相同的概率很小

    d:hash算法的执行效率要高效,对于较长的串也能在可接受的范围内得到hash值

    列:我们现在通过md5加密分别看看"我们今天学习hash算法"和"jiajia“经过md5加密的hash值

    解释:从途中可以看出,,经过md5进行hash算法得到的hash值虽然长度相同,但是值完全不同,我们在看下一个列子

    我们分别通过md5对"我今天讲hash算法!"和"我今天讲算法"分别求得hash值如图所示.

    解释:我们可以看到,虽然只有一个符号的差别,但是求得的hash值完全不同,因此,hash算法必须要求对被hash算法的字符串要非常敏感. 而且我们不能通过hash值反向推导出原有的字符串.

    2>hash算法有很多种应用,常见的有安全加密,唯一标识,数据校验,散列函数,复杂均衡,分布式存储,

    应用1:安全加密

    我们常用到对数据进行数据加密的hash算法有md5加密,sha加密, 对于数据加密有2条中的原则,
    a:对于给定的hash值我们不能反向推导出原始数据
    b:应做到解决hash冲突
    ,
    对于hash冲突是无法完全做到hash冲突的,为什么这么说呢?比如说我们有10个苹果,分到9个人的手里面,必定就会有一个人拿2个苹果,可以这样说,hash值是固定的128位2进制串,他表示的数据是有限的,最多能表示2128个数字,如果我们对2128+1个数字进行求hash值,必定有2个值是相同的,一般情况下,hash值越长,散列冲突的概率越小.

    应用2:数据校验:我们曾经都在网站上下载过电影吧,我们有时候下载的电影是不能够完全播放的,可能下载的电影已经被其他人破坏过,我们如何来保证下载的电影是完全的呢,完整的呢,我们对网站上的电影进行一个hash算法得到hash值,再对我们已经下载下来的电影进行一个hash算法得到hash值,如果2者的hash值完全相同,则数据完整,否则该电影已经被认为的破坏了.

    应用3:散列函数

    相比hsah算法,散列函数的要求是很低的,因为他可以通过链表法解决hash冲突,毕竟他仅仅只是为了存储数据.而hash算法必须保证不同数值的经过hash算法得到的hash值是不同的,我们更关注的是散列函数经过Hash是否能够平均的分布到不同的佣中,避免退化成单链表.

    展开全文
  • hash算法

    2013-09-17 17:25:50
    * Hash算法大全 * 推荐使用FNV1算法 * * @algorithm None * @author Goodzzp 2006-11-20 * @lastEdit Goodzzp 2006-11-20 * @editDetail Create */ public class HashAlgorithms { /** * 加法hash * ...
    /**
     * Hash算法大全<br>
     * 推荐使用FNV1算法
     * 
     * @algorithm None
     * @author Goodzzp 2006-11-20
     * @lastEdit Goodzzp 2006-11-20
     * @editDetail Create
     */
    public class HashAlgorithms {
    
    	/**
    	 * 加法hash
    	 * 
    	 * @param key
    	 *            字符串
    	 * @param prime
    	 *            一个质数
    	 * @return hash结果
    	 */
    	public 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);
    	}
    
    	/**
    	 * 旋转hash
    	 * 
    	 * @param key
    	 *            输入字符串
    	 * @param prime
    	 *            质数
    	 * @return hash值
    	 */
    	public 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);
    		// return (hash ^ (hash>>10) ^ (hash>>20));
    	}
    
    	// 替代:
    	// 使用:hash = (hash ^ (hash>>10) ^ (hash>>20)) & mask;
    	// 替代:hash %= prime;
    
    	/**
    	 * MASK值,随便找一个值,最好是质数
    	 */
    	static int M_MASK = 0x8765fed1;
    
    	/**
    	 * 一次一个hash
    	 * 
    	 * @param key
    	 *            输入字符串
    	 * @return 输出hash值
    	 */
    	public static int oneByOneHash(String key) {
    		int hash, i;
    		for (hash = 0, i = 0; i < key.length(); ++i) {
    			hash += key.charAt(i);
    			hash += (hash << 10);
    			hash ^= (hash >> 6);
    		}
    		hash += (hash << 3);
    		hash ^= (hash >> 11);
    		hash += (hash << 15);
    		// return (hash & M_MASK);
    		return hash;
    	}
    
    	/**
    	 * Bernstein's hash
    	 * 
    	 * @param key
    	 *            输入字节数组
    	 * @param level
    	 *            初始hash常量
    	 * @return 结果hash
    	 */
    	public 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;
    	}
    
    	/**
    	 * Universal Hashing
    	 */
    	public static int universal(char[] key, int mask, int[] tab) {
    		int hash = key.length, i, len = key.length;
    		for (i = 0; i < (len << 3); i += 8) {
    			char k = key[i >> 3];
    			if ((k & 0x01) == 0)
    				hash ^= tab[i + 0];
    			if ((k & 0x02) == 0)
    				hash ^= tab[i + 1];
    			if ((k & 0x04) == 0)
    				hash ^= tab[i + 2];
    			if ((k & 0x08) == 0)
    				hash ^= tab[i + 3];
    			if ((k & 0x10) == 0)
    				hash ^= tab[i + 4];
    			if ((k & 0x20) == 0)
    				hash ^= tab[i + 5];
    			if ((k & 0x40) == 0)
    				hash ^= tab[i + 6];
    			if ((k & 0x80) == 0)
    				hash ^= tab[i + 7];
    		}
    		return (hash & mask);
    	}
    
    	/**
    	 * Zobrist Hashing
    	 */
    	public static int zobrist(char[] key, int mask, int[][] tab) {
    		int hash, i;
    		for (hash = key.length, i = 0; i < key.length; ++i)
    			hash ^= tab[i][key[i]];
    		return (hash & mask);
    	}
    
    	// LOOKUP3
    	// 见Bob Jenkins(3).c文件
    
    	// 32位FNV算法
    	static int M_SHIFT = 0;
    
    	/**
    	 * 32位的FNV算法
    	 * 
    	 * @param data
    	 *            数组
    	 * @return int值
    	 */
    	public static 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;
    	}
    
    	/**
    	 * 改进的32位FNV算法1
    	 * 
    	 * @param data
    	 *            数组
    	 * @return int值
    	 */
    	public static int FNVHash1(byte[] data) {
    		final int p = 16777619;
    		int hash = (int) 2166136261L;
    		for (byte b : data)
    			hash = (hash ^ b) * p;
    		hash += hash << 13;
    		hash ^= hash >> 7;
    		hash += hash << 3;
    		hash ^= hash >> 17;
    		hash += hash << 5;
    		return hash;
    	}
    
    	/**
    	 * 改进的32位FNV算法1
    	 * 
    	 * @param data
    	 *            字符串
    	 * @return int值
    	 */
    	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;
    	}
    
    	/**
    	 * Thomas Wang的算法,整数hash
    	 */
    	public static int intHash(int key) {
    		key += ~(key << 15);
    		key ^= (key >>> 10);
    		key += (key << 3);
    		key ^= (key >>> 6);
    		key += ~(key << 11);
    		key ^= (key >>> 16);
    		return key;
    	}
    
    	/**
    	 * RS算法hash
    	 * 
    	 * @param str
    	 *            字符串
    	 */
    	public 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);
    	}
    
    	/* End Of RS Hash Function */
    
    	/**
    	 * JS算法
    	 */
    	public static int JSHash(String str) {
    		int hash = 1315423911;
    
    		for (int i = 0; i < str.length(); i++) {
    			hash ^= ((hash << 5) + str.charAt(i) + (hash >> 2));
    		}
    
    		return (hash & 0x7FFFFFFF);
    	}
    
    	/* End Of JS Hash Function */
    
    	/**
    	 * PJW算法
    	 */
    	public static int PJWHash(String str) {
    		int BitsInUnsignedInt = 32;
    		int ThreeQuarters = (BitsInUnsignedInt * 3) / 4;
    		int OneEighth = BitsInUnsignedInt / 8;
    		int HighBits = 0xFFFFFFFF << (BitsInUnsignedInt - OneEighth);
    		int hash = 0;
    		int test = 0;
    
    		for (int i = 0; i < str.length(); i++) {
    			hash = (hash << OneEighth) + str.charAt(i);
    
    			if ((test = hash & HighBits) != 0) {
    				hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits));
    			}
    		}
    
    		return (hash & 0x7FFFFFFF);
    	}
    
    	/* End Of P. J. Weinberger Hash Function */
    
    	/**
    	 * ELF算法
    	 */
    	public static int ELFHash(String str) {
    		int hash = 0;
    		int x = 0;
    
    		for (int i = 0; i < str.length(); i++) {
    			hash = (hash << 4) + str.charAt(i);
    			if ((x = (int) (hash & 0xF0000000L)) != 0) {
    				hash ^= (x >> 24);
    				hash &= ~x;
    			}
    		}
    
    		return (hash & 0x7FFFFFFF);
    	}
    
    	/* End Of ELF Hash Function */
    
    	/**
    	 * BKDR算法
    	 */
    	public static int BKDRHash(String str) {
    		int seed = 131; // 31 131 1313 13131 131313 etc..
    		int hash = 0;
    
    		for (int i = 0; i < str.length(); i++) {
    			hash = (hash * seed) + str.charAt(i);
    		}
    
    		return (hash & 0x7FFFFFFF);
    	}
    
    	/* End Of BKDR Hash Function */
    
    	/**
    	 * SDBM算法
    	 */
    	public static int SDBMHash(String str) {
    		int hash = 0;
    
    		for (int i = 0; i < str.length(); i++) {
    			hash = str.charAt(i) + (hash << 6) + (hash << 16) - hash;
    		}
    
    		return (hash & 0x7FFFFFFF);
    	}
    
    	/* End Of SDBM Hash Function */
    
    	/**
    	 * DJB算法
    	 */
    	public static int DJBHash(String str) {
    		int hash = 5381;
    
    		for (int i = 0; i < str.length(); i++) {
    			hash = ((hash << 5) + hash) + str.charAt(i);
    		}
    
    		return (hash & 0x7FFFFFFF);
    	}
    
    	/* End Of DJB Hash Function */
    
    	/**
    	 * DEK算法
    	 */
    	public static int DEKHash(String str) {
    		int hash = str.length();
    
    		for (int i = 0; i < str.length(); i++) {
    			hash = ((hash << 5) ^ (hash >> 27)) ^ str.charAt(i);
    		}
    
    		return (hash & 0x7FFFFFFF);
    	}
    
    	/* End Of DEK Hash Function */
    
    	/**
    	 * AP算法
    	 */
    	public static int APHash(String str) {
    		int hash = 0;
    
    		for (int i = 0; i < str.length(); i++) {
    			hash ^= ((i & 1) == 0) ? ((hash << 7) ^ str.charAt(i) ^ (hash >> 3))
    					: (~((hash << 11) ^ str.charAt(i) ^ (hash >> 5)));
    		}
    
    		// return (hash & 0x7FFFFFFF);
    		return hash;
    	}
    
    	/* End Of AP Hash Function */
    
    	/**
    	 * JAVA自己带的算法
    	 */
    	public static int java(String str) {
    		int h = 0;
    		int off = 0;
    		int len = str.length();
    		for (int i = 0; i < len; i++) {
    			h = 31 * h + str.charAt(off++);
    		}
    		return h;
    	}
    
    	/**
    	 * 混合hash算法,输出64位的值
    	 */
    	public static long mixHash(String str) {
    		long hash = str.hashCode();
    		hash <<= 32;
    		hash |= FNVHash1(str);
    		return hash;
    	}
    }
    


    展开全文
  • Hash 算法

    2013-02-22 10:13:49
    Hash,一般翻译做“散列”,也有直接音译为"哈希"的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间...
    
    

    Hash,一般翻译做“散列”,也有直接音译为"哈希"的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。

    数学表述为:h = H(M) ,其中H( )--单向散列函数,M--任意长度明文,h--固定长度散列值。

    用来产生一些数据片段(例如消息或会话项)的散列值的算法。好的散列算法具有在输入数据中的更改可以更改结果散列值中每个比特的特性;因此,散列对于检测在诸如消息等大型信息对象中的任何变化很有用。此外,好的散列算法使得构造两个独立的有相同散列的输入不能通过计算方法实现。典型的散列算法包括 MD2、MD4、MD5 和 SHA-1。散列算法也被称为散列函数。散列算法的算法就是争取一个萝卜一个坑的原则
    比如说有5个数 12,25,30,45,50,这几个数有个规律,就是十位数都不相同,
    如果我设置一个散列函数f(value)=value/10;平常的时候,我们查找50,要比较
    5次(其他算法可能不同),这里用散列算法只需要1次,就是解散列函数,key=50/10
    =5,要找的数就在第5个位子.但是上面问题还是很多的,比如说查找55呢?就会出
    错<因为55解散列函数之后,也是在第5个位子>,还有等等等问题,很显然这个是我
    散列函数没设置好,当你把散列函数设置好了后,由于数据的庞大,冲突很有可能
    产生,那么就需要我们来处理冲突了,所以写散列算法就是设置好的散列函数和
    处理冲突的过程.这里散列算法涉及的查找就跟查找的数量无关,跟冲突率有直接
    的关系

    在信息安全领域中应用的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 和 Dobbertin 很快就用分析和差分成功的攻击了它3轮变换中的 2 轮,证明了它并不像期望的那样安全,但它的整个算法并没有真正被破解过,Rivest 也很快进行了改进。

    下面是一些MD4散列结果的例子:

    MD4 ("") = 31d6cfe0d16ae931b73c59d7e0c089c0 
    MD4 ("a") = bde52cb31de33e46245e05fbdbd6fb24 
    MD4 ("abc") = a448017aaf21d8525fc10ae87aa6729d 
    MD4 ("message digest") = d9130a8164549fe818874806e1c7014b 
    MD4 ("abcdefghijklmnopqrstuvwxyz") = d79e1c308aa5bbcdeea8ed63df412da9 
    MD4 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = 043f8582f241db351ce627e153e7f0e4 
    MD4 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = 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的正弦绝对值之4294967296次方的整数部分,这样做是为了通过正弦函数和幂函数来进一步消除变换中的线性性。

    当所有512位分组都运算完毕后,ABCD的级联将被输出为MD5散列的结果。下面是一些MD5散列结果的例子:

    MD5 ("") = d41d8cd98f00b204e9800998ecf8427e 
    MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661 
    MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72 
    MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0 
    MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b 
    MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = d174ab98d277d9f5a5611c2c9f419d9f 
    MD5 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = 57edf4a22be3c955ac49da2e2107b67a 
    参考相应RFC文档可以得到MD4、MD5算法的详细描述和算法的C源代码。

    3) SHA1 及其他 
    SHA1是由NIST NSA设计为同DSA一起使用的,访问http://www.itl.nist.gov/fipspubs可以得到它的详细规范--[/url]"FIPS PUB 180-1 SECURE HASH STANDARD"。它对长度小于264的输入,产生长度为160bit的散列值,因此抗穷举(brute-force)性更好。SHA-1 设计时基于和MD4相同原理,并且模仿了该算法。因为它将产生160bit的散列值,因此它有5个参与运算的32位寄存器字,消息分组和填充方式与MD5相同,主循环也同样是4轮,但每轮进行20次操作,非线性运算、移位和加法运算也与MD5类似,但非线性函数、加法常数和循环左移操作的设计有一些区别,可以参考上面提到的规范来了解这些细节。下面是一些SHA1散列结果的例子:

    SHA1 ("abc") = a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d 
    SHA1 ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = 84983e44 1c3bd26e baae4aa1 f95129e5 e54670f1 
    其他一些知名的Hash算法还有MD2、N-Hash、RIPE-MD、HAVAL等等。上面提到的这些都属于"纯"Hash算法。还有另2类Hash算法,一类就是基于对称分组算法的单向散列算法,典型的例子是基于DES的所谓Davies-Meyer算法,另外还有经IDEA改进的Davies-Meyer算法,它们两者目前都被认为是安全的算法。另一类是基于模运算/离散对数的,也就是基于公开密钥算法的,但因为其运算开销太大,而缺乏很好的应用前景。

    没有通过分析和差分攻击考验的算法,大多都已经夭折在实验室里了,因此,如果目前流行的Hash算法能完全符合密码学意义上的单向性和抗冲突性,就保证了只有穷举,才是破坏Hash运算安全特性的唯一方法。为了对抗弱抗冲突性,我们可能要穷举个数和散列值空间长度一样大的输入,即尝试2^128或2^160个不同的输入,目前一台高档个人电脑可能需要10^25年才能完成这一艰巨的工作,即使是最高端的并行系统,这也不是在几千年里的干得完的事。而因为"生日攻击"有效的降低了需要穷举的空间,将其降低为大约1.2*2^64或1.2*2^80,所以,强抗冲突性是决定Hash算法安全性的关键。

    在NIST新的 Advanced Encryption Standard (AES)中,使用了长度为128、192、256bit 的密钥,因此相应的设计了 SHA256、SHA384、SHA512,它们将提供更好的安全性。

    Hash算法在信息安全方面的应用主要体现在以下的3个方面:

    1) 文件校验 
    我们比较熟悉的校验算法有奇偶校验和CRC校验,这2种校验并没有抗数据篡改的能力,它们一定程度上能检测并纠正数据传输中的信道误码,但却不能防止对数据的恶意破坏。

    MD5 Hash算法的"数字指纹"特性,使它成为目前应用最广泛的一种文件完整性校验和(Checksum)算法,不少Unix系统有提供计算md5 checksum的命令。它常被用在下面的2种情况下:

    第一是文件传送后的校验,将得到的目标文件计算 md5 checksum,与源文件的md5 checksum 比对,由两者 md5 checksum 的一致性,可以从统计上保证2个文件的每一个码元也是完全相同的。这可以检验文件传输过程中是否出现错误,更重要的是可以保证文件在传输过程中未被恶意篡改。一个很典型的应用是ftp服务,用户可以用来保证多次断点续传,特别是从镜像站点下载的文件的正确性。

    更出色的解决方法是所谓的代码签名,文件的提供者在提供文件的同时,提供对文件Hash值用自己的代码签名密钥进行数字签名的值,及自己的代码签名证书。文件的接受者不仅能验证文件的完整性,还可以依据自己对证书签发者和证书拥有者的信任程度,决定是否接受该文件。浏览器在下载运行插件和java小程序时,使用的就是这样的模式。

    第二是用作保存二进制文件系统的数字指纹,以便检测文件系统是否未经允许的被修改。不少系统管理/系统安全软件都提供这一文件系统完整性评估的功能,在系统初始安装完毕后,建立对文件系统的基础校验和数据库,因为散列校验和的长度很小,它们可以方便的被存放在容量很小的存储介质上。此后,可以定期或根据需要,再次计算文件系统的校验和,一旦发现与原来保存的值有不匹配,说明该文件已经被非法修改,或者是被病毒感染,或者被木马程序替代。TripWire就提供了一个此类应用的典型例子。

    更完美的方法是使用"MAC"。"MAC" 是一个与Hash密切相关的名词,即信息鉴权码(Message Authority Code)。它是与密钥相关的Hash值,必须拥有该密钥才能检验该Hash值。文件系统的数字指纹也许会被保存在不可信任的介质上,只对拥有该密钥者提供可鉴别性。并且在文件的数字指纹有可能需要被修改的情况下,只有密钥的拥有者可以计算出新的散列值,而企图破坏文件完整性者却不能得逞。

    2) 数字签名 
    Hash 算法也是现代密码体系中的一个重要组成部分。由于非对称算法的运算速度较慢,所以在数字签名协议中,单向散列函数扮演了一个重要的角色。

    在这种签名协议中,双方必须事先协商好双方都支持的Hash函数和签名算法。

    签名方先对该数据文件进行计算其散列值,然后再对很短的散列值结果--如Md5是16个字节,SHA1是20字节,用非对称算法进行数字签名操作。对方在验证签名时,也是先对该数据文件进行计算其散列值,然后再用非对称算法验证数字签名。

    对 Hash 值,又称"数字摘要"进行数字签名,在统计上可以认为与对文件本身进行数字签名是等效的。而且这样的协议还有其他的优点:

    首先,数据文件本身可以同它的散列值分开保存,签名验证也可以脱离数据文件本身的存在而进行。

    再者,有些情况下签名密钥可能与解密密钥是同一个,也就是说,如果对一个数据文件签名,与对其进行非对称的解密操作是相同的操作,这是相当危险的,恶意的破坏者可能将一个试图骗你将其解密的文件,充当一个要求你签名的文件发送给你。因此,在对任何数据文件进行数字签名时,只有对其Hash值进行签名才是安全的。

    3) 鉴权协议 
    如下的鉴权协议又被称作"挑战--认证模式:在传输信道是可被侦听,但不可被篡改的情况下,这是一种简单而安全的方法。

    需要鉴权的一方,向将被鉴权的一方发送随机串(“挑战”),被鉴权方将该随机串和自己的鉴权口令字一起进行 Hash 运算后,返还鉴权方,鉴权方将收到的Hash值与在己端用该随机串和对方的鉴权口令字进行 Hash 运算的结果相比较(“认证”),如相同,则可在统计上认为对方拥有该口令字,即通过鉴权。

    POP3协议中就有这一应用的典型例子:

    S: +OK POP3 server ready <1896.697170952@dbc.mtview.ca.us> 
    C: APOP mrose c4c9334bac560ecc979e58001b3e22fb 
    S: +OK maildrop has 1 message (369 octets) 
    在上面的一段POP3协议会话中,双方都共享的对称密钥(鉴权口令字)是tanstaaf,服务器发出的挑战是<1896.697170952@dbc.mtview.ca.us>,客户端对挑战的应答是MD5("<1896.697170952@dbc.mtview.ca.us>tanstaaf") = c4c9334bac560ecc979e58001b3e22fb,这个正确的应答使其通过了认证。

    散列算法长期以来一直在计算机科学中大量应用,随着现代密码学的发展,单向散列函数已经成为信息安全领域中一个重要的结构模块,我们有理由深入研究其设计理论和应用方法。


    展开全文
  • 在讲redis的hash slot之前,先讲一讲最常见的hash算法和一致性hash算法做个比较 hash算法 最常见的hash算法就是直接取模了,假如这是我们有三台redis服务器,这时来了一个key,我们会先对key进行hash计算,然后...

    这篇文章我们来了解一下各种数据分布算法,以redis作为数据分布的机器来举例

    1. hash算法
      首先是最简单的hash算法,假如我们有三台redis服务器,这时来了一个key,我们会先对key进行hash计算,然后根据机器数量进行取模,得出的结果就是机器的一个编号,就将key发送到这台机器上去
      如果这时突然有一台机器宕机了,那么一时间这台机器上所有的缓存都失效了,那么请求就会直接打到MySQL上,如果数据量太大,会导致MySQL也宕机
      即使MySQL抗住了这些请求,之后的key在进行hash算法的时候,也需要重新进行取模,因为机器的数量变了,从而导致大部分的缓存都会失效,大量的key重新分配
      hash算法
    2. 一致性hash算法
      一致性hash算法有一个hash环的概念,每个key的hash值会对2^32 进行取模,最终保证每个计算出的值都在这个hash环上
      而我们的redis机器也会根据ip地址的hash值对2^32进行取模,最后也是在这个hash环上,计算出的key值在hash环上顺时针找到的第一个机器,key就会发到这台机器上
      在遇到上面的hash算法的节点宕机问题时,原先节点上的key会顺时针的找到下一个节点,只有原先在这个节点上的key会失效,大部分的key并不会受到影响
      这里还有一个问题就是hash环的数据倾斜问题,当节点都集中在hash环的某一块时,会导致大量的key都会集中在其中的某一个机器上,极端情况下,如果这个机器宕机了,同样会造成系统崩溃
      为了解决这个问题,会使用虚拟节点,将各个机器虚拟出一些节点出来,均匀的分布在hash环上,让key顺时针可以找到这些虚拟节点,从而使得key更加均匀的分布到各台机器上
      一致性hash算法
    3. hash slot算法
      redis cluster中使用的是hash slot算法,redis cluster有固定的16384个hash slot,对每个key计算CRC16值,然后对16384取模,就得到了每个key对应的hash slot,即HASH_SLOT = CRC16(key) mod 16384
      redis cluster中的master都会持有一部分的hash slot,类似于分布式存储,如果你的集群有三个节点,那么每个节点都会有5000多个hash slot
      当节点增加或者减少的时候,hash slot也会对应的移动,并且移动hash slot的成本非常低,这种方式减轻了其他hash算法重新计算hash值的开销,且使用CRC16算法计算出来的key可以在16384个槽中均匀分布
      当key写入到了某个节点的hash slot,之后读取的时候,如果正好读取到了这个节点,那么就直接处理后返回即可;如果读取的key在其他节点的hash slot上时,就返回一个moved error,让客户端重定向到hash slot所在的节点去读取数据
      每次读取缓存的时候都是去找的hash slot,即使找的节点不对,也会重定向到新的节点去寻找,不会造成缓存失效的问题
      hash slot
    展开全文
  • HASH 算法

    千次阅读 2012-06-30 15:16:52
    Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间...
  • Hash算法和一致性Hash算法

    千次阅读 2019-06-20 18:34:09
    Hash算法在路由算法应用中,为了保证数据均匀的分布,例如有3个桶,分别是0号桶,1号桶和2号桶;现在有12个球,怎么样才能让12个球平均分布到3个桶中呢?使用Hash算法的做法是,将12个球从0开始编号,得到这样的一个...
  • 分布式数据存储的核心算法,数据分布的算法主要有三种算法:hash算法、一致性hash算法、hash slot算法。 hash算法 -> 一致性hash算法(memcached使用) -> hash slot算法(redis cluster 使用) ​ redis ...
  • Hash算法及其应用

    2019-08-30 14:43:40
    Hash算法 其实hash和散列表示的一个意思,所以hash表就是散列表,hash算法就是散列算法,hash函数就是散列函数。 这说的hash算法,什么是hash算法?有一句很easy的总结:将任意长度的二进制串映射为固定长度的二...
  • 一致性hash算法

    千次阅读 2019-04-27 22:47:14
    一致性hash算法Hash算法的作用Hash算法的冲突一致性hash算法一致性hash算法的原理容错性虚拟节点 Hash 算法也叫做散列算法,他可以让任意长度的数据M映射成为长度固定的值H。 Hash算法的作用 Hash算法的第一个作用...
  • Hash算法特点

    2020-04-15 16:22:47
    2.2 Hash算法有什么特点 一个优秀的 hash 算法,将能实现: 正向快速:给定明文和 hash 算法,在有限时间和有限资源内能计算出 hash 值。 逆向困难:给定(若干) hash 值,在有限时间内很难(基本不可能)逆推出...
  • 浅显理解 hashcode 和 hash 算法

    万次阅读 多人点赞 2017-12-30 23:06:07
    HashMap 的 hash 算法的实现原理(为什么右移 16 位,为什么要使用 ^ 位异或) HashMap 为什么使用 &amp; 与运算代替模运算? HashMap 的容量为什么建议是 2的幂次方? 我们自定义 HashMap 容量最好是多少? 前
  • C语言Hash算法

    2020-02-02 20:59:07
    Hash算法入门 什么是Hash算法 一般的线性表,树中,记录在结构中的相对位置是随机的,即和记录的关键字之间不存在确定的关系,因此,在结构中查找记录时需进行一系列和关键字的比较。简而言之就是将字符串转化为一个...
  • Hash算法详解

    万次阅读 2018-06-26 20:16:00
    Hash算法,简称散列算法,也成哈希算法(英译)。是将一个大文件映射成一个小串字符。
  • GeoHash 算法

    千次阅读 2019-04-26 01:08:26
    业界比较通用的地理位置距离排序算法是 GeoHash 算法,Redis 也使用 GeoHash 算法。GeoHash 算法将二维的经纬度数据映射到一维的整数,这样所有的元素都将在挂载到一条线上,距离靠近的二维坐标映射到一维后的点之间...
  • 一致性hash算法是在redis 分片中使用,hash槽在redis cluster(集群)中使用 hash槽: redis集群(cluster)并没有使用一致性hash算法,而是使用hash槽(slot)这个概念, 因为一致性hash算法对于数据的分布,节点...
  • maglev hash算法

    2019-10-31 00:01:28
    maglev hash算法先把n个server填满大小为m的数组table(m > n,m为素数); 然后算法选择table[hash(input)]中的sever。 1. 对每个server构建排列表(permutation) 1.1 计算 排列表的大小为m,计算如下: ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 23,494
精华内容 9,397
关键字:

hash算法