極客時間-實用密碼學-10怎麼防止資料重放攻擊

Tom哈哈發表於2020-12-16

為什麼還要學習 CBC 模式?

不知道你是不是已經有了一個問題:既然 CBC 要退出歷史舞臺了,我們還學習它幹什麼呢?

第一個原因,CBC 的退出程式可能需要十數年才能完成。你現在工作的專案種,可能還存在 CBC 模式的大量使用。我們學習了 CBC 模式,有助於你解決現存專案的安全問題。

第二個原因,學習針對 CBC 的攻擊方案, 是我們深入理解加密演算法安全問題的最好的切入點。瞭解這些安全缺陷和攻擊方案,有助於你更好地使用密碼學的演算法。因為,這些缺陷也可能換個面孔,出現在應用程式層面。如果你能夠說清楚 CBC 模式的攻擊辦法,也就意味著你已經試著走入了演算法的細節。

第三個原因,也是最重要的原因,就是我們要進一步地理解初始化向量和連結模式對加密演算法的影響。學習 CBC 模式會為我們將來討論更高階的協議和更安全的演算法打下基礎。那麼,CBC 模式是什麼樣子的?它是怎麼解決資料重放攻擊的?它存在哪些安全陷阱?這是我們這一次要解決的問題。

CBC模式加密流程

CBC連結流程
如上圖,每一個明文分組加機密前都會與上一個密文分組做異或運算,第一個明文資料與初始化向量做異或,再送入加密函式加密。

解密流程如下:
CBC解密流程
將密文分組送入解密函式,將輸出與上一個密文分組做異或得到明文資料,第一個分組與初始化向量異或。

CBC模式關鍵點:

  • 加密解密都要使用初始化向量
  • 加密解密初始化向量等同的
  • 上一次的密文分組參與下一次的加密和解密運算

初始化向量需要保密嗎?

如果每一次運算,初始化向量都能不重複,即使是相同的明文資料,它的加密結果也是不同的。但是,如果初始化向量重複使用,相同的明文就會有相同的密文。重複使用的初始化向量,會消解密文反饋的作用,使得 CBC 模式和 ECB 模式一樣脆弱。

所以,初始化向量的唯一性在加密運算的安全性中至關重要。

那你會問了,既然初始化向量這麼重要,那我們需要對它進行保密嗎?初始化向量並不需要保密。如果你對這一點有疑問,不妨換個角度想一想:每一個分組加密的初始化向量都是上一次加密運算得到的密文分組,而密文分組是可以公開的資訊。

異或運算會不會有問題?

我在上面的講解中提到了異或運算,其實,它在密碼演算法裡有廣泛的應用,為什麼它如此廣泛

第一個原因是異或運算是按位運算,所以在相同的計算環境下,異或運算時間只和資料的位數相關,和資料的實際數值無關。

換句話說,如果運算時間和資料數值相關,而且別人還了解到這種相關性,他就可以通過統計學的方法,通過觀察、測算運算時間,找到運算時間和資料數值之間的關聯,來破解密碼。

第二個原因同樣是按位運算,在相同的計算環境下,異或運算的複雜度,也就是需要的算力,只和資料的位數相關,和資料的實際數值無關。而且,一個運算需要的算力,在計算機環境中,可以通過佔用的 CPU 週期數,以及消耗的記憶體空間來衡量。

同理,如果佔用的 CPU 或者消耗的記憶體和資料數值相關,別人就可以通過統計學的辦法,然後觀察 CPU 的佔用、電力消耗或者記憶體的消耗,來破解密碼。一般來說,這種相關性,也會影響運算時間,從而使得基於測算運算時間的攻擊方式同樣有效。

不光如此,如果運算的複雜度和資料數值相關,密碼破解的辦法可就是千奇百怪的了。記錄、測算計算機的噪音、溫度、輻射、反應時間等等,都有可能成為有效的攻擊手段。

如果讓一個一流的黑客,拿著手機進入資料中心,錄一段伺服器發出的聲音,說不定你的伺服器就被攻陷了。之所以沒有說一定會被攻破,是因為近幾年的密碼學進展,已經發展出了具有防範能力的演算法和實現。

但是,如果你的伺服器使用的是十年前的技術和軟體,黑客得手的概率還是有的。我們後面會討論這些新技術和新演算法。

第三個原因和異或運算的運算特點有關,也就是相同的資料歸零,不同的資料歸一

  • 歸零律:如果兩段資料完全相同,它們的異或運算結果,就是每一位都是零的資料;
  • 恆等律:如果一段資料和一段全是零的資料進行異或運算,前一段資料中是零的位運算後還是零,是一的位運算後還是一。也就是說,和零進行異或運算,不改變原資料的數值。

正是異或運算的歸零律和恆等律,CBC 模式才能成立,解密才能進行。這兩個性質,還使得解密運算和加密運算具有相同的運算效率。

如果兩段資料中只有一位不同,它們的異或運算結果,就是隻有這一位的資料是一,其他的資料都是零。那是不是我們就可以通過構造明文分組或者密文分組,一次改變一位資料,然後把資料交給加密運算或者解密運算來處理,通過觀察加密或者解密的結果展開攻擊了?

比如說,一個 128 位的金鑰,它的強度能承受 2^128 次的運算,是一個強度的指數級別的量級。

  • 如果我們一次改變一位資料的攻擊方式得逞,最多需要 128 次的運算;
  • 如果我們一次只能觀測一個位元組,一次一位的改變需要 2^8 = 256 次,這樣的攻擊方式得逞,最多需要 255 * 16 = 4080 次的運算。

這樣的運算強度,和設計的理論值 2^128 相差太遠了,一次有效的破解也就是分分鐘的事情。

還別說,這樣的攻擊方式在實踐中真的是可行的。這種攻擊方式,把 CBC 模式變成了一個充滿陷阱的模式。用的好,它就是安全的;用的不好,它就會惹來麻煩。這實在不符合密碼演算法要皮實、耐用的要求。

金鑰少一位會有影響嗎?

不知道你有沒有注意到,我們上面的討論,提到了資料的位數。

因為分組加密是按照固定的分組進行加解密運算,所以每一次的分組運算,資料的位數都是固定的。比如,AES 演算法的分組大小都是 128 位。所以,我們不用擔心分組運算的資料位數的變化。

在分組運算中,初始化向量、密文分組和明文分組金鑰的資料位數也都是固定的。所以,我們也不需要擔心它們的位數的變化。加密演算法和解密演算法不涉及資料位數,所以我們也不擔心演算法。剩下的一個變數,就是金鑰了。金鑰的位數會變化嗎?金鑰的位數變化有影響嗎?

一般來說,我們也不太關心金鑰的位數變化,金鑰少一位似乎也不是什麼無關緊要的事情。所以,出於互操作性的考慮,很多標準和協議(包括應用最廣泛的 TLS 1.2 協議)需要把金鑰的高位的零清除掉,然後再參與運算。

原來 128 位的金鑰,可能就被清除成了 127 位或者 126 位的金鑰了。2018 年釋出的的 TLS 1.3 版本,不再需要清除金鑰高位的零。少一位密碼,當然會帶來計算效能的差異,以及由此引發的計算時間偏差。可是,似乎 2020 年之前,沒有人擔心這件事。

直到 2020 年 9 月 8 日,一個名字叫做“浣熊攻擊”的安全研究成果釋出了。浣熊攻擊可以利用金鑰高位清零造成的運算時間差,通過觀察、測算運算時間,運用統計學的技術破解運算金鑰。這實在是一個了不起的發現。

目前來看,這種攻擊方式還比較複雜,不容易執行。但是,一旦發現攻擊方法,如果業界沒有采取及時的措施,攻擊技術的改進速度是驚人的。“浣熊攻擊”出現,再一次敲了敲大門,警告我們要儘量避免計算時間偏差和計算算力偏差,謹慎地處理不可避免的計算時間偏差和算力偏差

相關文章