Implementation
JVM 語言中的時序安全
如何用 JVM 語言(Java、Scala、Clojure…)編寫時間安全程式碼?是否有可能使像 BouncyCastle 這樣的庫能夠安全地抵禦時間攻擊?
我知道即使在 C 語言中,也很難把這些事情做好——在 C 語言中,您可以查看生成的彙編程式碼,至少可以預測您的目標 CPU 將如何執行它。
在 JVM 語言中,您不知道 JVM 將如何將您的程式碼轉換為機器程式碼或將執行哪些執行時優化。
編輯:我並不真正擔心本地定時攻擊,而是擔心遠端可利用的攻擊。
理論是:不要試圖用 JVM 語言或其他本質上解釋但可能有時編譯的語言編寫時間安全程式碼;相當
- 使用舒適的 JVM 語言呼叫的時序安全庫。典型範例:在通過 AVA_VAN.5 擴充將通用標準評估傳遞給 EAL5+ 的 JavaCard 中,可以肯定的是 AES(如果可用)是時序安全的。
- 盡可能避免首先需要時間安全。典型範例:與其嘗試在恆定時間內將所謂的 16 字節值與參考 16 字節值進行比較,不如繪製一個新的 AES 密鑰,使用此 AES 密鑰加密所謂的和參考值(使用恆定時間 AES 實現) ,然後使用手頭的任何方法比較結果。
- 作為上述的變體,使用降低定時攻擊效率的對策,例如致盲。
上述方法也傾向於對抗時序以外的側通道攻擊,例如功率分析。
當市場壓力另有規定時,期權應盡可能少地進行相對安全的押注;當一個人有幸知道實際目標時,仔細檢查它們。例如,寫的時候
// 比較兩個字節數組,這樣時間就不會在差異所在的地方洩漏 公共靜態布爾 myEqualByteArrays[(byte[] a, byte[] b) { int j = a.length; 如果 (j != b.length) 返回假;// 數組長度不同 詮釋 r = 0; // 將保持為零,直到發現差異 而 (--j>=0) r |= a[j] ^ b[j]; 返回 r==0; // 當且僅當數組匹配時為真 }
僅假設
- 二元運算
^
和|
是恆定時間的(&
一元~
也可能是,儘管我們在這個例子中不需要它);- 即使對以下內容的深入分析表明它們可以退出,循環也不會退出。
到目前為止,如果我遇到任何打破這些假設的事情,我還沒有意識到!
不能安全地假定為常數時間的事情的例子:
- 任何使用
if
,switch
..- 短路運算符
&&
和||
- 邏輯不
!
- 數組訪問(例如由於記憶體)。
- 整數乘法(包括常數):一些 CPU 的乘法時間取決於一個參數;範例包括這個和這個32 位 CPU(感謝製造商記錄它)。
- 當然,除法(包括常數)。
+
對比編譯器、執行時和硬體組合支持的更大數據類型的操作:可以想像,即使在內部使用 32位-
變數的某些 64 位類型中,某些內部進位也可能導致數據相關的時序依賴性。這比增量更不用擔心變數添加,增量可以在執行時實現或自動過度優化為:增加低半部分,如果不是零,則增加高半部分。- 班次:時間通常取決於班次計數。
- 通過常量移位右移:這可能取決於移位參數的符號或高位(對於無符號類型不太可能;在 Java 中,使用無符號運算符的可能性低於有符號
>>>
運算符移位運算符>>
)。- 選擇運算符
?:
;但是,在 Java 中,僅限於內置有符號2 的補碼32 位類型int
,替代品d = (a==0) ? b : c;
可能是// 計算 a 中所有位到 d 低位的 OR d = (a >>> 1) | 一個; d = (d >>> 2) | d; d = (d >>> 4) | d; d = (d >>> 8) | d; d = (d >>>16) | d; d = -(d&1); // 在整個 d 上複製 d 的低位 d = ((b^c)&d)^b; // 如果 a==0 選擇 b,否則選擇 c
如果效率確實是次要的,那麼該技術可以擴展到,例如,在橢圓曲線上的某個二進制域上的恆定時間點乘法。