哈希算法:是把任意长度的输入映射成固定长度的输出,这个映射规则就是哈希算法,该输出就是哈希值。
哈希算法应满足以下几点要求:
1、从哈希值不能反向推导出原始数据,所以哈希算法又叫单向哈希算法
2、对输入敏感,原始数据即使只修改了一个bit,得到的哈希值也不同
3、散列冲突的概率很小,对不同的原始数据,计算出的哈希值相同的概率非常小
4、执行效率要高,即便针对较长的文本,也能快速地计算出哈希值
哈希算法常见的应用场景:安全加密、唯一标识、数据校验、散列函数、负载均衡、数据分片、分布式存储。
安全加密:
最常见的安全加密算法是MD5(Message-Digest Algorithm ,消息摘要算法)和SHA(Secure Hash Algorithm ,安全散列算法)。除此之外还有DES(Data Encryption Standard,数据加密标准)、AES(Advanced Encryption Standard,高级加密标准)。
没有绝对安全的加密。越复杂、越难破解的加密算法,需要的计算时间也越长。比如 SHA-256 比 SHA-1 要更复杂、更安全,相应的计算时间就会比较长。
唯一标识:
比如在海量的图库中查找一张图是否存在。就可以给每张图片取一个唯一标识,来根据唯一标识来判断。
数据校验:
校验下载的文件是否被篡改过。
散列函数:
根据key生成均匀的数组下标
我们可以通过哈希算法,对用户密码进行加密之后再存储,不过最好选择相对安全的加密算法(SHA),不过仅仅这样还不行。
字典攻击:黑客拿到了加密之后的密文,可以通过猜的方式来破解密码,使用一个常用密码的字典表,把字典中的每个密码用哈希算法计算哈希值,然后拿哈希值和拿到的密码密文进行对比,如果相同,基本上就可以认为,这个加密后的密码对应的明文就是字典中的密码。
针对字典攻击,可以通过加盐(salt)的方式,用盐和用户的密码组合在一起,增加密码的复杂度;拿组合之后的字符串来做哈希算法加密,将结果存储到数据库中。
1 MD5 JAVA实现 2 参考 3 public class MD5{ 4 /* 5 *四个链接变量 6 */ 7 private final int A=0x67452301; 8 private final int B=0xefcdab89; 9 private final int C=0x98badcfe; 10 private final int D=0x10325476; 11 /* 12 *ABCD的临时变量 13 */ 14 private int Atemp,Btemp,Ctemp,Dtemp; 15 16 /* 17 *常量ti 18 *公式:floor(abs(sin(i+1))×(2pow32) 19 */ 20 private final int K[]={ 21 0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee, 22 0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,0x698098d8, 23 0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193, 24 0xa679438e,0x49b40821,0xf61e2562,0xc040b340,0x265e5a51, 25 0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8, 26 0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905, 27 0xfcefa3f8,0x676f02d9,0x8d2a4c8a,0xfffa3942,0x8771f681, 28 0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60, 29 0xbebfbc70,0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05, 30 0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,0xf4292244, 31 0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92, 32 0xffeff47d,0x85845dd1,0x6fa87e4f,0xfe2ce6e0,0xa3014314, 33 0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391}; 34 /* 35 *向左位移数,计算方法未知 36 */ 37 private final int s[]={7,12,17,22,7,12,17,22,7,12,17,22,7, 38 12,17,22,5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20, 39 4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,6,10, 40 15,21,6,10,15,21,6,10,15,21,6,10,15,21}; 41 42 43 /* 44 *初始化函数 45 */ 46 private void init(){ 47 Atemp=A; 48 Btemp=B; 49 Ctemp=C; 50 Dtemp=D; 51 } 52 /* 53 *移动一定位数 54 */ 55 private int shift(int a,int s){ 56 return(a<<s)|(a>>>(32-s));//右移的时候,高位一定要补零,而不是补充符号位 57 } 58 /* 59 *主循环 60 */ 61 private void MainLoop(int M[]){ 62 int F,g; 63 int a=Atemp; 64 int b=Btemp; 65 int c=Ctemp; 66 int d=Dtemp; 67 for(int i = 0; i < 64; i ++){ 68 if(i<16){ 69 F=(b&c)|((~b)&d); 70 g=i; 71 }else if(i<32){ 72 F=(d&b)|((~d)&c); 73 g=(5*i+1)%16; 74 }else if(i<48){ 75 F=b^c^d; 76 g=(3*i+5)%16; 77 }else{ 78 F=c^(b|(~d)); 79 g=(7*i)%16; 80 } 81 int tmp=d; 82 d=c; 83 c=b; 84 b=b+shift(a+F+K[i]+M[g],s[i]); 85 a=tmp; 86 } 87 Atemp=a+Atemp; 88 Btemp=b+Btemp; 89 Ctemp=c+Ctemp; 90 Dtemp=d+Dtemp; 91 92 } 93 /* 94 *填充函数 95 *处理后应满足bits≡448(mod512),字节就是bytes≡56(mode64) 96 *填充方式为先加一个0,其它位补零 97 *最后加上64位的原来长度 98 */ 99 private int[] add(String str){ 100 int num=((str.length()+8)/64)+1;//以512位,64个字节为一组 101 int strByte[]=new int[num*16];//64/4=16,所以有16个整数 102 for(int i=0;i<num*16;i++){//全部初始化0 103 strByte[i]=0; 104 } 105 int i; 106 for(i=0;i<str.length();i++){ 107 strByte[i>>2]|=str.charAt(i)<<((i%4)*8);//一个整数存储四个字节,小端序 108 } 109 strByte[i>>2]|=0x80<<((i%4)*8);//尾部添加1 110 /* 111 *添加原长度,长度指位的长度,所以要乘8,然后是小端序,所以放在倒数第二个,这里长度只用了32位 112 */ 113 strByte[num*16-2]=str.length()*8; 114 return strByte; 115 } 116 /* 117 *调用函数 118 */ 119 public String getMD5(String source){ 120 init(); 121 int strByte[]=add(source); 122 for(int i=0;i<strByte.length/16;i++){ 123 int num[]=new int[16]; 124 for(int j=0;j<16;j++){ 125 num[j]=strByte[i*16+j]; 126 } 127 MainLoop(num); 128 } 129 return changeHex(Atemp)+changeHex(Btemp)+changeHex(Ctemp)+changeHex(Dtemp); 130 131 } 132 /* 133 *整数变成16进制字符串 134 */ 135 private String changeHex(int a){ 136 String str=""; 137 for(int i=0;i<4;i++){ 138 str+=String.format("%2s", Integer.toHexString(((a>>i*8)%(1<<8))&0xff)).replace(' ', '0'); 139 140 } 141 return str; 142 } 143 /* 144 *单例 145 */ 146 private static MD5 instance; 147 public static MD5 getInstance(){ 148 if(instance==null){ 149 instance=new MD5(); 150 } 151 return instance; 152 } 153 154 private MD5(){}; 155 156 public static void main(String[] args){ 157 String str=MD5.getInstance().getMD5(""); 158 System.out.println(str); 159 } 160 } 161 1 162
留点什么