“攻城狮” 需要了解的密码知识
本人錄制技術視頻地址:https://edu.csdn.net/lecturer/1899 歡迎觀看。
1. 基本概述
我們在平時的工作中或多或少的都接觸過加密算法,比如:對稱加密,RSA加密算法。我們一般的操作就是上網查找相關的算法,分配自己項目相關的密鑰(實際處理中有可能叫Secret Key, APP key等),而對于加密算法本身沒有做過多的了解,本篇博客就向大家詳細的介紹加密知識,使得我們有一個更好的理解。
1.1 口令
不管是在PC或者是APP的登錄界面,我們都需要輸入“密碼”,嚴格來說,這里的“密碼”與密碼技術沒有任何關系。因為這里的“密碼”只是用戶記憶或者將其保存在一個地方,沒有涉及到任何的加密算法和密鑰,因此我們可以將登陸時候輸入的“密碼”稱作為口令(Password)。
1.2 編碼
編碼(Encoding)是信息從一種形式或格式轉換為另一種形式的過程。解碼(Decoding)是編碼的逆過程。從概念上可以看出,編碼只是表現形式的轉換,沒有保密的作用,因為編碼和解碼的算法是公開的,只要知道是什么編碼的內容,任何人都可以輕松地解碼。下面給大家介紹三種常用的編碼。
1.2.1 ASCII編碼
ASCII編碼使用指定的7 位或8 位二進制數組合來表示128 或256 種可能的字符。標準ASCII編碼也叫基礎ASCII編碼,使用7 位二進制數(剩下的1位二進制為0)來表示所有的大寫和小寫字母,數字0 到9、標點符號, 以及在美式英語中使用的特殊控制字符,點擊這里 可以查看具體的對照表。
char ch1 = 'a'; // ASCII 編碼對應 97char ch2 = 'b'; // ASCII 編碼對應 98int diff = ch2 - ch1; // diff 的值是1int result = (int)ch1; // 轉化為int的值就是971.2.2 Base64編碼
Base64編碼是從二進制到字符的過程,可用于在HTTP環境下傳遞較長的標識信息。標準的Base64并不適合直接放在URL里傳輸,因為URL編碼器會把標準Base64中的“/”和“+”字符變為形如“%XX”的形式。Base64編碼表如下表:
| 0 | A | 8 | I | 16 | Q | 24 | Y | 32 | g | 40 | o | 48 | w | 56 | 4 |
| 1 | B | 9 | J | 17 | R | 25 | Z | 33 | h | 41 | p | 49 | x | 57 | 5 |
| 2 | C | 10 | K | 18 | S | 26 | a | 34 | i | 42 | q | 50 | y | 58 | 6 |
| 3 | D | 11 | L | 19 | T | 27 | b | 35 | j | 43 | r | 51 | z | 59 | 7 |
| 4 | E | 12 | M | 20 | U | 28 | c | 36 | k | 44 | s | 52 | 0 | 60 | 8 |
| 5 | F | 13 | N | 21 | V | 29 | d | 37 | l | 45 | t | 53 | 1 | 61 | 9 |
| 6 | G | 14 | O | 22 | W | 30 | e | 38 | m | 46 | u | 54 | 2 | 62 | + |
| 7 | H | 15 | P | 23 | X | 31 | f | 39 | n | 47 | v | 55 | 3 | 63 | / |
從上圖我們可以看出:Base64的索引范圍是0~63,總計64個,而對應的字符分別是 [A-Z,a-z,0-9,+,/ ],總計64個字符,這也是Base64命名的由來。它的目的是任意的字符串,通過Base64編碼之后,只會出現這64個字符(Base64編碼之后有可能出現’=’, 這個字符后面再說明)組合而成的新的字符串。
情形一:字節個數正好是3的倍數
情形二:字節個數不是3的倍數
由“情形一”描述的Base64分割規則,我們可以總結出任意情況的Base64分割規則(當然包括字節個數不是3的倍數的情形)。
Note: 上述的兩個例子說明了不需要補充及補充一個字節的情況,還有一種情況是補充兩個字節,大家可以嘗試分析一下,比如字符串:“a@aa”。
從上面的分析,我們可以看出,Base64編碼處理之后,傳輸的字節數反而更多了,但是我們在實際的開發過程中隨處使用它,比如一般的HTTP[S] 發送請求之前,會進行一次Base64編碼操作,這是因為在網絡上交換數據時,比如說從A地傳到B地,往往要經過多個路由設備,由于不同的設備對字符的處理方式有一些不同,這樣那些不可見字符就有可能被處理錯誤,這是不利于傳輸的。所以就先把數據做一個Base64編碼,統統變成可見字符,這樣出錯的可能性就大大降低了。
1.2.3 霍夫曼編碼
霍夫曼編碼是一種十分有效的編碼方法,廣泛用于數據壓縮中,其壓縮率通常在 20%~90% 之間。
假設有一個包含 1000 個字符的文件,每個字符占 1 個 Byte(1Byte=8bits),存儲這 1000 個字符就一共需要 8000bits,那有沒有更加節省空間的存儲方式呢?
思路一:
假設我們通過統計分析發現,這 1000 個字符中只包含 6 種不同字符,假設它們分別是 a、b、c、d、e、f。而 3 個二進制位(bit)就可以表示 8 個不同的字符,所以,為了盡量減少存儲空間,每個字符我們用 3 個二進制位來表示。那存儲這 1000 個字符只需要 3000bits 就可以了,比原來的存儲方式節省了很多空間。a(000)、b(001)、c(010)、d(011)、e(100)、f(101)
思路二:
我們不僅考察文本中有多少個不同字符,還會考察每個字符出現的頻率,根據頻率的不同,選擇不同長度的編碼,假設這1000 個字符中只有a、b、c、d、e、f,并且各自出現的頻率如下圖:
圖中,第一列表示字符、第二列表示出現的次數、第三列表示使用的編碼、第四列表示占用的二進制位數。上述中使用的編碼其實就是霍夫曼編碼。a(1)、b(01)、c(001)、d(0001)、e(00001)、f(00000)。通過統計,存儲這 1000 個字符只需要 1910bits 就可以了,可以看出壓縮比例是76%左右。
霍夫曼編碼的中心思想就是:統計字符出現的頻率,頻率越高,編碼比特數越少;頻率越低,編碼比特數越多。而且要求任意一個編碼不能是另一個編碼的前綴(這樣要求的目的就是防止編碼結果產生歧義,導致無法解碼)
任意一個霍夫曼編碼的結果 都可以使用一個霍夫曼樹(二叉樹)來表示。對于上述例子的霍夫曼樹如下圖:
圖中橙色的節點就是需要編碼的字符(他們在霍夫曼樹中全都是葉子節點),而黃色的節點全部是輔助節點,是為了構建霍夫曼樹臨時生成的。我們發現,編碼的時候,將指向左子樹的權重全部編碼為0,而指向右子樹的權重全部編碼為1。以字符’d’為例,從根節點出發,走過的節點分別是p、k、z、y、d,而對應的權重編碼是0、0、0、1,所以字符’d’的編碼是 0001。全部編碼結果就是a(1)、b(01)、c(001)、d(0001)、e(00001)、f(00000)。當然,左右子樹上面的權重可以自定義,假設將指向左子樹的權重全部編碼為1,而指向右子樹的權重全部編碼為0,則全部編碼結果就是a(0)、b(10)、c(110)、d(1110)、e(11110)、f(11111),也是正確的,因為他們并不影響最終編碼的比特數。
上面就是霍夫曼編碼的整體邏輯,由于使用霍夫曼樹能夠大大減少傳輸量,所以霍夫曼樹又稱為最優二叉樹。如果要代碼實現,有兩種思路:
一、 隊列構建霍夫曼樹
首先根據字符出現的頻率,有低到高放入隊列中,然后先將隊列前面兩個元素(f、e)出隊,將他們的結果相加構成新的節點(x),而x節點的值就是f、e節點值的和 (50),這一輪計算完畢后,刪除剛才用于計算的節點f、e,并且將節點x放入隊列中,升序排列,循環前面的操作,直到隊列為空位置。 實現思路如下圖:
二、數組構建霍夫曼樹,這里就不展開敘述了。
Note: 如果對Base64編碼及霍夫曼編碼的具體實現感興趣的話,歡迎查看我錄制的《算法攻略》視頻,里面有詳細的C語言代碼實現。
1.3 密碼
加密(Encrypt)相關的內容:對稱加密、公鑰加密、混合加密、單向散列函數、消息認證碼、數字簽名、證書及 Diffie-Hellman。其中加密之前的消息稱為明文(plaintext),加密之后的消息稱為密文(ciphertext),與明文一起參與加密算法的稱之為密鑰(key),加密的反向過程稱之為解密(Decrypt)。
加密及解密的大致流程如下入:
在詳細說明這些密碼知識之前,我們先了解一下密碼常識:
一、不要使用保密的密碼算法
這一點有悖于大家的認知。人們一直認為,公司自己設計一套加密算法,私鑰公司自己保存,那么別人就無法破解。其實這是一個很嚴重的錯誤。如果某個員工泄露或者公司核心員工離職而導致加密算法及密鑰泄露,那么可想而知,公司設計的加密算法等于形同虛設。反而那些公開加密算法并且給出詳細設計清單的公認加密算法(AES,RSA)才是可靠的,安全的。因為這些加密算法,是經過眾多密碼學家嘗試破譯(最終失敗)及眾多數學家證明很難逆向反推。
二、 使用低強度的密碼比不進行任何加密更危險
對于客戶而言,加密意味著安全。如果內容沒有一點機密性可言,客戶直接可以選擇不加密。反之,對于重要的內容,會進行加密,但是如果密碼強度很低的話,很容易被破解,這樣不利于數據信息的安全性。所以要么選擇密碼強度高的加密算法,要么不加密。
三、 任何密碼總有一天都會被破解
鴿巢理論:10只鴿子放進9個鴿籠,那么一定有一個鴿籠放進了至少兩只鴿子。
假設RSA密碼算法的密鑰長度是512bits,那就有2512 種可能。也許大家對這個數字沒有具體的概念,我們舉例說明:假設我們想暴力破解這個密鑰,需要的條件大致如下:
Note: 宇宙的年齡是1011年左右。
根據上述條件,計算的結果是3.16224 * 10154, 而2512 大致結果是 1.340780 * 10154。 所以當達到上述條件的時候,能夠遍歷一遍512位的RSA密鑰空間,可想而知破解難度,但隨著科技的發展,后續也許會有重大突破,破解的速度可能更快。但不管加密算法多么的復雜,任何密碼總有一天都會被破解。
四、密碼只是信息安全的一部分
我們所說的加密操作都是保證數據在傳輸過程中的安全性,而信息安全還包括很多的其他的層面。比如:密鑰被惡意破壞的人發現并且泄露、密鑰被其他人騙取等。所以除了傳輸過程中的信息安全交給加密算法處理,其他的還需要人為約束,制度規范等。
2.對稱加密
對稱加密,采用這種加密方法的雙方使用同樣的密鑰進行加密和解密(加密方和解密方是共享密鑰的)。
2.1 常用對稱密碼
對稱加密的方式有很多,比較流行的有DES(Data Encryption Standard)、三重DES(Triple Data Encryption Standard),但由于實踐證明,DES和三重DES已經不安全,可以在可觀的時間內被破解。所以現在主流的對稱加密是 AES(Advanced Encryption Standard)。AES是公開競選的,參加競選的條件就是:被選為AES的密碼算法必須無條件地免費供全世界使用。參加者所提交的密碼算法,必須在詳細設計和程序代碼完全公開的情況下,依然保證較高的強度。密碼算法的評審不是由某個組織或者評委來完成的,而是由全世界的企業和密碼學家共同完成的,其中包括AES競選的參賽者。一旦被找到弱點,意味著該密碼算法落選。在眾多的參加者中,最終選擇了Rijndael(是由比利時密碼學家Joan Daemen 和 Vincent Rijmen 設計的分組密碼算法)作為AES。如果大家對AES的具體算法感興趣的話,請點擊這里。
2.2 對稱密碼的設計
下面就Rijndael 的加密和解密進行說明。
Step1: SubBytes
Rijndael的輸入分組為128bits,是16Bytes。首先進行的就是SubBytes處理,也就是以每個字節的值為索引,從一張擁有256個值的替換表找出對應的值,也就是說,要將一個1字節的值替換為另一個1字節的值。
Step2: ShiftRows
這一步是將以4字節為單位的行按照一定的規則向左平移,且每一行平移的字節數是不同的。
Step3: MixColumn
這一步是對一個4字節的值進行比特運算,本質就是進行矩陣運算,得到另一個4字節的值。
Step4: AddRoundKey
上圖中的XOR表示異或運算,以"k" 表示的數據是每一輪的密鑰。因此這一步的操作就是將MixColumns的輸出與輪密鑰進行異或運算。
上面的四步操作就是Rijndael的一輪操作,實際上,Rijndael中需要重復進行10 ~ 14 輪計算。
2.3 AES密鑰配送
雖然說AES加密算法本身很難破解,但是存在一個致命的問題,就是密鑰怎么配送。
1. 事先共享密鑰
舉個例子,一個公司有100名員工,每個員工都有自己的密鑰。員工兩兩之間需要使用對稱加密消息進行通信,比如A需要與B通信,則A將自己的私鑰告訴B,B將自己的私鑰告訴A;則每個員工需要999個通信密鑰,整個公司的密鑰數量就是1000 * 999 / 2 = 499500個,這個顯然不現實。實現共享密鑰雖然有效,但局限性依舊很明顯。
2. 通過密鑰配送中心來解決
事先準備一臺充當密鑰配送中心的計算機。這臺計算機中保存了所有員工的密鑰,對上述問題來說,需要保存的密鑰有1000個。這種方式的通信大致如下:
以上就是通過密鑰分配中心完成的通信過程。顯然能夠完成通信,但存在很大的局限性。1. 所有密鑰的保存及會話密鑰的生成全部由密鑰分配中心完成;2. 如果密鑰分配中心被入侵,則所有信息都會被泄露。
3. 通過Diffie-Hellman 密鑰交換來解決密鑰配送問題
4. 通過公鑰密碼來解決密鑰配送問題
其中,第3、4點會在后面的內容中進行詳細的說明。
3.公鑰加密
3.1 基本概念
在對稱密碼中,加密和解密使用的是同樣的密鑰,即加密和解密只是同一密鑰進行相反的運算而已。而公鑰加密,加密和解密使用的是不同的密鑰。并不是相互對稱的,因此公鑰加密也稱為非對稱加密。在公鑰加密中的密鑰是由接受者自己生成的密鑰對 [公鑰(Public Key)和 私鑰(Private Key) ],其中,接受者將公鑰可以通過任意方式發送給發送者,相對的,私鑰只能由接受者自己保管。公鑰和私鑰是一一對應的,由公鑰加密的密文,必須使用與該公鑰配對的私鑰才能夠解密。
3.2 公鑰加密流程圖
網絡傳輸過程中,假設有攻擊者劫持相關信息。能夠截獲到的信息:1. B的公鑰;2. A發送的密文。但是劫持者沒有B的私鑰,所以沒有辦法獲取到A發送的明文信息,所以公鑰加密解決了對稱加密需要配送密鑰的問題。但是上述傳輸還是會出現問題,這個問題就是中間人攻擊。
中間人攻擊:我們假設中間人是C。在B將自己的公鑰發送給A的過程中,C將這條請求攔截,C將B的公鑰保存下來,同時C將自己的公鑰發送給A;然后A用得到的公鑰進行加密(A以為接受到的是B的公鑰,其實是C的公鑰),將密文發送給B(假設A發送的明文是"I love you"),此時又被C攔截下來,C用自己的私鑰進行解密,就可以得知A發送的明文內容是"I love you"。然后C用截獲到的B的公鑰加密內容(假設C發送的明文是"I hate you")發送,B接受到密文之后,用自己的私鑰進行解密。發現接受到的內容是"I hate you"。至此A與B就誤會下去了。
通過上述的說明,我們發現:公鑰加密本身是可以保證機密性的,而且公鑰加密解決了密鑰配送的問題,但是它不能確認收到的公鑰是否真的是想要的通信對方發送過來的,這種情況,我們就需要對公鑰進行認證,關于認證,后續會詳細說明。
3.3 RSA
RSA是一種公鑰加密算法(現在市面上幾乎都是用這種公鑰加密算法),它的名字是有它的三位開發者的姓氏的首字母組成的(Rivest-Shamir-Adleman), RSA可以被用于公鑰加密和數字簽名(后面會講解)。下面我們看看公鑰加密的代表 - RSA加密解密過程(RSA加密解密表達式很簡單)。
RSA加密可以直接用公式表達:
密文 = 明文E mod N
RSA的密文是明文的E次方除以N求余數。其中E和N的組合就是公鑰。
RSA解密可以直接用公式表達:
明文 = 密文D mod N
RSA的明文是密文的D次方除以N求余數。其中D和N的組合就是私鑰。
那上述加密解密中提到的E,D及N到底是怎么得來的,我們畫圖進行說明。
下面我們來分析一下為什么RSA算法不容易被攻擊。
RSA加密公式是:
密文 = 明文E mod N
而且(E, N) 就是公鑰,并且他們是已知的,加密之后的密文也是已知的。破解的問題其實就是已知密文、E、N求解明文。但是這種計算實質是求解離散對數的問題,這是非常困難的,因為人類還沒有發現求離散對數的高效算法。
4. 混合密碼系統
通過使用對稱密碼,我們能夠在通信中確保機密性。然而要在實際中運用對稱密碼,就必須解決密鑰配送的問題。而公鑰密碼就可以解決密鑰配送的問題。但是公鑰密碼的處理速度遠遠低于對稱密碼。所以可以考慮將這兩種加密方式結合起來。
混合密碼系統中會先使用快速的對稱密碼來對消息進行加密,這樣消息就被轉化為密文,從而保證了消息的機密性。然后使用公鑰密碼對加密消息時使用的對稱密碼的密鑰進行加密。由于對稱密碼的密鑰一般比消息本身要短,因此公鑰密碼速度慢的問題就可以忽略了。我們日常所使用的HTTPS,就是使用的混合密碼系統。混合密碼系統的加密流程圖如下:
混合密碼系統的解密就是一個逆過程:首先使用私鑰解密,得到會話秘鑰;再用會話密鑰解密,得到明文。
5. 單向散列函數
5.1 基本概念
我們知道,對稱加密和公鑰加密能保證消息的機密性,但是不能保證消息是否被篡改或者被偽造,也就是不能檢查消息的完整性。而單向散列函數可以根據消息的內容計算出散列值,而散列值就可以被用來檢查消息的完整性。單向散列函數(one-way function)有一個輸入和一個輸出,其中輸入稱為消息(message),輸出稱為散列值(hash value)。
消息可以是文本、圖像、聲音等文件,單向散列函數不需要知道消息實際代表的含義。無論任何消息,單向散列函數都會將它作為單純的比特序列來處理。散列值的長度和消息的長度無關。無論是1bit,還是100M,或者是10G,單向散列函數都會計算出固定長度的散列值。
5.2 單向散列函數的性質
5.2.1 任意長度的消息計算出固定長度的散列值
單向散列函數必須能夠輸入任意長度的消息。無論輸入多長的消息,都能夠產生長度很短的而且長度固定的散列值,如果消息越長生成的散列值也越長的話,就不好用了。
5.2.2 能夠快速計算出散列值
計算散列值所花費的時間必須要短。盡管消息越長,計算散列值的時間也會越長,但如果不能再現實的時間內完成計算就沒有意義了。
5.2.3 消息不同散列值也不同
為了能夠確認完整性,消息中哪怕只有1bit 的改變,也必須有很高的概率產生不同的散列值。兩個不同的消息產生同一個散列值的情況稱為碰撞(有的地方稱為哈希沖突)。如果要將單向散列函數用于完整性的檢查,則需要確保在事實上不可能被人為地發現碰撞。事實證明,碰撞的概率可以忽略不計。
弱抗碰撞性:要找到和該消息具有相同散列值的另外一條信息是非常困難的。
強抗碰撞性:要找到散列值相同的兩條不同的消息是非常困難的。
5.2.4 具備單向性
單向性是指無法通過散列值反算出消息。大致如下圖所示。
5.3 單向散列函數的實際應用
5.3.1 檢測文件是否被篡改
我們應該都有過下載軟件下載完畢之后,發現不是自己想要的內容的經歷;或者下載電影,下載到99%而下載不了的問題。這里面有很大的因素是想要下載的內容,被人篡改或者替換了。而正規的軟件下載,軟件提供商會提供被下載軟件的散列值,用戶在下載之前,可以先用單向散列函數計算軟件的散列值,然后使用這個散列值與官方提供的散列值進行比較,就能知道是否是真正的需要下載的軟件了。
5.3.2 消息認證碼
5.3.3 數字簽名
關于 消息認證碼 和 數字簽名 會在后續內容進行講解。
5.3.4 具體例子
MD5 (MD: Message Digest,即消息摘要)是由 Rivest 在1991 年設計的單向散列函數,能夠產生128bits 的散列值。MD5的抗碰撞性已經被攻破,也就是說,現在已經能夠產生具備相同散列值的兩條不同的消息,因此它也已經不安全了。后續又出現了很多的單向散列函數,比如: SHA-1、SHA-256、SHA-384、SHA-512(SHA: Secure Hash Algorithm)。后來最出名的是SHA-3。SHA-3 和 AES 一樣,都是通過公開競選產生的,最終認定 Keccak 為 SHA-3 標準的單向散列函數。
6. 消息認證碼
6.1 基本概念
確認消息的機密性,我們可以使用對稱加密、公鑰加密;確認消息的完整性,我們可以使用單向散列函數。
但我們前面也提到了中間人攻擊,之所以會出現中間人攻擊,就是攻擊者可以偽裝成消息的發送者,而我們不能進行認證。消息認證碼(Message Authentivation Code)是一種確認完整性并進行認證的技術。
消息認證碼的輸入包括任意長度的消息和一個發送者與接受者之間共享的密鑰,它可以輸出固定長度的數據,這個數據稱為MAC值。單向散列函數中計算散列值時不需要密鑰,相對的,消息認證碼中則需要使用發送者和接受者之間共享的密鑰。要計算MAC值必須持有共享密鑰,沒有共享密鑰就無法計算MAC值,消息認證碼正是利用這一性質來完成認證的。因此我們可以說:消息認證碼是一種與密鑰相關聯的單向散列函數。
6.2 消息認證碼的使用步驟
我們還是以畫圖的形式來分析一下消息認證碼的整體流程。
消息認證碼之所以工作,是因為通信雙方有共享的密鑰。因為只有根據共享的密鑰才能夠計算出正確的MAC值。從上圖可以看出,消息認證碼并沒有保證機密性,消息是明文傳遞的,但是它可以保證完整性及完成認證工作。為了確保共享密鑰的安全性,我們可以對共享密鑰進行公鑰加密或者進行 Diffie-Hellman運算(后續會講解到)。
6.3 對消息認證碼的重放攻擊
消息認證碼雖然可以確認消息的完整性及可以認證通信的對方,但如果處理不當,有可能出現重放攻擊。
重放攻擊:我們舉一個例子進行說明,假設有A銀行及B銀行,而攻擊者C在A、B銀行都有自己的賬號。
整個過程中,C并沒有破解消息認證碼,而只是將A銀行的正確MAC值保存下來重復利用而已。這種攻擊方式稱為 重放攻擊(Replay Attack)。
防止重放攻擊的方式有很多。
6.4 消息認證碼無法解決的問題
1. 對第三方證明
假設通信的雙方是A和B,現在要對C進行證明。那么C必須校驗MAC值,由于計算MAC值的密鑰在A和B那里,所以C也就無法計算出正確的MAC值了。假設A非常信任C,將密鑰值告訴C,此時C是可以計算出正確的MAC值了,但是能夠提供MAC值的有A和B兩者,依舊不能說明消息是A提供的還是B提供的。
2. 防止否認
由于A和B都能對消息進行消息驗證碼處理,所以都可以得出MAC值,如果此時C想問消息到底是誰發出的從而去追究責任,A和B完全都可以矢口否認,認定是對方發出的。因為能夠計算出正確MAC值的有A和B兩者,無法進行確認。
為了解決上述問題,我們可以使用數字簽名來解決。
7. 數字簽名
7.1 基本概念
通過消息認證碼,我們可以識別消息是否被篡改或者發送者身份是否被偽裝,也就是可以校驗消息的完整性,還可以對消息進行認證。然而,消息認證碼無法防止否認。之所以無法防止否認,是因為消息認證碼需要在發送者和接受者之間共享一個密鑰。現在我們假設發送者和接受者之間不共享密鑰,那就可以防止否認了。發送者發送消息時,使用自己的私鑰生成一個簽名,相對的,接受者則使用和發送者配對的公鑰對簽名進行認證。這就是數字簽名。
生成數字簽名這一行為是由消息的發送者來完成的,也叫“對消息簽名”,驗證數字簽名這一行為一般由消息的接受者來完成,當然驗證可以由任何人完成,只要認證的人持有用于認證的鑰匙。這樣看來,數字簽名和公鑰加密很像! 公鑰加密中,密鑰分為加密密鑰和解密密鑰,用加密密鑰無法進行解密,解密密鑰只能由需要解密的人持有。而加密密鑰則是任何需要加密的人都可以持有。而數字簽名就是通過將公鑰密碼“反過來用”而實現的。下面的表格說明了公鑰密碼和數字簽名的使用。
| 公鑰密碼 | 接受者解密時使用 | 發送者加密時使用 |
| 數字簽名 | 簽名者生成簽名時使用 | 驗證者驗證簽名時使用 |
| 誰持有密鑰? | 個人持有 | 只要需要,任何人都可以持有 |
7.2 數字簽名的流程
我們了解了公鑰加密和數字簽名,公鑰加密是使用公鑰進行加密,私鑰進行解密;而數字簽名是使用私鑰進行簽名,公鑰進行驗證。假設明文是content, 加密函數是 E, 解密函數是 D, 則根據公鑰加密的定義可得出 D(E(content)) = content. 而數字簽名是逆運算,則有E(D(content)) = content. 正是得益于這個可逆解的數學公式,我們可以實現數字簽名。下面我們看看數字簽名的流程圖。
數字簽名過程中,很多人可以進行認證,而數字簽名的私鑰只有發送者自己才有。所以可以有效的防止否認。
7.3 對數字簽名的質疑
1. 為什么可以直接對明文進行數字簽名?
在【數字簽名的流程圖】中,我們看出消息是直接發送出去的,可以不需要加密,因為數字簽名的職責是進行認證,而不是保證消息的機密性。
2. 數字簽名可以被任意復制嗎?
簽名可以被復制。并不意味著簽名就沒有意義,因為簽名所表達的意義是特定的簽名者對特定的消息進行了簽名,即便簽名被復制,也并不會改變簽名者和消息的內容。
3. 簽名會不會被重復使用?
在獲得簽名之后,將相關信息提取出來。然而在數字簽名中,簽名和消息之間具有對應關系,消息不同,簽名的內容也會不同,因此事實上是無法做到將簽名提取出來重復使用的。
4. 刪除簽名也無法作廢嗎?
的確,帶有數字簽名的內容即便刪除掉也無法作廢,要作廢帶有數字簽名的內容:1. 根據新的內容,重新創建數字簽名; 2. 在消息中申明該消息的有效期(證書就是這么處理的)。
8. 證書
8.1 基本概念
證書就是將某人或者某個組織的相關信息(包括公鑰), 由認證機構(Certification Authority, CA)施加數字簽名。只要看到證書,我們就可以知道認證機構認定該公鑰的確屬于某人或者某個組織。從基本概念可以看出,證書其實就是對公鑰的認證,因此又稱為公鑰證書,簡稱證書。
在公鑰加密那一節提到中間人攻擊(攻擊者針對發送者冒充接收者,針對接收者冒充發送者,用自己的公鑰進行欺騙,最根本的原因就是發送者和接收者不能確定接收到的公鑰是否真的是想要通信的對方發送過來的)。而證書就是為公鑰加上數字簽名,成功的解決了中間人攻擊的問題。
證書的大致處理流程如下圖:
8.2 證書規范
證書是由認證機構頒發的,使用者需要對證書進行驗證,如果證書的規范不統一,那使用起來就會非常的不方便,所以人們指定了X.509規范,現在很多應用程序都支持X.509并將其作為證書生成和交換的標準規范。X.509證書所包含的構成要素大致如下:
| 證書序列 | S/N: 4233232BC543333A563993B09234222A |
| 證書頒發者 | Issuer: CN=China History Department CA,… |
| 公鑰所有者 | Subject: … aka: alphapkbeta@163.com |
| SHA-3 指紋 | sha3_fpr: 32:45:3C:56:B1:09:21:D5:4C… |
| MD5指紋 | md5_fpr: 34:12:B9:0A:4C:37:D9… |
| 證書ID | certid: 123124325454325BA4334556c566d2222a344 |
| 有效期(起始時間) | notBefore: 2019-05-01 00:00:00 |
| 有效期(結束時間) | notAfter: 2022-05-01 00:00:00 |
| 散列算法 | hashAlgo: 1.2.840.113549.1.1.5(shalWithRSAEncryption) |
| 密鑰類型 | keyType: 2048 bit RSA |
| 密鑰ID | subjectKeyId: 5234234234A5545BCCC2234D54330 |
| 密鑰用途 | keyUsage: digitalSignature keyEncipherment |
X.509有多種常用的擴展名,常用的如下:
| .cer, .crt, .der | 通常是DER二進制格式的,但Base64編碼后也很常見 |
| .pem | (隱私增強型電子郵件)DER編碼的證書再進行Base64編碼的數據存放在"-----BEGIN CERTIFICATE-----“和”-----END CERTIFICATE-----"之中 |
| .p7b, .p7c | –PKCS#7 SignedData structure without data, just certificate(s) orCRL(s) |
| .p12 | –PKCS#12格式,包含證書的同時可能還有帶密碼保護的私鑰 |
| .pfx– PFX | PKCS#12之前的格式(通常用PKCS#12格式,比如那些由IIS產生的PFX文件 |
8.3 認證機構(CA)
認證機構是對證書進行管理的人,它的主要職責:
前面兩步我們已經在【基本概念】中進行了說明,現在我們看看“作廢證書”。當用戶的私鑰丟失、被盜時,認證機構需要對證書進行作廢。此外,即便私鑰安然無恙,有時候也需要作廢證書,例如用戶從公司離職導致其失去私鑰的使用權限,或者是名稱變更導致和證書中記載的內容不一致等情況。
紙質證書只要撕毀就可以作廢了,但是這里的證書是數字信息,即便從倉庫中刪除也無法作廢,因為用戶會保存證書的副本,但認證機構又不能入侵用戶的電腦將副本作廢。要作廢證書,認證機構需要制作一張證書作廢清單(Certificate Revocation List),簡稱 CRL。
假設我們手中有某個證書,該證書有合法的認證機構的簽名,而且也在有效期內,但僅憑這些還不能說明該證書一定是有效的,還需要查詢認證機構最新的CRL,并確定證書是否有效。一般來說,這個檢查不是由用戶自身來完成的,而是應該由處理證書的軟件來完成。
9. Diffie-Hellman
在進行對稱加密的時候,我們需要進行密鑰配送,主要有兩種方案:1. 密鑰配送中心; 2. 公鑰加密。
使用密鑰配送中進行密鑰配送,當時進行了詳細的流程說明,它不僅流程復雜,還需要經過配送中心進行中轉。使用公鑰加密進行配送是一種不錯的選擇,發送者使用接收者的公鑰加密對稱加密的密鑰發送給接收者,接收者再使用自己的私鑰解密,便可以得到對稱加密的密鑰。這一節,介紹另一種可以解決對稱加密密鑰配送的方案:Diffie-Hellman。
Diffie-Hellman密鑰交換是一種算法,通信雙方僅通過交換一些可以公開的信息就能夠生成出共享的秘密數字,而這一秘密數字就可以被用作對稱密碼的密鑰(IPsec中就使用了經過改良的Diffie-Hellman密鑰交換)。雖然這種方法的名字叫做“密鑰交換”,但實際上雙方并沒有真正交換密鑰,而是通過計算生成出了一個相同的共享密鑰。因此,這種方法也稱為Diffie-Hellman密鑰協商(Diffie-Hellman key agreement)。交換的示意圖大致如下:
通過上述的操作,通信雙方得到的對稱加密的密鑰就是 GAB mod P,然后就可以使用這個密鑰加密傳輸通信內容了。
上述操作步驟中,能夠截獲到的信息是P、G、GA mod P、GB mod P;但是根據這四個值,計算出GAB mod P就非常困難了,其實這里求解的難度就是已知P、G、GA mod P 求解A的值,因為這又是離散對數求解的問題,而我們在前面講解過的RSA加密算法也是使用的這個數學理論知識,由于有效的計算離散對數的方案至今沒有被發現,所以他們是安全的。
10. 實際案例
回顧一下,我們講解了:編碼知識、對稱加密、公鑰加密、單向散列函數、消息認證碼、數字簽名、證書、Diffie-Hellman。而實際的軟件開發過程中,使用這些知識點的地方太多了,這里我們選取 “git”、“bitcoin”、“HTTPS” 進行說明。
1. SSH key
我們在實際的開發過程中,幾乎都在使用git進行版本管理控制。剛開始使用git的時候,每次的操作步驟都需要輸入賬號及密碼,那是因為需要進行身份的確認。但是每次操作如果都輸入賬號及密碼,那就太麻煩了,我們有必要使用SSH key進行身份的認證。處理的大致步驟如下:
通過以上步驟,其實就已經根據用戶名及密碼,產生了對應的 “密鑰對”,然后可以查看具體產生的 “密鑰對”,結果如下圖:
其中 “id_rsa” 是私鑰,“id_rsa.pub” 是公鑰,私鑰是自己保存在電腦里面的,不需要也不能透露給任何人,而公鑰是要發送給git服務器的。產生的公鑰的大致內容如下:
完成上述所有步驟后,自己會持有私有,git服務端會保存公鑰。每次在進行代碼的push,pull等操作的時候,會使用自己的私鑰進行數字簽名,而服務端會使用對應的公鑰進行認證,如果認證通過,則順利的進行相關的操作,再也不需要每次都輸入賬號及密碼了。
2. Bitcoin
Bitcoin 中文稱為比特幣,是一種虛擬貨幣。比特幣可以脫離物理介質,僅通過互聯網就可以流通。比特幣的實現基于一個自稱 中本哲史 的不明身份的人所發表的一篇論文。
比特幣交易是在比特幣地址之間完成的。假設A要從B商店購買商品,并通過比特幣來支付,流程如下:
比特幣中使用的地址是由公鑰的散列值生成的。其中公鑰用于接收比特幣,而私鑰用于支付比特幣。
區塊鏈:區塊鏈就是保存比特幣全部交易記錄的公共賬簿。
全世界使用比特幣進行的所有交易都被記錄在這一本公共賬簿中。顧名思義,區塊鏈就是將交易以區塊為單位組織起來的。
一個區塊是由若干條交易以及一個區塊頭所組成的,區塊頭中保存了“上一個區塊頭的散列值”(其中區塊頭2中保存的散列值H2就是根據它前面的區塊1的區塊頭1計算出來的);區塊頭中還保存著 “本區塊所有交易的整體散列值”(其中區塊頭2的散列值T2就是根據區塊2中記錄的所有交易數據計算出來的散列值)。
3. HTTPS
HTTPS是本篇博客講解的密碼知識應用的知識點最多的一個代表。HTTPS能保證通信的安全性,本質是依賴于 SSL/TLS。這里講解的是HTTPS,如果對HTTP感興趣的話,可以查看我的另一篇博客 《HTTP連接管理》。
SSL/TLS 中綜合運用了對稱密碼、消息認證碼、公鑰密碼、數字簽名、偽隨機數生成器等密碼技術,嚴格來說,SSL(Secure Socket Layer) 與 TLS(Transport Layer Security) 是不同的,TLS相當于是SSL的后續版本,TLS是IETF在SSL 3.0的基礎上設計的協議,相當于SSL 3.1。
SSL/TLS 可以承載 HTTP 通信,發送郵件使用的SMTP和接收郵件使用的POP3都可以使用SSL/TLS進行承載。在這樣的情況下,SSL/TLS就可以對收發的郵件進行保護。
SSL/TLS 提供了一種密碼通信的框架,這意味著 SSL/TLS 中使用的對稱密碼、公鑰密碼、數字簽名、單向散列函數等技術,都是可以像零件一樣進行替換的。也就是說,如果發現現在使用的某個密碼技術存在弱點,那么只要將這一部分進行替換就可以了。盡管如此,也并不是說所有的組件都可以自由選擇。由于實際進行對話的客戶端和服務端必須使用相同的密碼技術才能進行通信,因此如果選擇過于自由,就難以確保整體的兼容性。為此,SSL/TLS 就像事先搭配好的盒飯一樣,規定了一些密碼技術的 “推薦套餐”,稱之為 密碼套件。
在《HTTP連接管理》這一篇博客里,我講解了HTTP的握手協議,現在我們來看看HTTPS的握手協議,而HTTPS安全性是依賴于SSL/TLS的,所以HTTPS的握手協議本質上是 SSL/TLS 的握手協議。
以TLS為例,TLS協議的層次結構如下圖:
TLS記錄協議位于TLS握手協議的下層,是負責使用對稱密碼對消息進行加密通信的部分。TLS記錄協議中使用了對稱密碼和消息認證碼,但是具體的算法和共享密鑰則是通過后面將要介紹的握手協議在服務端和客戶端之間協商定的。
TLS握手協議分為4個子協議:握手協議、密碼規格變更協議、警告協議和應用數據協議。
握手協議 是TLS握手協議的一部分,負責在客戶端和服務端之間協商決定密碼算法和共享密鑰。基于證書的認證操作也在這個協議中完成。它是4個子協議中最復雜的一個。后面單獨進行詳細的說明。
密碼變更協議是TLS握手協議的一部分, 負責向通信對象傳達變更密碼方式的信號,當協議中途發生錯誤時,就會通過下面的警告協議傳達給對方。
警告協議是TLS握手協議的一部分,警告協議負責在發生錯誤時將錯誤傳達給對方。如果沒有發生錯誤,則會使用下面的應用數據協議來進行通信。
應用數據協議是TLS握手協議的一部分,應用數據協議是將TLS上面承載的應用數據傳達給通信對象的協議。
下面我們看看最為復雜的握手協議 ,它的大致流程圖如下:
從上述可以看出,握手協議中使用了密碼技術中的對稱密碼、消息認證碼、公鑰密碼、數字簽名、偽隨機數生成器等密碼技術,充分的保證了數據傳出的安全性及完整性。
至此,關于密碼技術的這篇博客就講解完畢了,如果大家感興趣的話,歡迎點贊及轉發~~~
總結
以上是生活随笔為你收集整理的“攻城狮” 需要了解的密码知识的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 女子学电子计算机哪一项专业好,2018最
- 下一篇: 《攻城Online》快速原型:服务端设计