HASH算法介绍
-
Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一地确定输入值。
-
数学表述为:h = H(M) ,其中H( )--单向散列函数,M--任意长度明文,h--固定长度散列值。
HASH算法的实际应用-加密
-
常见的哈希加密算法:MD5,SHA-1,SHA-2,SHA-256,SHA-X(系列)
-
1) 文件校验:MD5 Hash算法的“数字指纹”特性,使它成为目前应用最广泛的一种文件完整性校验和(Checksum)算法,不少Unix系统有提供计算md5 checksum的命令;
-
2) 数字签名:在这种签名协议中,双方必须事先协商好双方都支持的Hash函数和签名算法。签名方先对该数据文件进行计算其散列值,然后再对很短的散列值结果--如Md5是16个字节,SHA1是20字节,用非对称算法进行数字签名操作。对方在验证签名时,也是先对该数据文件进行计算其散列值,然后再用非对称算法验证数字签名; (实际是HASH+非对称加密)
-
3) 鉴权协议:需要鉴权的一方,向将被鉴权的一方发送随机串(“挑战”),被鉴权方将该随机串和自己的鉴权口令字一起进行 Hash 运算后,返还鉴权方,鉴权方将收到的Hash值与在己端用该随机串和对方的鉴权口令字进行 Hash 运算的结果相比较(“认证”),如相同,则可在统计上认为对方拥有该口令字,即通过鉴权。(摘要)
-
HASH加密算法与其他加密算法的主要不同点是:哈希(Hash)算法是一种单向密码体制,即只有 加密过程,没有解密过程
HASH算法的实际应用-查找
-
常见的哈希查找算法:BKDRHash,APHash,DJBHash,JSHash,RSHash,SDBMHash等
-
1) 基本思想是:以数据对象的关键词 key 为自变量,通过一个确定的函数关系 ℎh ,计算出对应的函数值 ℎ(𝑘𝑒𝑦)h(key) ,把这个值解释为数据对象的存储地址,并按此存放,即“存储位置=ℎ(𝑘𝑒𝑦)存储位置=h(key)”。
-
Gdb下函数符号实际对应的是一个内存地址,映射大小为32bit或64bit(即32位系统或64位系统)
FNV算法介绍
-
FNV哈希算法全名为Fowler-Noll-Vo算法,是以三位发明人Glenn Fowler,Landon Curt Noll,Phong Vo的名字来命名的,最早在1991年提出
-
特点和用途:FNV能快速hash大量数据并保持较小的冲突率,它的高度分散使它适用于hash一些非常相近的字符串,比如URL,hostname,文件名,text,IP地址等。
-
适用范围:比较适用于字符串比较短的哈希场景
FNV哈希算法有如下两种,FNV-1a相比FNV-1,散列分布更好。二者不同点为:for循环两行代码的顺序相反
哈希函数一般适用移位和乘除法来实现。哈希函数一般都比较精简,算法复杂度比较低。哈希函数的移位和乘除法可能会导致数据丢失,这也是哈希不可逆的原因
FNV算法说明-1
-
hash值:一个n位的unsigned int型hash值,初始值为offset_basis.
-
offset_basis:初始的哈希值,该值在最早的版本中是0,为了增强哈希的可靠性,后续修改为非0的值,通过如下算法获取
参见《生成offset_basis.py》
FNV算法说明-2
octet_of_data:8位数据(即一个字节):即需要被哈希的字符串
FNV_prime:FNV用于散列的质数(质数在哈希算法中发挥着重要作用,在一般使用的哈希除留余数法中: H(key) = key MOD p,p也要求是一个质数(质数也称为素数))
-
32 bit FNV_prime = 224 + 28 + 0x93 = 16777619
-
64 bit FNV_prime = 240 + 28 + 0xb3 = 1099511628211
-
128 bit FNV_prime = 288 + 28 + 0x3b = 309485009821345068724781371
-
256 bit FNV_prime = 2168 + 28 + 0x63 = 374144419156711147060143317175368453031918731002211
-
512 bit FNV_prime = 2344 + 28 + 0x57 = 35835915874844867368919076489095108449946327955754392558399825615420669938882575126094039892345713852759
FNV算法使用
-
支持将字符串哈希为32/64/128/256/512/1024bit的数字
-
支持将字符串哈希为任意bit的数字,比如11/33bit
-
支持将字符串哈希为特定范围的数字,比如[0,99999]
将字符串哈希为32bit的数字
hash = offset_basis for each octet_of_data to be hashed hash = hash xor octet_of_data hash = hash * FNV_prime return hash
参见《生成32位哈希.py》
将字符串哈希为特定范围的数字
将字符串哈希为[0,999]的数字 #define TRUE_HASH_SIZE ((u_int32_t)50000) /* range top plus 1 */ #define FNV_32_PRIME ((u_int32_t)16777619) #define FNV1_32_INIT ((u_int32_t)2166136261) #define MAX_32BIT ((u_int32_t)0xffffffff) /* largest 32 bit unsigned value */ #define RETRY_LEVEL ((MAX_32BIT / TRUE_HASH_SIZE) * TRUE_HASH_SIZE) u_int32_t hash; void *data; size_t data_len; hash = fnv_32_buf(data, data_len, FNV1_32_INIT); while (hash >= RETRY_LEVEL) { hash = (hash * FNV_32_PRIME) + FNV1_32_INIT; } hash %= TRUE_HASH_SIZE;
参见《生成任意范围哈希.py》,代码附件链接
Java代码Demo
1 /** 2 * FNV算法 3 * 参考:https://www.cnblogs.com/charlieroro/archive/2018/03/01/8486941.html 4 */ 5 public class FNC { 6 7 public static int FNV1_32_HASH(String data) { 8 // p = FNV_prime:FNV用于散列的质数 9 final int p = 16777619; 10 // hash = offset_basis:初始的哈希值 11 int hash = (int)2166136261L; 12 for(int i=0;i<data.length();i++) { 13 hash = (hash ^ data.charAt(i)) * p; 14 } 15 hash += hash << 13; 16 hash ^= hash >> 7; 17 hash += hash << 3; 18 hash ^= hash >> 17; 19 hash += hash << 5; 20 return hash; 21 } 22 23 /** 24 * 测试散列IP的情况 25 */ 26 @Test 27 public void testIP_FNV1_32_HASH() { 28 // 总个数 29 long totalIp = 0; 30 // 小于0个数 31 long ltCount = 0; 32 // 等于0个数 33 long eqCount = 0; 34 // 大于0个数 35 long gtCount = 0; 36 int maxIpHash = 0; 37 int minIpHash = 0; 38 39 SortedMap<Integer, Long> sortedMap = new TreeMap<>(); 40 // 生成ip 41 // int[] ip = new int[]{0, 0, 0, 0}; 42 long startTime = System.currentTimeMillis(); 43 for (int i = 0; i < 100; i++) { 44 for (int j = 0; j < 100; j++) { 45 for (int k = 0; k < 100; k++) { 46 for (int l = 0; l < 100; l++) { 47 // ip[0] = i; 48 // ip[1] = j; 49 // ip[2] = k; 50 // ip[3] = l; 51 StringBuilder ip = new StringBuilder(); 52 ip.append(i); 53 ip.append("."); 54 ip.append(j); 55 ip.append("."); 56 ip.append(k); 57 ip.append("."); 58 ip.append(l); 59 int hash = FNC.FNV1_32_HASH(ip.toString()); 60 61 // 统计 62 // 小于0个数 63 if(hash < 0) { 64 minIpHash = Math.min(hash, minIpHash); 65 ltCount++; 66 } else if (hash == 0) { 67 eqCount++; 68 } else { 69 maxIpHash = Math.max(hash, maxIpHash); 70 gtCount++; 71 // 计算正数的区间 72 int key = hash / (Integer.MAX_VALUE / 100); 73 if (key == 100) { 74 System.out.println("key = " + key + "\thash = " + hash); 75 } 76 sortedMap.put(key, sortedMap.getOrDefault(key, 0l) + 1); 77 } 78 totalIp++; 79 } 80 } 81 } 82 } 83 84 // ---------------------- 85 long endTime = System.currentTimeMillis(); 86 System.out.println("endTime - startTime = " + (endTime - startTime)); 87 88 System.out.println("totalIp = " + totalIp); 89 System.out.println("Integer.MIN_VALUE = " + Integer.MIN_VALUE); 90 System.out.println("Integer.MAX_VALUE = " + Integer.MAX_VALUE); 91 System.out.println("minIpHash = " + minIpHash); 92 System.out.println("maxIpHash = " + maxIpHash); 93 System.out.println("ltCount = " + ltCount); 94 System.out.println("eqCount = " + eqCount); 95 System.out.println("gtCount = " + gtCount); 96 long[] mapArr = new long[]{Long.MAX_VALUE, 0l, 0l, 0l}; 97 sortedMap.forEach((k, v) -> { 98 long min = Math.min(v, mapArr[0]); 99 if (min != mapArr[0]) { 100 mapArr[1] = mapArr[0]; 101 mapArr[0] = min; 102 } 103 long max = Math.max(v, mapArr[3]); 104 if (max != mapArr[3]) { 105 mapArr[2] = mapArr[3]; 106 mapArr[3] = max; 107 } 108 System.out.println("(k, v) = " + "("+k+", "+v+")"); 109 }); 110 System.out.println("Arrays.toString(mapArr) = " + Arrays.toString(mapArr)); 111 System.out.println("-------------------"); 112 // System.out.println("256*256*256*256 = " + 256l*256*256*256); 113 } 114 }
参考:http://www.isthe.com/chongo/tech/comp/fnv/index.html#lazy-mod
原文连接:https://www.cnblogs.com/charlieroro/archive/2018/03/01/8486941.html