信息加密技術通過多年的發展,由一些基本算法組合造成了許多成熟的應用,如數字簽名,安全證書,HTTPS,以及最近大熱的數字加密貨幣,區塊鏈等。這些看似種類繁多的應用,其實都由三類基本的算法經過不一樣的組合來實現,這三類算法分別是: 數據摘要(在不少場合也被稱做哈希運算),對稱加密,非對稱加密。本文拋開這三類算法在不一樣實現方案中的差別,抽象出各種算法的共性,提綱挈領地描繪出三類算法在加密體系中的應用場景,讓開發者能在短期內對信息加密體系有個全局的認識,並能將這三類算法應用在實際的需求場景中,但願本文能成爲設計信息加密應用的簡要手冊。
閱讀建議:每類算法都以僞代碼給出函數聲明,不表明特定算法, 好比函數digest表明了在實際使用中的MD5, SHA1, RIPEMD160等實現了數據摘要功能的算法,讀者在閱讀過程當中不要急於去考慮這些函數的實現,而應該去領會算法的特色和完成的功能。這些算法幾乎在全部主流的編程語言庫中都有具體實現,實在有不多的場合須要本身再去實現。對於有研究技術細節需求的讀者,能夠在閱讀完本文後,對信息加密體系這棵樹有了全局的瞭解,再按圖索驥地去研究樹葉.
下面將分別介紹這三類算法各自的特性和應用, 而後再對將這些算法組合起來的應用進行介紹.
java
byte[] digest(byte[] data)
1.2.1. 不管data的長度爲多少,digest返回某必定長數據,一般爲幾十個字節
1.2.2. 若digest(data1) != digest(data2),則data1 != data2;若digest(data1) = digest(data2)則能夠認爲有很高的機率data1 = data2,在特定的狀況下,對某些算法來說,該判斷出錯的機率不到1/128^2。
1.2.3. 運算不可逆,即知道digest的返回值,不能反推出data的值。順便提一句,人們常提起的比特幣挖礦其實就是指經過不斷的嘗試找出一個data,使得digest(data)的結果小於某一個表示難度的數,其基本代碼以下:算法
while(digest(blockData + random()) > difficultyFactor); //random()在這裏產生隨機數
可見即便爲了獲得知足某一條件的data值,也只能經過暴力嘗試,而不能有其它快速的方法。
1.2.4. digest函數相對於下面要談的其它兩類算法來講,運算速度很是快。注意是相對的快,由於即使如此挖礦也是個很費時的運算,呵呵。編程
假設要作這麼一個文件上傳系統,要求上傳文件前,先檢測服務器上是否已經有一樣的文件存在,若是已經存在,則再也不上傳。若是沒有digest算法,只有把整個文件上傳到服務器再進行比較,這無疑很是費時。若是咱們每次上傳文件,都對文件作一次摘要運算(特性1.2.4:摘要運算速度很是快,相對於文件上傳的耗時來講忽略不計),並將摘要值保存起來;那麼下次上傳文件前咱們對將要上傳的文件進行一次摘要運算,只是把摘要值提交到服務器(特性1.2.1:摘要值通常只有幾十個字節), 服務器在以前保存的摘要值列表中查找客戶端新提交上來的摘要值,若是找到了(特性1.2.2),則告訴客戶端不用再上傳了。這就是不少雲盤使用的秒傳技術,不少上G的文件,只要幾秒鐘就上傳成功了,緣由就在於其餘人在你以前已經上傳過一樣的文件。瀏覽器
仍是上傳文件的例子,客戶端上傳前先把本地文件的摘要值傳給服務器,服務器在接收到完整的文件後,用一樣的摘要算法,計算接收到的文件的摘要值,和客戶端上傳的摘要值進行比較,若是相同則能夠認爲文件接收完整;反之則認爲文件在傳輸過程當中損壞(特性1.2.2)。安全
設計一個簡單的充值磁條卡,全部磁卡機都能讀磁卡中的數據,但只有受權的磁卡機才能合法地寫入數據。其數據寫入的過程以下圖所示:
寫入磁卡的數據分爲兩部分,一部分是明文數據;一部分是摘要數據。這裏的摘要數據有個術語叫簽名。簽名的生成過程很簡單,就是把密碼和明文數據拼接在一塊兒做爲digest函數的輸入,digest的輸出即爲簽名。受權的磁卡機讀取磁條數據時先要驗證簽名,即把磁條的明文數據讀入內存,而後和密碼按照寫入時一樣的過程生成一個簽名,把該簽名和磁條上記錄的簽名作對比,若是簽名同樣則認爲數據沒有被篡改,反之則認爲已經被篡改。磁條上任何一個字節的修改,都不能經過簽名驗證過程。由於非受權磁卡機在不知道密碼的狀況下,很難生成一個合法的簽名,雖然能讀取簽名,但也不能根據簽名推導出密碼(特性1.2.3).
注意:在實際生產環境中,大部分狀況下,簽名是在服務器端進行。爲了增強安全性,產生簽名時還會加入一個隨機數,隨機數和明文同樣寫入磁條,同時參加簽名驗證過程。同時也還能夠進行多遍摘要運算。這些措施都是爲了進一步增長經過試探僞造簽名的難度。
服務器
byte [] symEncrypt(byte[] plainData,byte[] password); byte [] symDecrypt(byte[] cipherData,byte[] password);
2.2.1. 加密和解密必須使用一樣的密匙。 2.2.2. 相對於非對稱加密速度快。
再也不贅述。
網絡
class KeyPair //密鑰對 { byte [] privateKey //私鑰 byte [] publicKey; //公鑰 }; KeyPair generateKeyPair();//用於產生一個密鑰對 byte[] asyEncrypt(byte[] plainData,byte[] publicKey); //用公鑰對數據加密 byte[] asyDecrypt(byte[] cipherData,byte[] privateKey); //用私鑰對公鑰加密的數據解密
3.2.1. 用公鑰加密的數據,只能由對應的私鑰解密。即他們都在由generateKeyPair產生的一個密鑰對(KeyPair)裏面。有時也用私鑰加密,公鑰解密。
3.2.2. 知道一個KeyPair的publicKey,以如今計算機的算力在短時間內沒法計算出它對應的privateKey。這個短時間指的是至少幾十年。
3.2.3. 非對稱加密一般比對稱加密慢不少。因此它一般只用來對密鑰或摘要加解密,而不會用在長數據上。dom
設計一個文件上傳系統,要求全部終端上傳的數據都通過加密,即便數據通過被竊聽的網絡,竊聽者也沒法獲知數據內容。若是使用對稱加密會發生什麼:
1. 全部終端和服務器共享一個祕鑰,任何一個終端泄露了祕鑰,數據傳輸將再也不安全。
2. 爲每一個終端分配一個祕鑰,服務器保存每一個終端的祕鑰,從不一樣終端來的數據使用對應終端的祕鑰來解密。這能夠解決一個終端泄密,致使整個系統泄密的問題。但一樣存在祕鑰泄露的風險。
這時候使用非對稱加密就解決了上面的全部問題。首先用generateKeyPair生成一個密鑰對(KeyPair),將KeyPair的publicKey分配給全部終端,將KeyPair的privateKey安全保存在服務器。終端上傳數據時使用asyEncrypt(byte[] plainData,byte[] publicKey)加密數據,服務器端用asyDecrypt(byte[] cipherData,byte[] privateKey)解密數據。由於公鑰加密的數據只能經過對應的私鑰來解密(特性3.2.1),因此數據即便在傳播途中被竊聽也是安全的,又由於特性3.2.2,即便全部人知道公鑰,私鑰也是安全的。
上述設計方案只是爲了演示非對稱加密方案的使用,在現實中通常不會這麼作,由於特性3.2.3,這樣會存在性能問題。因此通常會與對稱加密組合使用,咱們接着就要介紹這種用法。
編程語言
繼續上文的例子,因爲非對稱加密的速度很是慢,因此咱們考慮只用它來加密數據量小的一個臨時密鑰,用這個臨時密鑰來使用對稱加密的方法加密實際的通訊數據。終端向服務器發起通訊的流程大體以下:
1.終端生成一個隨機密碼:symPassword.
2.終端將這個隨機密碼使用非對稱加密加密,加密使用服務器對應的公鑰(publicKey)。asyEncrypt(symPassword,publicKey),並將這個加密後的結果發到服務器端。
3.服務器端使用私鑰進行非對稱解密asyDecrypt(encryptedSymPassword,privateKey),解密獲得symPassword.
4.終端使用symEncrypt(data,symPassword)對data進行加密,並將加密結果發送到服務器。
5.服務器使用symDecrypt(encryptedData,symPassword)對數據進行解密。
這個方案使用臨時的對稱加密密碼來進行數據的加密傳輸,因爲臨時密碼能夠在每次通訊創建時從新生成,因此不會有密碼泄露的風險。
函數
上文的加密通訊還有個問題沒有解決,就是服務器的公鑰如何發放到衆多的終端。若是隻是小範圍內使用,好比一個辦公室內部,能夠用U盤將服務器公鑰拷貝到每一個終端計算機上。但若是是一個公共網站,但願和全世界的全部用戶的通訊都是安全的,該怎麼發放服務器的公鑰呢?這將就要用到數字證書了。假定咱們要爲a.com的服務器發放一個證書,以下圖所示:
終端訪問a.com時,先下載上圖右邊所示的數字證書。通常證書是從a.com下載,但從其它地方下載也是安全的,由於數字證書要驗證後纔會使用。終端獲得證書後,就開始驗證它,驗證步驟以下:
1. 把上圖中證書下部的明文內容部分進行一次digest運算。
2. 根據明文內容中證書籤發者的信息,在本機查找並驗證證書籤發者的公鑰。(稍後詳述這一過程)
3. 用證書籤發者的公鑰,解密證書上部的數字簽名部分,使用asyDecrypt.
4. 將第3步的asyDecrypt結果和第1步的digest結果進行比較,若是同樣,則認爲證書合法;反之則說明證書非法或已損壞。
5. 若是證書合法,就能夠把明文內容中a.com的公鑰拿來使用了。
前面步驟的第2步具體怎麼操做的?注意到咱們實際上是要檢驗證書籤發者公鑰的合法性,咱們就須要一個關於證書籤發者公鑰的證書:
就這樣一環扣一環,造成了一個稱爲證書鏈的東西。這樣的循環何時結束呢?一直找到一個值得信任的證書或根證書。根證書是證書擁有者本身給本身簽發的證書。根證書怎麼驗證合法性?答案是不能,咱們選擇信任它。咱們爲何信任它,由於它是和操做系統或瀏覽器一塊兒發佈的。
在實際應用中,證書還有個過時的概念。這也是由非對稱加密的特性3.2.2.決定的,爲了防止通過較長時間的計算由某個簽發者的公鑰算出他對應的私鑰。
這其實是在HTTP協議的下層增長了由4.1和4.2組合成的加密通訊協議。先有4.2獲得網站的公鑰,再用4.1的方法傳輸HTTP數據。具體的實現不在本文討論的範圍。
不外乎也是本文討論的三類算法的組合應用,將在接下來的文章討論這個話題。