Side-Channel-Attack

為什麼不在常數時間比較中使用 <>==

  • August 18, 2016

我正在比較儲存在數組中的秘密數據ab看看哪個值更大。我目前的(偽)程式碼如下所示:

unsigned char smaller = 0, bigger = 0;
for (i = 0; i < size; ++i) {
  smaller |= (!bigger)  & (a[i] < b[i]);
  bigger  |= (!smaller) & (a[i] > b[i]);
}
return bigger;

但是當我查看(例如)sodium_compare時,我發現他們沒有使用<or>運算符。相反,它們減去值並執行一些位操作,其中將一個字節移動 8 位(作為旁注:這不會導致 C 中的未定義行為嗎?)。

有沒有理由避免使用<and>運算符?

類似地,相等的恆定時間比較通常通過按字節進行 xor ( ) 並取所有值^的 or ( ) 來實現。在那種情況下|是否有理由偏愛?^``==

如果條件滿足, C 比較運算符(嚴格關係< <= > >=和相等== !=)產生 1,否則產生 0。在取決於 CPU 和有時選項的某些實現(編譯器)上,這可以通過以下程式碼實現:

; int a = ..., b = ...;
; int x = a > b;
 move a, r0
 compare r0, b ; sometimes subtract with value ignored and only flags used
 bgtr lab1
   move 0, r1
   br lab2
lab1:
   move 1, r1
lab2:
 move r1, x

這取決於條件是真還是假,執行不同的指令序列。取決於 CPU,如果它有今天很多(不是全部)的分支預測/推測,這取決於條件分支是否被正確預測,而這又取決於許多其他通常無法完全分析的因素,這可能需要可以檢測到的不同時間量(儘管通常很小)。

一些現代 CPU 有條件移動指令,甚至是邏輯化標誌指令,可以避免這個問題,但是在編寫要移植到未知編譯器版本和環境的原始碼時,您不能確定這些是否存在並且(如果所以)使用。

實際上,您不能保證即使按位運算也是恆定時間,但實際上它們是您最好的選擇。

類似地,您的程式碼中的邏輯否定運算符!可能由類似這樣的東西實現,這不是恆定時間:

move x, r0
test r0 ; sometimes included in the move
bzer lab1   ; (EDIT)
 move 0, r1
 br lab2
lab1:
 move 1, r1
lab2:
; use r1 as result

沒有未定義的行為:

移位大於或等於左操作數寬度的計數是 UB。即使它來自unsigned char您連結的程式碼中的 as ,移位的左操作數也受 6.3.1.1 的整數提升(儘管不是 6.3.1.8 的通常算術轉換)的影響,因此左操作數始終具有寬度至少 16 並且他們移動 8 沒關係。

同樣左移帶有負值或溢出值的有符號類型(即輸入的高 N 幅度位中的至少一個非零)是 UB。他們不會左移。

用負值右移有符號類型是實現**定義的:符號位可以傳播或移出。它們確實會右移有時為負的值,但它們會立即屏蔽結果,以便不使用可能受此 IB 影響的位。

引用自:https://crypto.stackexchange.com/questions/39429