使您的軟體運轉起來:密碼術本質 -將散列演算法用於資料完整性和認證
Gary McGraw 和 John Viega
Reliable Software Technologies
2000 年 7 月 7 日
內容: |
|
|
單向函數 |
散列函數 |
網際網路分發 |
認證問題 |
MAC |
回放攻擊 |
Telnet 協議 |
其它攻擊 |
數位簽章 |
簽名問題 |
下一步是什嗎? |
參考資料 |
關於作者 |
|
|
迄今為止,在關於密碼術的這個系列中,Gary 和 John 已經討論了密碼編譯演算法的兩種常見形式 — 公開金鑰密碼系統,譬如 RSA,對稱演算法,譬如 DES — 這是解決資料機密性問題的最常用方法。他們還討論了使用為人熟知的演算法的重要性,而不推薦使用您自己的演算法,並介紹了在應用程式中實現密碼術時經常遇到的風險。在這一部分中,他們從介紹散列演算法開始,致力於研究用於資料完整性和認證的常用方法。
單向函數
散列演算法是單向函數。也就是說,它們接收一個明文字串,將它轉換成一小段無法用來重建原始明文的密文。顯然,要使這種函數起作用,轉換中必需丟失一些資料。
乍聽上去,單向函數似乎沒有用,因為您無法從單向計算的密文中找回明文。為什麼要計算一個無法解開的密碼呢?當然,幾乎是單向的函數是非常有用的,因為從本質上講,所有的公開金鑰函數都是帶“天窗”的單向函數。公開金鑰密碼術的良好候選函數,是那些在一個方向上容易計算,而在另一個方向上除非您知道某些秘密否則極難計算的函數。因此,我們發現公開金鑰演算法是基於因式分解和其它較難的數學竅門的。
散列函數
正如結果所表明,真正的單向函數也是有用的。這些函數通常叫做散列函數,其結果通常稱為密碼散列值、密碼校正和、密碼指紋或訊息摘要。此類函數在許多密碼協議中起著重要作用。
其構思就是接收一段明文,然後以一種無法復原的方式將它轉換成一段(通常更小)密文。理論上,所有可能的明文將散列成一個唯一的密文,但實際上通常發生的不是那樣。大多數時候,幾乎有無窮多個不同的字串可以產生完全相同的散列值。但是,對於一個好的密碼散列函數來說,在實踐中應該很難有兩個可理解的字串散列相同的值。好的散列函數的另一個特性是輸出不以任何可辨認的方式反映輸入。
散列函數通常產生恒定大小的摘要。許多演算法產生很小的摘要,但是,演算法的安全性很大程度上取決於結果摘要的大小。我們推薦選擇那些提供不小於 128 位摘要的演算法。SHA-1 提供 160 位散列,是一種可以使用的好散列函數。
可以使用散列函數來確保資料完整性,這很象傳統的校正和。如果您公開發布一個文檔的有規律密碼散列,則任何人都可以檢驗該散列,假設他們知道散列演算法的話。人們在實踐中使用的大多數散列演算法是公開發布和為人熟知的。再次提醒您,使用專用密碼演算法,包括散列函數,通常是一個壞主意。
網際網路分發
考慮一下分發在網際網路上的軟體包的情況。在不遠的過去,通過 ftp 得到的軟體包是與校正和關聯的。其思想是下載軟體,然後運行一個程式來計算您的校正和版本。然後可以將自行計算的校正和與 ftp 網站上得到的校正和相比較,以確定兩者匹配並確保傳輸串連上(over the wire)的資料完整性(各種各樣)。問題是這種過時的方法根本就不加密。首先,有許多校正和技術可以惡意修改下載程式,並可能導致修改過的程式產生完全相同的校正和。其次,帶有其相關聯(保護極差)校正和的軟體包的“特洛伊”版本可以輕易地在 ftp 網站上發布。密碼散列函數可以用做老式校正和演算法的隨便替代物。它們具有一個優點,就是使篡改投遞代碼變得極其困難。
預先警告您 — 這種分發方案還有一個問題。如果作為軟體消費者,不知何故下載了錯誤的校正和,您會怎麼辦?例如,假設我們分發了“xyzzy”軟體包。一天夜裡,一些駭客闖入了分發機器,並將 xyzzy 軟體換成了一個稍作修改的版本,其中包含惡意的特洛伊木馬。攻擊者也將我們公開分發的散列替換成帶有特洛伊副本的散列發行版。此時,當某個無辜的使用者下載目標軟體包時,將得到惡意的副本。受害者也下載了密碼校正和,並針對軟體包測試它。它進行檢測,而惡意代碼看起來安全可供使用。顯然,如果我們不能確保散列本身不被修改,僅僅散列不能成為完整的解決方案。簡而言之,我們需要一種認證散列的方法。
認證問題
在我們考慮認證問題時,可能出現兩種情況。我們可能希望每種情況都可以驗證散列。如果是這樣,我們可以使用基於 PKI 的數位簽章,這將在下面討論。或者,我們希望限定誰能驗證散列。例如,假設我們向 sci.crypt 新聞群組發送了一封匿名信,其中投遞了一種專用密碼編譯演算法的全部原始碼,但是希望只有我們最親密的朋友才能驗證我們投遞了訊息。可以使用訊息認證代碼(MAC)來達到這個目的。
訊息認證代碼
MAC 通過使用一種共用秘鑰起作用,接收方端使用它的一個副本。該密鑰可以用於認證可疑資料。發送方必須擁有秘鑰的另一個副本。MAC 有幾種工作方式。第一種方式是在計算摘要之前,將秘鑰共置到資料末尾。如果沒有秘鑰,則無法確認資料未經改動。另一種計算更複雜的方式是照常計算散列,然後再使用對稱演算法(如 DES)加密散列。要認證散列,必須首先對它解密。
Applied Cryptography MAC 的許多構造不是取決於密碼散列法的。Bruce Schneier 的 Applied Cryptography 更詳細地講述了這個主題(請參閱參考資料)。 |
MAC 在許多其它環境中也很有用。如果您希望不使用加密而實現基本訊息認證(也許是由於效率原因),MAC 是完成該任務的合適工具。即使您已經使用了加密,MAC 也是一種確保加密位流在傳輸中免遭惡意修改的極佳方法。
如果仔細設計,好的 MAC 可以協助解決其它公用協議問題。許多協議在遭受所謂的回放攻擊(或者捕獲-回放攻擊)期間,明顯存在一個普遍問題。假設我們向銀行發送一個請求,要求從我們的帳戶劃撥 50 美元到 John Doe 的銀行帳戶。如果 John Doe 攔截了通訊,他可以稍後向銀行發送一個相同的訊息副本!有時銀行會認為我們發送了兩個請求。
回放攻擊
回放攻擊被證實是許多真實世界系統中的普遍問題。幸好,我們可以使用 MAC 的巧妙用法來緩和這種情況。在銀行劃撥樣本中,假設我們使用了一種隨秘鑰散列請求的原始 MAC。為了對付回放,我們可以確保散列永遠不同。做到這一點的一個顯而易見的方法是使用時間戳記。
小心! 如果編寫代碼時不夠仔細,可能會出現另一個小錯誤。如果攻擊者能夠輕易挑選出您訊息中對應於加密時間的位,並用一組不同的、隨機的位取代它們,代碼可能無法運行。如果您的代碼只檢查此前 60 秒內的時間戳記,而不檢查時間戳記是否來自未來的某個時間,那麼攻擊者也將很平常地獲得幸運的(以竊取資金)方式。 |
如果伺服器發現一個請求的時間戳記到期(比如,超過 60 秒),它將拒絕請求。這或許足夠了,也可能還不夠,因為它還是導致了一個 60 秒的視窗,其中回放攻擊可能發生。您可能會考慮禁止在同一時間單元發生兩次請求,並緩衝關於過去 60 秒以內到達的有效請求的資訊。如果您能夠處理這種特殊情況:在同一時間單元裡兩次執行了同一交易,則這種解決方案也許可行。但是存在更簡單的解決方案。當您計算 MAC 時,不僅散列資料和秘鑰,而且散列一個唯一、有序的序號。遠程主機只需要瞭解它所處理的最後一個序號,並確保不處理比下一個預期序號更舊的請求。這是普遍使用的方法。
在許多情況下,認證其實不是問題。例如,考慮使用密碼散列來認證從控制台登入到機器的使用者。在許多系統中,當使用者第一次輸入密碼時,實際上並沒有儲存密碼本身。相反,儲存了密碼的密碼散列。因為大多數使用者覺得如果系統管理員不能隨意檢索他們的密碼會更好。假設作業系統是可信的(這是個可笑的大前提),我們可以假設我們的加密散列密碼的資料庫是正確的。當使用者試圖登入,並輸入密碼時,登入程式散列它,並將新散列的密碼與儲存的散列比較。如果兩者相等,我們假設使用者輸入了正確密碼,則登入繼續。
Telnet 協議
可惜,架構設計師和開發人員有時假設認證機制的安全性實際上不是問題,但實際上它是。例如,考慮一下 telnet 協議。大多數 telnet 伺服器接收使用者名稱密碼作為輸入。然後散列密碼,或執行一些類似的轉換,然後將結果與本機資料庫中的比較。問題在於使用 telnet 協議時,密碼在網路上以明文傳輸。任何能夠使用包嗅探器在網路線路上偵聽的人都可以發現密碼。telnet 認證提供了很差的保護,潛在攻擊者可以輕易地清除保護。許多著名的協議(包括 FTP、POP3 和 IMAP 的多數版本)都具有類似的破綻百出的認證機制。
當然,圍繞密碼認證系統的實現,還有許多其它重要的安全性注意事項。這個問題是個很大的主題,我們將在另一篇文章中詳細剖析它。
其它攻擊
任何好的密碼散列演算法應該是這樣的,即使給定一個已知的訊息和與它關聯的訊息散列,也很難找到替代明文的重複散列。對衝突的故意搜尋意味著蠻力攻擊,這通常很難。當攻擊者希望用第二份明文文檔產生除了雜亂無意義的字串之外的東西時,就尤其困難。
另一種對密碼散列的攻擊比平均蠻力攻擊容易實施得多。考慮下列情況:Alice 向 Bob 顯示了一份文檔和驗證文檔的密碼散列,文檔內容是 Alice 同意為每個小飾品付給 Bob 5 美元。Bob 不想在他的伺服器中儲存該文檔,所以他只儲存了密碼散列。Alice 希望只為每個小飾品付 1 美元,所以她想建立第二份文檔,所產生的散列值和 5 美元的那份相同,然後告上法庭,控訴 Bob 多收了她的錢。當她出庭時,Bob 將出示散列值,相信 Alice 的文檔不能散列出那個值,因為這不是她顯示給他的原始文檔。如果其攻擊是成功的,Alice 將能夠證明她所偽造的文檔確實散列出 Bob 儲存的值,法庭將判她勝訴。
但她是如何做到這一點的呢?Alice 使用了所謂的生日攻擊。在這種攻擊中,她建立了兩份文檔,一份寫著每個小飾品 5 美元,另一份則寫著每個小飾品 1 美元。然後,在每份文檔中,她標識出 n 處可以進行表面更改的地方(例如,那些可以用定位字元取代空格的地方)。好的 n 值通常是最終散列輸出的位長度的一半加 1(所以如果我們指定散列輸出的位長度為 m,則 n = m/2+1)。對於 64 位元散列演算法,她將在每份文檔中選擇 33 個地方。然後她反覆嘗試每份文檔不同的排列,建立和儲存散列值。一般來說,預計她將在散列了大約 2m/2 條訊息之後找到散列出相同值的兩份文檔。這比蠻力攻擊要有效得多,如果使用蠻力攻擊,預計她必須散列的訊息數為 2m-1。如果 Alice 執行一次成功的蠻力攻擊需要一百萬年,那麼她也許一周以內就可以完成一次成功的生日攻擊。因此,Bob 應該要求 Alice 使用一種演算法,它所產生的摘要大小使得她不能在任何合理的時間之內完成生日攻擊。
如果希望針對生日攻擊獲得和針對蠻力攻擊一樣的安全性,給定一個密鑰長度為 p 的對稱密碼,您應該選擇提供大小為 p*2 的摘要的散列演算法。因此,對於具有很高安全性需求層級的應用程式,要求散列演算法產生 256 位甚或 512 位的訊息摘要是個好主意。
什麼是適用的好散列演算法呢?
我們特別喜歡 SHA-1。Bruce Schneier 也推薦這個演算法。但是如果散列長度必需超過 160 位,SHA-1 還不夠。對於大位元散列,嘗試使用適合於執行散列法的對稱式加密術。GOST 散列演算法是個好樣本,它從 GOST 加密術派生而來,帶有 256 位的散列長度。更長的散列長度很可能要求進行一些編碼來適應對稱式加密術。Schneier 在 Applied Cryptography 中概述了構建此類演算法的構造。SHA-1 或 GOST 散列演算法都沒有任何智慧財產權限制。
數位簽章
數位簽章背後的思想是模仿傳統手寫簽名。該思想是能夠以某種方式“簽署”一份數字文檔,該簽名具有和物理簽名一樣的法律效力。數位簽章至少必須和手寫簽名一樣好地滿足以下主要目的:
- 簽名應該成為可靠性證明。它在一份文檔上的存在應該使人信服,某人的簽名出現在某文檔上是他有意簽署的。
- 簽名應該不可偽造。因此,在文檔上籤了名的人應該不能聲明這簽名不是他們的。
- 在簽署文檔以後,應該不可能不可檢測對文檔的更改,否則簽名可能是無效的。
- 簽名應該不能移動到另一份文檔。
即使對於手寫簽名,這些目標也只是概念上的,並不能真正地反映現實。例如,偽造簽名是可能的,儘管很少有人技藝高超,真的能偽造。然而,簽名罕有濫用的傾向,這很好地保持了它在法庭的地位。總之,墨水簽名已經是足夠好的解決方案。
電子簽名至少可以做得和物理簽名一樣好。這個事實經常使人們吃驚,因為他們將這種簽名當成是類似於人們經常放置在電子郵件訊息末尾的那種簽名檔案(一串 ASCII)。如果數位簽章就是象這樣的,那麼它們根本就沒什麼用。很容易從一個檔案複製簽名,並將它直接添加到另一個檔案上以形成一個贗品。也可能輕易地修改一個經過簽署的文檔,並且誰也不能發現。謝天謝地,數位簽章完全不是這樣。
大多數數位簽章系統將公開金鑰密碼術和密碼散列演算法結合使用。正如我們所解釋的,公開金鑰密碼系統經常使用接收方公開金鑰來加密訊息,然後接收方使用相應的專用密鑰解密。專用密鑰也能用來對只能用相應公開金鑰解密的訊息進行解密。如果某人將他的專用密鑰完全保持私人,(您最近沒有被黑,不是嗎?)能夠使用相應公開金鑰解密訊息,則構成可疑的人對原始訊息進行加密的證明。
數位簽章不僅在簽署文檔的時候有用 — 它們幾乎可用於任何認證需求。例如,它們經常與加密聯合使用,以便保持資料私人性和資料認證。
用於文檔的數位簽章經常由對文檔的加密散列構成,然後用專用祕密金鑰加密散列。結果密文稱為簽名。任何人都可以通過自行散列文檔,然後解密簽名(使用公開金鑰或共用秘鑰),並比較兩個散列來確認簽名。如果兩個散列相等,則認為簽名有效(假設進行確認的人相信他使用的公開金鑰確實屬於您)。
簽名不必隨文檔一起儲存。同樣,簽名適用於文檔的任何相同的數字副本。簽名也可以複製,但是無法使它適用於其它文檔,因為最後得到的散列與解密散列不匹配。
數位簽章的問題
數位簽章的一個問題是認可。人們總是可以聲明他們的密鑰被盜。但是,數位簽章還是作為物理簽名的合法替代廣泛地得到接受,因為它們至少和物理簽名一樣接近上面提到的目標。目前至少有 30 個州有數位簽章法律,並且更多州很可能立法(如果美國國會沒有搶先通過一項國家法律的話)。
大多數公開金鑰演算法,包括 RSA 和 ElGamal,可以容易地擴充以支援數位簽章。實際上,一個支援這些演算法之一的好軟體包應該也支援數位簽章。我們推薦您將自己喜歡的公開金鑰密碼術演算法用於數位簽章。嘗試使用內建原語而不是拋開密碼編譯演算法和散列函數去構建自己的構造。
Applied Cryptography 中的酷方法 Bruce Schneier 討論了許多您可以用密碼術來做的很酷的事情。例如,他概述了該如何建立您的數字認證郵件系統。他還討論了如何以一種將任務分發給 n 個人的方式來分解一個加密的秘密,只有這 n 個人中的 m 個人將他們的資源拼湊到一起,秘密才能顯示出來。如果您正想瞭解密碼術必須提供的各種可能性,這本書確實值得仔細讀。 |
下一步是什嗎?
在未來的文章中,我們將討論幾個相關主題。最重要的主題是密鑰管理:如何安全地產生、儲存、更改、銷毀或傳遞加密金鑰?我們還將討論實質問題,並實際研究一些真正的密碼軟體包,包括程式碼範例。我們將研究用於 Java 應用程式的 Cryptix 包、C 的 SSL 實現以及 Kerberos 的一個實現。我們還將提供其它被認為是很健壯的密碼軟體包的連結。
在下一篇專欄文章中,我們將探究關於如何向軟體應用程式添加密碼管理的實質細節,以及(可能更重要)如何不這樣做。
密碼術是一個巨大的領域,但又只是軟體安全性的一個方面。甚至我們也不能謊稱自己完全瞭解它。
參考資料
請參閱 developerWorks 上以前的關於密碼術的專欄文章:
- 使您的軟體運轉起來:隱藏所有事物
- 使您的軟體運轉起來:久經考驗的密碼術
- 請閱讀 Bruce Schneier 的“Applied Cryptography”。
- 請訪問 Reliable Software Technologies 網站
關於作者
Gary McGraw 是 Reliable Software Technologies 負責企業技術的副總裁,該公司位於美國維吉尼亞州杜勒斯(Dulles)。他從事諮詢服務和研究,協助決定技術研究和開發的方向。McGraw 在 Reliable Software Technologies 從研究科學家做起,從事軟體工程和電腦安全性方面的研究。他擁有印地安那大學認知科學和電腦科學雙博士學位,以及維吉尼亞大學哲學學士學位。他為技術刊物撰寫了 40 餘篇經過同行審閱的文章,擔任主要電子貿易供應商(包括 Visa 和 Federal Reserve)的顧問,並在空軍研究實驗室、DARPA、國家科學基金會以及 NIST 的進階技術項目贊助下擔任其首席調研員。
McGraw 是行動程式碼安全性方面著名的權威人士,並且與普林斯頓的教授 Ed Felten 合作撰寫了“Java Security: Hostile Applets, Holes, & Antidotes”(Wiley, 1996)和“Securing Java: Getting down to business with mobile code”(Wiley, 1999)。McGraw 和 RST 創始人之一、首席科學家 Jeffrey Voas 博士一起編寫了“Software Fault Injection: Inoculating Programs Against Errors”(Wiley, 1998)。McGraw 定期為一些受歡迎的商業出版物撰稿,而且其文章經常在全國出版的文章中所引用。
John Viega 是 Reliable Software Technologies 進階副研究員、軟體安全性小組共同創始人以及進階顧問。他是 DARPA 資助的用於開發標準程式設計語言的安全性擴充項目的首席調研員。John 編寫過 30 多部關於軟體安全性和測試領域的技術出版物。他負責尋找主要網路和電子商務產品的幾個公開宣傳的安全性弱點,包括最近對 Netscape 安全性的闖入。他還是開放源碼軟體社團中的重要成員,編寫了 Mailman,即 GNU Mailing List Manager,以及最近的 ITS4,這是一個用來尋找 C 和 C++ 代碼中的安全性弱點的工具。Viega 擁有維吉尼亞大學電腦科學理科碩士學位。