本篇文章主要講解的內容有: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求餘,則哈希表應爲下:
固然,這裏只是爲了更加形象纔將哈希函數設置爲對6求餘,因此纔會有這麼多的碰撞。在這種狀況下,咱們若是要查詢24,則能夠將24對6求餘獲得0,而後到下標0對應的鏈表中去一個個找,在這裏咱們仍然須要找不少次,因此這個哈希函數設計的挺失敗的。在正經常使用法中,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系統提供的加密方法參數解釋寫到了這裏。
本文地址。