If/else 是否容易受到定時側通道攻擊?
我在 C++ 中有一個分支:
if (x & 1) { x = function_1(x); } else { x = function_2(x); }
如果
function_1
和function_2
是恆定時間並且計算它們需要相同的時間,那麼這種分支仍然容易受到側通道攻擊嗎?攻擊者能否以某種方式知道執行了哪個條件?
是的,if/else 容易受到時間攻擊。與其他答案一樣,選擇要通過數組索引呼叫的函式也是如此。
對於高級語言中的恆定時間執行,唯一可靠的解決方案是:確保程式碼執行路徑和記憶體訪問模式獨立於數據。
這排除了呼叫單個
function_1
或function_2
(如問題的程式碼和所述其他答案所做的那樣)和索引數組,基於在控制下或以對手可觀察到的方式變化的數據,甚至部分和間接。如果呼叫這兩個函式的額外成本是可以容忍的,並且函式的行為是明確定義的並且無論其輸入的低位如何都可以接受,那麼這將適用於大多數目前的 C 編譯器和硬體:
m = -(x&1); // mask variable; assumes m and x are int x = (function_1(x) & m) | (function_2(x) & ~m);
或等效地
x = function_1(x) & -(x&1) | function_2(x) & ~ -(x&1);
這將呼叫這兩個函式,並適當地選擇結果,使用該遮罩
-(x&1)
的所有位都為 1,表示奇數x
,否則為 0。我不知道自 1985 年以來引入的任何 CPU + C 編譯器會依賴於
x
由該技術引入。關於加密的恆定時間實現的現代文獻假設沒有,不用說。儘管現代高性能 CPU 的執行時間是未指定的,並且從應用程序程序員的角度來看可能會發生不可預測的變化(例如,由於編譯器/連結器及其選項、程式碼和數據對齊、中斷、記憶體等待狀態和刷新周期) 、記憶體、管道、推測執行、分支預測器、同一核心/CPU/連結 CPU 上的其他執行緒、同一核心上執行緒之間的資源仲裁、虛擬化、BIOS 或 VM 設置,以及看似無窮無盡的有缺陷的微程式碼更改流減輕最新報導的側通道攻擊的性能……)重要的是,問題中的那個不切實際的假設
function_1
並且function_2
是常數時間,計算它們需要相同的時間可以用似是而非的和可證偽的代替:
的執行時間的變化
function_1
與 的值不相關x
。function_2
具有相同的屬性。警告 1:C/C++ 語言僅對獲得的結果提供保險,對執行時間不提供保險。我知道沒有編譯器手冊關心,有些 CPU 沒有文件。
警告 2:
-(x&1)
根據低位獲取遮罩x
是一個眾所周知的習慣用法,現在幾乎適用於所有 CPU。那是因為他們使用 二進制補碼約定,用-1
全1表示。但是我忘記了 C 是否承諾隱藏硬體可能具有的任何不同行為(我把它留給有用的評論)。無論如何,這都需要確定。
x
警告 3:由於 C 提升規則,可能需要根據類型進行調整。我通常會1
轉換為 的類型x
,例如,如果x
是uint32_t
,我會使用-(x&(uint32_t)1)
,如果沒有編譯器警告,我會對此感到滿意。一些編譯器在取無符號表達式的負數時會抱怨。根據 C 標準,它們是錯誤的。簡單的方法是鞠躬和使用
(0-(x&1))
,並像上面一樣轉換常量。另一種方法是使用一些編譯指示或選項來禁用該投訴。根據我的經驗,另一個毫無希望的方法是發送問題報告。精心製作的參數轉到 NUL(/dev/null 的本地等價物),包括:該構造有用、通用、ISO C 明確支持;並發出警告可能會使所有警告不分青紅皂白地沉默。注意:我假設
function_1
and的返回類型function_2
與x
.自 1980 年代以來,在對手也可以執行程式碼的標準 CPU 上執行安全/加密一直很脆弱。有一些有用的進步:使用記憶體管理單元、安全環或飛地進行程序隔離。有一些軟體啟發式方法可以將漏洞降低到可接受的水平。但是,到目前為止,還沒有靈丹妙藥。
因此,當風險很高時,通常最好將安全功能解除安裝到專為安全而非性能而設計的受信任硬體(智能卡、安全 CPU、HSM、TPM ……);以及對手無法執行程式碼的地方(最簡單的最好的),或者是設計的。