第15.16.17章學習筆記

20211113發表於2024-04-21

實際上的問題 II

15.1 大整數的運算

所有公鑰中的計算都是基於大整數運算。如我們曾提及的,恰當地實現大整數運算並不是一件容易的事情。大多數的處理例程總是或多或少地與平臺相關。能夠透過平臺特性得到的有效率提升總是難以發揮實際作用。比如,多數CPU有一種帶進位加法運算(add-with-carry)功能來處理多字值的加法。但是在C語言或者幾乎所有其他高階語言中,你是無法訪問這個指令的在高階語言中進行大整數運算一般都比經過平臺最佳化的實現速度慢幾倍。這些計算也成了公鑰效能的瓶頸,所以這個問題難以忽視。

15.1.1 woop技術

  • woop技術的基本思想是為了驗證對隨機選擇的小素數的取模計算。將這個問題作為密碼學問題考慮。我們有一個大整數庫,這個庫試圖欺騙我們,給出錯誤的結果。我們的任務是檢查是否得到了正確的結果。如果只是檢查這個結果和同一個庫再計算一遍得到的結果是否一樣,這不是一個
    好主意,因為這個庫可能會一直錯下去。使用woop技術,只要看看這個庫是否會嘗試修改我們驗證計算的結果,就可以驗證這個庫的計算結果了。
  • 我們也相信在已有的庫中新增wo0p驗證比在使用該庫的應用中新增應用層面的驗證所需要的工作量小一些。

15.1.2 檢查

  • 檢查DH計算
    如果你沒有一個使用了woop技術的庫,就只能在沒有woop驗證的情況下工作。我們所描述的DH協議已經包括了許多檢查,也就是說,結果不應該是1,結果的階應該是q。不幸的是,這些檢查不是由計算的一方來做的,而是由接收計算結果的一方進行的。總體上說,你不會想傳送任何有錯誤的結果,因為可能會洩露一些資訊,但是在這種特定情況下似乎沒有什麼危害。如果結果是錯誤的,協議不管怎樣都會失敗,所以這個錯誤會被注意到。協議不安全的時候是當你的運算庫在要求計算g’的時候卻返回了x,但是這種錯誤普通的測試很可能就會檢測到。 必要的時候,我們可能會在一個沒有woop驗證的庫上執行DH協議。我們所擔心的非常罕⻅的運算錯誤型別不太可能從一個g’的運算中洩露x。其他的錯誤看起來沒什麼害處,尤其是當DH的計算沒有⻓期秘密時。不過,我們仍然更願意在可能的時候使用一個內建woop系統的庫,只是因為安全一些。

15.1.3 檢查

檢查RSA加密
RSA加密更加脆弱,需要額外的檢查。如果某一步出錯了,可能會洩露你正在加密的秘密,或者你自己的金鑰。如果不能使用woop驗證,還有另外兩種辦法來檢查RSA加密。假設實際的RSA加密包括計算c=m^mod n,其中m是訊息,c是密文。為了驗證這個結果,我們可以計算
c^mod n並且和m進行比較。這種方法的缺點在於計算過程很快,而驗證過程很慢,並且它需要知道私鑰,而我們正在進行RSA加密時通常不知道私鑰。

15.1.4檢查

檢查RSA簽名
RSA簽名相當容易檢查。簽名者只需要執行簽名驗證演算法即可。這是一個比較快的驗證,如果有運算錯誤也很容易捕捉到。每個RSA簽名計算都應當用這種方法去驗證剛產生的簽名。

15.2 更快的乘法

更快的乘法

  • 有很多種方法可以讓你實現模乘法,這個方法的乘法再跟一個⻓除法(long division)更快。如果你必須做很多次乘法,那麼Montgomery方法是最廣泛使用的方法
  • Montgomery方法是一種計算(x mod n)的方法,其中x遠大於n。傳統的“⻓除法”是從x中減去n的倍數。Montgomery的想法更簡單:重複地將x除以2。如果x是偶數,我們除以2的方法是將它的二進位制表示右移一位。如果x是奇數,我們首先加一個n/2然 (當然這不會影響modn的結果),然後將這個偶數結果除以2。(這個技術只適合n是奇數的情況,在我們的系統裡通常如此。當n是偶數時可以進行一個簡單的歸納。)如果n的⻓度是k位並且x不大於(n-1)²,我們總共進行k次除以2。這個結果總是在區0,...,2^n-1中,這幾乎就是modn的約簡結果。但是,等等!我們一直在除以2,所以這個結果還不對。 Montgomery的歸約並沒有給你實際的(x mod n),而是對於某個合適的k值的x/2modn。這個歸納快一些,但是你額外地乘了一個2。有幾種技巧來處理這個額外的因子。第一個不太好的主意是重
    新定義你的協議,在計算中納人一個額外的2因子。這個方法不好,因為它混淆了不同的層次。

15.3 側通道攻擊

側通道攻擊
一些加密演算法要求實現時使用不同的程式碼路徑去處理特殊情況。
加密演算法使用的CPU操作會因為處理的資料不同而造成時間消耗上的差異。在一些CPU上,乘法(RC6[108]和MARS使用)或重複資料(RC6和RCS[107]使用)的執行時間取決於輸入資料。這可以導致時間攻擊。

15.4 協議

協議
實現密碼協議和實現通訊協議區別不是那麼大。最簡單的辦法是保持程式計數器的狀態,然後簡單地輪流實現協議的每一步。除非使用了多執行緒,否則這會使得你在等待一個回覆時,程式其他部分都停止執行。這通常不是一個好主意。一個更好的解決方案是保持一個顯式的協議狀態,並且在每次一條訊息到來時更新這個狀態。這種訊息驅動(message-driven)的方法在實現的時候需要稍微多花點功夫,但是它也提供了更多的靈活性。

15.4.1 安全通道上的協議

安全通道上的協議
多數的密碼協議都是在非安全通道上執行的,但是有時候你需要在一個安全通道上執行密碼協議。在一些情況下這是必要的。比如,每個使用者都有一個和金鑰分發中心(key distribution center)通訊的安全通道,中心使用一個簡單的協議來分發金鑰給使用者,允許他們之間互相通訊。(Kerberos協議所做的事情與此類似。)如果你在和你已經交換過金鑰的某一方執行一個密碼協議,你應該使用全部的安全通道功能。並且,你需要實現重放保護。這非常容易做到,可以阻止大量針對密碼協議的攻擊。有
時安全通道會允許協議使用捷徑。例如說,如果安全通道提供了重放保護,協議本身就不需要再次實現一次重放保護。不過,老的模組化規則認為,協議應該最小化其對安全通道的依賴程度。

15.4.2 接收一條訊息

接收一條訊息
當一個協議狀態接收到一條訊息時,需要進行若干個檢查。第一個是檢查這條訊息是否屬於這個協議。每條訊息都應該由以下幾個欄位開頭:
1)協議識別符號(protocol identifier):用來識別這是哪個協議和哪個協議版本。版本識別符號是很重要的。
2)協議例項識別符號(protocol instance identifier):識別這條訊息屬於協議的哪個例項。 Alice 和 Bob可能同時在執行兩個金鑰協商協議,而我們不想混淆。
3)訊息識別符號(message identifier):識別協議內部的訊息。最簡單的方法是給它們編號。
取決於具體情況,一部分識別符號可能是隱式的。比如,對於那些在自己的TCP連線上執行的協議,埠號和相關聯的套接字就可以識別出本地機器上的協議例項。協議標
識符和版本資訊只需要交換一次。需要注意的是,這些資訊至少需要交換一次以保證它們被包含在協議的所有認證或者簽名中。
在檢查了協議識別符號和例項識別符號之後,我們知道了一條訊息應該傳送給哪個協議狀態。讓我們假設這個協議狀態剛剛接收了訊息n-1並正在等待訊息n。如果收到的這條
訊息的確是訊息n,事情很好辦。只需要按照協議規則來處理即可。但如果是不同的訊息號呢?
如果這條訊息號比n大或者比n-1小,那麼表明發生了一些奇怪的事情。不應該生成的訊息,所以一定是某種偽造訊息。你必須忽略這條偽造訊息的內容。如果收到的是消
息n-1,可能是你傳送的回覆訊息還沒有到達。當協議執行在某種不穩定的傳輸系統上時,可能會發生這種事情。因為我們都知道最小化對系統其他部分的依賴,這正好滿
足我們的假設。
首先,檢查這條新收到的訊息n-1是否和之前那條標號n-1的訊息完全相同。如果它們不同,那麼你必須忽略這條新訊息。再次傳送一條回覆會被壞協議的安全性。如果消
息內容是相同的,那麼只需要重發之前的回覆。當然,回覆的訊息版本需要和之前回復的版本保持相同。
如果你由於任何一條規則忽略了這條收到的訊息,就需要做第二個決定了。是否應該終止協議?答案在一定程度上取決於應用和具體情況。如果你一直在一個安全通道上
執行協議,事情就很不對了。要麼是這個安全通道被破壞了,要麼就是你正在交流的另外一方行為不正常。不論哪種情況,你都應該終止協議和通道。然後刪除協議狀態
和通道狀態,包括通道金鑰。
如果你在一個非安全通道上執行這個協議,那麼任何一條被忽略的訊息都可能是攻擊者試圖攻擊協議的一次嘗試。理想狀態下你會忽略這條攻擊者的訊息,繼續完成協
議。當然並不總是這樣。比如說,如果攻擊者偽造的訊息n-1先到達,你會傳送一條回覆,而當“真正”的訊息n-1來了的時候你被迫忽略它。這種情況是沒有辦法恢復的,
因為你沒辦法安全地傳送第二個回覆。你不知道收到的兩條訊息n-1中哪條是真的,所以為了能夠儘可能地完成協議,你將第二條訊息n-1記為一次錯誤,然後照常繼續執
行協議。如果你回覆的 訊息來自於攻擊者,協議最終仍會失敗,因為密碼協議的設計目的是正是阻止攻擊者成功地和一個參與者完成協議。

15.4.3 超時設定

超時設定
任何協議都包括超時設定。如果你沒有在一段時間內收到訊息的響應,可以重新傳送最後一條訊息。在幾次重發之後,你不得不放棄。當你無法和另一方通訊時,繼續執行協議是沒有意義的。

第十六章 金鑰管理

16.1 時鐘的使用

16.1.1 有效期

有效期
在多數情況下,需要限制檔案的有效期。在現實生活中,我們也通常會看到有限的有效期。支票、⻜機票、代金券、優惠券甚至是版權都有期限的有效期。限制數字文件
有效期的標準方法是在文件內部包含有效期。但為了檢查一個文件是否到期,我們需要知道當前時間,因此就要用到時鐘。

16.1.2 唯一值

唯一值
時鐘另一個重要功能(如果它的精度足夠高的話)是可以為單個機器提供一個唯一值。我們已經在幾個地方用到了瞬時值(nonce)。瞬時值的主要特點是任何一個值都不會被使用兩次。

16.1.3 單調性

單調性
時間的一個有用的性質是它會一直不斷向前走,從來不會停止或倒退。有一些密碼協議用到了這個性質。在密碼協議中包含時間資訊可以防止攻擊者把舊的訊息當作有效訊息放到當前協議中。畢竟,編碼在那些資訊中的時間不在當前協議的時間跨度內。時鐘的另一個非常重要的應用是審計和日誌。

16.1.4 實時交易

實時交易為了支援實時支付,銀行需要執行實時金融交易系統。為了讓審計能夠完成,應該有一個清晰的交易序列。給定兩個交易A和B,瞭解兩者哪個先發生是很重要的,因為其
中一個交易的結果取決於另一個是否已經完成。記錄這一序列的最簡單的方法是給每一個交易一個時間戳,但這需要在有可靠時鐘的前提下才可行。一個不可靠的時鐘也許會給出錯誤的時間。如果時鐘只是偶然地向回移動的話,還不會有多大危險,因為很容易就能夠發現當前時間比上次交易完成時的時間戳大。然而,如果時鐘是向前移動的話,就會出現問題。假定當時鐘設定為2020年時,完成了半個小時的交易。你不能只是改變那些交易的時間戳,人工修改金融記錄是不能被接受的。問題是你在2020年之前不能進行任何新的交易,因為那將違反了由時間戳所決定的交易的順序。對於這個問題有解決方案,但如果能有一個可靠的時鐘肯定是最好的。

16.2 使用實時時鐘晶片

  • 使用實時時鐘晶片
    大多數臺式計算機包含一個實時時鐘晶片和一塊小電池,這是安裝在你的機器中的一個非常小的數字鐘。這就是為什麼計算機會在你早上開機的時候知道現在的時間是幾點。那麼,為什麼不就簡單地使用這個時鐘時間呢?實時時鐘晶片對一般的普通應用來說是足夠了,但在安全系統中,我們必須強制要求更高的標準。作為安全系統的一部分,即使攻擊者試圖去操縱時鐘,它也應該給出正確的時間來。第二個原因是時鐘有時會有故障。在一般的應用中,時鐘顯示錯誤的時間很惱人,但是並不危險。如果
    時鐘是安全系統的一部分,那麼它的故障就會帶來更大的危害。在一般硬體中的實時時鐘並不像我們所需要的那樣可靠和安全。在過去的十年裡,我們已經親自經歷了幾次實時時鐘晶片的故障。而且,那些故障都是自發的,沒有惡意攻擊者嘗試去破壞它。大多數故障的原因很簡單:在臺舊機器上,由於電池電量不足,時鐘就停止了或者被重新設定成1980年。或是有一天你啟動機器,時鐘已經設定成2028年的某一天了。有時候一個時鐘可能會發生漂移,比實際時間慢一點或者快一點。除了實時時鐘的
    意外錯誤,我們還必須考慮主動攻擊。有些人可能嘗試用某種方式操縱時鐘。根據計算機的具體情況,改變時鐘時間可能會容易也可能很困難,在有些系統中只有特定的管理員才有許可權改變時鐘,而這些系統的時鐘可以被任何人修改。

16.3 安全性威脅

安全性威脅

16.3.1 時鐘後置

時鐘後置
假定攻擊者能夠把時鐘設為過去的任何一個時間。這會導致各種可能的危害,機器會錯誤地相信自己生活在過去。

16.3.2 時鐘停止

時鐘停止
如果時鐘停止了,時間似乎就靜止了。這時事情可能就無法完成。而且很多系統可能會有無法預測的行為。這種情況引起的簡單問題類似於交易記錄和報告的時間錯誤了,一則交易的準確時間可以造成很嚴重的經濟上的後果,傳送一份印有錯誤時間和日期的正式報告可能導致嚴重的混亂情況。

16.3.3 時鐘前置

時鐘前置
把時鐘向前設定會使計算機認為自己生活在將來,這會導致簡單的拒絕服務攻擊。

16.4 建立可靠的時鐘

大多數計算機有或者可以實現某種計數器,在電腦啟動的時候開始計數。這也許是CPU時鐘迴圈的計數,也許是重新整理計數器或其他類似的計數器。這個計數器能用來記錄自從最後一次重新啟動之後的時間。它不是時鐘,因為它不能提供具體時間的資訊,但它能用來測量兩個事件(這兩個事件都是在最後一次重啟之後發生的)之間所經過的時間

第十七章 金鑰伺服器

17.1 基本概念

基本概念
我們假定每個人都與金鑰伺服器建立一個共享金鑰。例如,Alice產生一個只有她和金鑰伺服器知道的金鑰K4,Bob也建立一個只有他和金鑰伺服器知道的金鑰KB。其他參與方都以同樣的方式建立金鑰。現在假定 Alice想與 Bob進行通訊。她沒有與 Bob 通訊的金鑰,但她可以與金鑰伺服器安全地通訊。金鑰伺服器反過來也能與 Bob 安全地通訊。我們能簡單地把所有的通訊傳給金鑰伺服器,把金鑰伺服器當成一個巨大的郵局。但對金鑰伺服器來說存在一些困難,因為它將不得不處理大量的通訊。一個更好的解決方案是,讓金鑰伺服器建立一個 Alice 和 Bob 的共享金鑰 KB。

17.2 Kerberos協議

協議
當 Alice 想與 Bob 對話時,她首先與金鑰伺服器聯絡。金鑰伺服器向 Alice 傳送一個新的金鑰 KAB 以及使用 Bob 的金鑰 Kg 對 KAB 加密後的值。這些訊息都用 K4 加
密,因此只有 Alice 能讀。Alice 解密之後,再用 KB 加密之後的訊息,這條訊息稱 為標籤 (ticket),傳送給 Bob。Bob 對它解密,然後得到 KAB,這是隻有 Alice 和
Bob 知道的會話金鑰,當然,金鑰伺服器也知道。Kerberos 的一個特點是金鑰伺服器,在 Kerberos 協議的術語中叫作 KDC,KDC 不需要知道 Alice 或 Bob 的密碼。
太經常地更新自己的狀態。當然,金鑰伺服器要記住與每個使用者共享的金鑰。但當Alice請求KDC建立一個她和Bob之間的金鑰時,KDC完成這個任務之後就把結果忘記
了。它並不記錄使用者之間建立了哪些金鑰。這是一個很好的性質,因為它可以讓金鑰伺服器以一種簡單的方式把原本很重的負載分佈在幾個機器上。由於沒有狀態要更
新,Alice在某一個時候可與金鑰伺服器的一個副本進行互動,而下一時刻使用另一個副本。事實證明,Kerberos⻛格的系統所需的密碼協議是很複雜的。剛開始,設計這
樣的協議看起來很容易,但即使是經驗豐富的密碼學家提出的方案後來也被攻破了。悄悄混進去的那些缺陷都是很微妙的。我們在這裡不打算解釋這些協議,對它們做實
驗和手動修改都太危險了。我們甚至不願意重新去設計這種型別的協議。如果你想使用一種這樣的協議,請使用Kerberos協議的最新版本。它已經存在很⻓時間了,並且
被很多專家研究過。

17.3 更簡單的方案

更簡單的方案
有的使用者說:“標籤”,每個參與者還需要一個可靠的時鐘。這些要求有些時候是無法滿足的。並且,我們發現去研究一個更簡單的設計能夠提供更多的有用資訊。如果我們不是那麼強調效率,可以給出一個更簡單、更強壯的解決方案。事實證明允許金鑰伺服器來維護狀態是很有用的。現在的計算機與Kerberos剛被設計出來的那個年代的機器相比要強大多了,它們可以沒有任何困難地維護上萬個參與者的狀態。甚至對有十萬級別參與者的大系統也不成問題:如果每個參與者的狀態在金鑰伺服器中
需要佔用1KB,那麼儲存所有的狀態僅需要100MB的記憶體。金鑰伺服器需要足夠快地建立所有這些請求的金鑰,但對現代的快速計算機來說仍然不是個問題。我們這裡僅討論有單個金鑰伺服器的情況。有一些技術可以用來把金鑰伺服器狀態分佈幾個計算機上,對此我們將不進行詳細討論,因為你並不會真的想用一個管理著上萬參與者的金鑰伺服器,那樣太冒險了。這樣的大金鑰伺服器的⻛險在於,所有的金鑰都放在一個地方。這樣使得金鑰伺服器成為一個很有吸引力的攻擊目標。這個金鑰
伺服器也必須一直線上,意味著攻擊者願意的時候能隨時與它進行通訊。當前的狀態並不能很好地保護計算機免受網路的攻擊,而把金鑰都放在一個地方簡直就是找麻煩。對更小的系統來說,被金鑰伺服器儲存的金鑰“總值”小,因此威脅也減少了。在後面的幾章裡,我們要討論更適合大規模系統的金鑰管理系統解決方案,我們這裡僅討論小系統的金鑰伺服器的設定和使用方法。

蘇格拉底挑戰

時鐘



kerberos


相關文章