本篇文章主要讲解的内容有:html
若是是你感兴趣的,那么我们就接着往下看,若是不是就能够cmd+w
离开了。面试
哈希(hash)表原称散列表,音译为哈希。它是一种能够根据键(key)直接访问对应值(value)的数据结构。算法
hash表是基于数组的,所以咱们来先看下面这个数组(上面是index,下面是value)// 表格有点宽,显示不完,能够左右滑动查看数组
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
28 | 16 | 97 | 45 | 9 | 76 | 33 | 47 |
这个数组的值是随便写的,如今假设咱们要判断33是否在这个数组中,那么咱们就能够经过for循环遍历这个数组,一一对比数组中的元素是否等于33,而后就能够得出结果,可是这样作的时间复杂度是O(n),也就是说最坏的状况是咱们须要把数组中的元素都对照一遍才能得出结论。那么如何可以更快找出33呢?安全
咱们都知道在数组中,经过下标取值是很是快的,而hash表就是以这个思想为基础进行实现的。下面咱们改变一下思路,将上面数组中的每一个元素都对10进行整除而且把计算结果做为数组的下标,而后就能够获得下面的表:服务器
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
9 | 16 | 28 | 33 | 45 | 76 | 97 | |||
47 |
这样,当咱们再想找33的时候咱们就能够直接把33对10进行整除得出3,而后对比数组中下标是3的那个元素就能够了。这样作的时间复杂度是O(1)。微信
看了上面的那个哈希表咱们能够发现,45和47经过对10整除这个算法的映射,结果都是4,这种状况被称为哈希冲突/散列冲突,也叫散列碰撞,反正无论怎么叫,是那个意思就对了。
在理想状况下,哈希函数(在这里就是对10整除这个算法)设计合理的话,可让不一样的值映射成不一样的结果,时间复杂度真正为O(1)。可是事实证实不管设计的哈希函数多么好,哈希冲突老是不可避免的,所以就须要咱们来解决哈希冲突。网络
解决哈希冲突最多见的方法有线性探测法(也叫开放定址法) 和 链地址法。
其实上面那个表中解决哈希冲突的方法有点链地址法的影子。下面仍是以上面的那个表为例子分别讲解一下这两种方法。数据结构
在上面的例子中,在插入45时经过哈希函数计算的映射值为4,而后查看下标4对应的地方是否有值,没有,因此将45插入到4的位置;在插入47时映射值也是4,查看下标为4的地方是否有值,有值,此时会向后面一个地址(或多个地址,具体视状况而定)进行探测,当探测到下标5没有值,则将47插入到5的位置,如果5的地方也有值,则继续向后探测。所以若是用线性探测法,上面那个哈希表应该是:app
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
9 | 16 | 28 | 33 | 45 | 47 | 76 | 97 |
为了让这个解释更形象,此次咱们换一组数据。将3二、8八、6五、7二、三、1八、9九、3七、4八、4二、5六、8一、十二、八、2四、2八、9二、69 用链地址法解决冲突插入到哈希表中。在这假设哈希函数为对6求余,则哈希表应为下:
在正经常使用法中,hash函数的设计主要有两个做用
要作到以上两点其实并不容易,尤为是第2点。hash 表的空间若是远大于实际存储数据的数量,则形成空间浪费;若是太小,又容易形成哈希冲突。针对hash表的大小通常有如下两种解决思路:
下面说一下常见的hash函数设计方法
直接定址法:
根据数据中的某些线性特征,如学生的学号,公司的工号等,直接拿来做为hash的地址。平方取中法:
能够将数据的某些数字进行平方运算,再取结果的中间的1~2位数做为hash地址。折叠法:
能够将数据中某串数字进行叠加做为hash地址,如18位身份证号,每两位看成一个数字,进行加法运算,运算结果取最后两位为hash地址。除留取余法:
若是知道了hash表的最大长度,则能够取不大于最大长度的最大质数做为除数,即hash(key) = key % x
,这里x很关键,若是取的好可以最大程度的减小冲突的概率,通常状况下是取不大于hash表长度的最大质数。目前著名的哈希算法有不少,好比:MD5,SHA1/256/512(加密强度不同)
,它们都是将任意长度的二进制数据映射成固定长度的二进制串。hash算法应具备如下一些特色:
原始值
经过哈希算法
的映射可以获得一个结果哈希值
,可是经过哈希值
并不能逆向推导出原始值
,即哈希算法不可逆。哈希冲突
发生的概率要很小。对于不一样的原始值,哈希值相同的几率应该很是小。数据敏感
。对于原始值,哪怕只有一个二进制位不同,计算出的哈希值也要大不相同。算法效率高
。哈希算法应具备高效计算的特色。对于很长的数据也应该快速计算出哈希值。hash算法的用途有不少,iOS系统就有不少地方用到了hash算法。这里简单说几个:weak的底层原理、关联对象(也就是常说的分类添加属性)底层、字典NSDictionary(经过上面就能发现hash和字典真的很像,快速查找),还有其余不少,有兴趣的能够看看这篇文章---->搞iOS的,面试官问Hash干吗?。
上面这些都是iOS系统中使用的hash,可是今天我要讲的不是这方面的,我要讲讲hash在加密这一块的用途。
在用户进行登陆注册操做时,在网络中直接传输明文帐号密码是很是危险的,黑客可使用Charles
等工具在网络拦截http请求,可以很轻易的就获取到用户帐号密码信息。为了保护用户的密码信息,咱们不得不和黑客进行一场攻防战。
开发者:
咱们为了避免让明文传输帐号密码,能够在登陆注册的时候将用户密码的md5值传输给服务器,服务器保存帐号和密码的md5值,这样黑客在拦截的时候他看到密码就是一串32个字符的16进制字符串。
黑客:
好,我拦截到了一串不知道的md5值,我本身算不出来,能够找其余人算,只要用户的密码强度不高,同样可以破解出来。
开发者:
就算用户本身设置的密码强度不高,我也同样可让它变成强度高的密码。加盐,在用户密码后面拼接一串很乱的字符串,如:a1df/H&OI)HF@,这样计算的md5值就算你请其余人也没法逆算出来。
黑客:
既然你加盐了,那我就分析你代码的二进制文件,找到那个字符串盐,只要有这个盐,我同样能够破解出密码。
开发者:
既然如此,那这个盐我不保存到程序中了,我在注册的时候就让服务器给我这个帐号分配一个盐(这种方案叫:Hmac),即给我这个设备受权。换设备登陆时我让服务器向已受权的设备询问是否容许给新设备受权。(说到这,你们应该都很熟悉了,QQ、微信登陆时都有相似这样的操做)。
黑客:
好吧,既然我获取不到用户的帐号密码,那么我摊牌了。我直接拦截你的登陆请求,我拦截到你发送的md5(密码+受权盐),我也无论你密码是啥,我就拿我拦截到的这个东西来登陆,同样能够登陆这个帐号。
开发者:
还能这样?既然如此,那我再加点东西,我在登陆以前向服务器要一下时间戳,我发送一个md5(md5(密码+受权盐)+202003131118)的东西(固然,时间戳不长这个样,为了更形象),服务器判断的时候只计算最近的两分钟的时间戳,以防止网络延时致使的问题。
黑客:
wc,一个登陆都搞的这么麻烦,我拦截到了数据还要破解,还要在两分钟内登陆?登陆以后我还不知道要花多少时间才能破解到其余的东西,不干了。碰、碰、哗啦(砸电脑、摔手机的声音)。
固然,若是黑客不计代价的想破解的话,他老是能找到其余办法破解的,可是也不能一直没完没了下去啊。咱们要作的就是让黑客花更多的时间破解,作不到绝对安全,但咱们能够作到相对安全。
这里我想到以前看的一个例子:有两个屋子,放着一样的东西,一个屋子所有用水泥盖的,门都是防盗门;另外一个屋子全是烂木头搭起来的,甚至连门都没安。你说若是你是黑客你选择哪一个屋子?
签名的做用是什么?老外喜欢用支票,他们在支票上签上本身的名字,那么就表明着这张支票就是他的,是有效的。签名的意义就不言而喻了吧?那么数字签名类推下来就是用来鉴别数字信息(二进制数据)的。
当咱们向服务器发送一条很关键的数据(特别是有关钱的)时,为了防止黑客在网络传输过程当中拦截篡改数据,咱们一般会对数据进行数字签名操做。以下:咱们将原始数据
进行md5哈希
获得一个32个字符的16进制字符串
,再将这个字符串进行RSA加密计算
,最后和原始数据拼接起来
一块儿发送到服务器。服务器拿到这个以后解密RSA
获得原始数据的md5
值,对比收到的原始数据
计算的md5值
,来验证原始数据
是否在传输过程当中被篡改。
有关RSA加解密原理
不懂的能够看我上一篇文章。
咱们都知道在app打包上架的过程当中须要配置证书和签名,其实原理也和上面相似(具体方案要比上面的那些复杂些),只是原始数据成了app打包的二进制数据。
上一篇文章说RSA非对称加密的时候提到过一些对称加密的特色,如加密和解密使用的密钥是同一个,所以被称为对称加密。下面说一下如今比较经典的对称加密算法。
/**
CCCrypt函数的参数说明
一、加密或解密,加密传kCCEncrypt,解密传kCCDecrypt
二、加密算法,AES/DES
三、ECB/CBC模式,kCCOptionPKCS7Padding为CBC模式,kCCOptionPKCS7Padding | kCCOptionECBMode为ECB模式
四、加密密钥的字节数组
五、加密密钥的大小
六、初始化向量IV的字节数组
七、原始数据的字节数组
八、原始数据的大小
九、加密结果要存放的地方
十、分块加密分的块的大小
十一、加密完成后的密文大小
*/
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
self.algorithm,
option,
cKey,
self.keySize,
cIv,
[data bytes],
[data length],
buffer,
bufferSize,
&encryptedSize);
NSData *result = nil;
if (cryptStatus == kCCSuccess) {
result = [NSData dataWithBytesNoCopy:buffer length:encryptedSize];
} else {
free(buffer);
NSLog(@"[错误] 加密失败|状态编码: %d", cryptStatus);
}
复制代码
本篇文章主要讲述了Hash(哈希)的概念、hash的数学原理、哈希冲突及解决方法、hash算法和算法的特色、hash的用途。用户密码加密方案HMAC(若不是太理解能够搜一下相关文章看看)、数字签名原理,应用签名。
另外由于对称加密内容很少,懒得再开一篇文章,就直接把经常使用对称加密Des,Aes的特色、加密模式、以及iOS系统提供的加密方法参数解释写到了这里。
本文地址。