Elliptic-Curves

Curve25519-java 安全嗎?

  • August 18, 2014

我只有大約 2 週的密碼學經驗,主要是在 bitcoin.se 上提出問題。

Curve25519-java是否符合目前 Curve25519 標準?

Curve25519 本身是否安全?

換句話說,使用加密貨幣密鑰生成和交易簽名和驗證算法是否安全?

與 Curve25519 相關

到目前為止,Curve25519 似乎是安全的。但是,您必須提醒自己,Bernstein 博士指定 Curve25519 用於密鑰交換。含義:密鑰生成、交易簽名和驗證在某種程度上是不同的野獸——在跳到 Curve25519 之前,您可能需要對其進行交叉檢查。當然,Curve25519-java 支持簽名……但我不知道對事物的簽名方面進行徹底、經過嚴格審查的密碼分析。它可能存在問題,尚未檢查是否可以找到。

與 Curve25519-java 相關

NxtCoins.NL 報告稱,名為 Jesse James 的 BCT 使用者(也稱為 DoctorEvil)審查了 Java 實現,他似乎認為它是安全的。引用他的出版物:“Curve25519.java 和 Crypto.java 的加密評論”,最後修改於 2014 年 3 月 14 日:

Curve25519.java 和 Crypto.java 的加密評論

作者:Nextcoin.org上的 DoctorEvil由 BitcoinTalk.org 上

的 MSIN 贊助

TL;博士

NXT 的 Crypto.java 和 Curve25519.java 除了目前正在解決的簽名錯誤外,看起來很乾淨。

一般方法論

  1. 回顧了有關 Curve25519 和 EC-KCDSA 的主要/次要文獻,以針對 NXT 案例評估它們。
  2. 在 Python 中從頭開始重新實現這些原語(不同於 Java 版本)。
  3. 搜尋 Crypto.java/Curve25519.java 的每一行。
  4. 執行測試以發現我的實現和 Java 版本之間的輸出差異。

算法的選擇

Curve25519+EC-KCDSA 理論上是 NXT 案例的合理選擇。然而,由於加密貨幣應用程序以簽名驗證為主,Ed25519 可以說是一個更好的選擇(儘管不存在它的高質量 Java 實現,因此 NXT 的選擇是可以理解的)。

簽名錯誤

正如我(和其他人)之前所指出的,Curve25519.sign 函式有一個合法的缺陷,導致它偶爾會產生無效的簽名。之所以出現這個缺陷,可能是因為 Java 的原始 C 程式碼是從使用無符號原始整數類型移植而來的,而 Java 移植僅限於有符號類型。

BloodyRookie提出的更新檔本質上是合理的,儘管它可以被簡化並保持恆定時間。這是一個受他的更改啟發的固定符號函式:

(Java 原始碼)

public static final boolean sign(byte[] v, byte[] h, byte[] x, byte[] s) {
    // v = (x - h) s  mod q
    int w, i;
    byte[] h1 = new byte[32], x1 = new byte[32];
    byte[] tmp1 = new byte[64];
    byte[] tmp2 = new byte[64];     
    // Don't clobber the arguments, be nice!
    cpy32(h1, h);
    cpy32(x1, x);       
    // Reduce modulo group order
    byte[] tmp3=new byte[32];
    divmod(tmp3, h1, 32, ORDER, 32);
    divmod(tmp3, x1, 32, ORDER, 32);        
    // v = x1 - h1
    // If v is negative, add the group order to it to become positive.
    // If v was already positive we don't have to worry about overflow
    // when adding the order because v < ORDER and 2*ORDER < 2^256
    mula_small(v, x1, 0, h1, 32, -1);
    mula_small(v, v , 0, ORDER, 32, 1);     
    // tmp1 = (x-h)*s mod q
    mula32(tmp1, v, s, 32, 1);
    divmod(tmp2, tmp1, 64, ORDER, 32);
    for (w = 0, i = 0; i < 32; i++)
        w |= v[i] = tmp1[i];
    return w != 0;
 }

我已經用超過 100,000 個隨機鍵/消息測試了這個更新檔。

非標準算法調整

由 Crypto/Curve25519.java 實現的 EC-KCDSA 與IEEE P1363a的規範不完全匹配。尤其:

它將 EC-KCDSA 修改為確定性。恕我直言,這是一個很好的改變。但是,該實現使用了非標準的確定性簽名隨機數生成方案;在受到更多關注的基礎上,RFC6979 或 Ed25519 的方案可以說是更好的選擇。也就是說,我找不到所使用的方案有任何明顯錯誤。

該實現在w的計算方面也偏離了標準,而是將其計算為 H(H(m) + x1) (使用橢圓曲線密碼學指南的術語)。也就是說,我沒有發現這種偏差有什麼明顯的錯誤。它看起來不錯。

由於 Curve25519 使用僅 x 座標表示的複雜性,實現的 EC-KCDSA 密鑰生成也是非標準的。雖然這種模棱兩可的表示在 Diffie-Hellman 密鑰協議(Curve25519 專門為此設計)的上下文中沒有問題,但對於幼稚的 EC-KCDSA 來說是不方便的。該實現在密鑰生成期間使用了一種解決方法來解決此問題。雖然我找不到使用特定解決方法的任何其他人的參考,但在我看來它是合理的。

Curve25519.verify 使用蒙哥馬利階梯微分加法鏈的變體來計算曲線點 (vP + hG)。我在文獻中找不到對這個變體的任何引用,這很容易成為實現中最優化混淆的部分。話雖這麼說,但沒有什麼是錯誤的,我可以理解使用該變體的性能動機。

簽名延展性和簽名規範化

值得注意的是,Curve25519 的主要設計者 Daniel Bernstein 在其有關Ed25519簽名方案的論文中明確指出,他在設計簽名方案時並未將簽名延展性視為威脅模型的一部分。這應該讓那些認為他們能夠定義規範化約定以消除所有可延展性來源的人停下來。使用這樣的約定也許可以實現,但如果沒有正式的、經過同行評審的證據,就不能安全地假設。

據我所知,NXT 對我之前報告的攻擊的修復使其不受簽名延展性的影響。

一個與​​延展性相關的觀察:公鑰是 2^255-19 階欄位上的 EC x 座標。這意味著每個公鑰都有兩個 32 字節的表示。雖然是一個有趣的旁注,但我看不出這如何為 NXT 環境中的攻擊開闢了任何途徑。

我還想更正我之前的漏洞報告。Curve25519 中的 GROUP_ORDER 常量我報告為 2^252+2^124(由於誤讀程式碼註釋),但實際上定義為 7237005577332262213973186563042994240857116359379907606001950938285454250989,因為它使用了定義的利用程式碼。

側通道攻擊

該實現在 Crypto.sign 簽名期間通過定時洩漏少量(最多 2 位?)私鑰資訊,因為此函式在每次呼叫時從密碼片語重新計算簽名密鑰(Curve25519.keygen 在用於生成時不抗定時攻擊EC-KCDSA 密鑰)。我看不出有任何方法可以在 NXT 的上下文中利用這一點。但是,如果 NXT 曾經有一個程式碼路徑,外部觀察者可以導致目標按需簽署任何內容並觀察它的時間(例如,像一些互動式身份驗證協議)。

替代實施

作為我分析的一部分,我開發了加密原語的替代 Python 實現。如前所述,我的程式碼是教學性的(緩慢且不抗時序攻擊)。然而,由於它使用完全不同的 EC 算術(仿射 XY 座標與投影 XZ 座標),因此它可以作為 Java 版本數學的有用的健全性檢查(以及更易於理解的底層算法說明)。

在包含 1024 個簽名者的測試中,它產生了與(修補的)Java 實現相同的簽名輸出和相同的驗證結果。

其他檢查

送出到 NXT 儲存庫的 Curve25519(截至本報告發佈時)與Dmitry Skiba 分發的埠完全匹配。不是特別引人注目,但認為這值得為錫箔帽人群檢查。

EC-KCDSA 與 ECDH

它們兼容的正式安全證明超出了本次審查的範圍。然而,我的初步調查使我相信 NXT 可以將 EC-KCDSA 密鑰重新用於 ECDH 密鑰協議(NXT 目前不這樣做,但道路映射功能暗示了這一點)。

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