如何正確實施集成加密方案?
我正在開發一個 REST 客戶端(來自 Android 銷售點),我在其中獲得了一個公共 RSA 2048 位密鑰,我需要加密交易資訊。由於該單個塊無法使用公鑰加密(AFAIK 也不應該),我們需要使用 AES 128 位對其進行加密。所以我們生成一個隨機密鑰(使用 KeyGenerator 類),加密資訊並發送在其公鑰下加密的 AES 密鑰。AES 處於 ECB 模式,因為我知道他們的要求是不安全的。
所以問題是:這種方法有什麼陷阱(除了歐洲央行)?
我的想法是實現一種 ECIES(但沒有橢圓曲線),其中使用密鑰派生函式(儘管我是菜鳥,不知道如何實現它)並使用經過身份驗證的加密方法,如 AES-GCM。
為了擴展這個問題,我會喜歡一些上下文,因為我認為我的資訊很少並且需要“完全連接”。
你有正確的想法!有一個非常通用的公鑰加密結構,稱為 KEM/DEM,其工作原理如下: $ m $ :
- 密鑰封裝機制,KEM:生成密鑰 $ k $ 和一個封裝 $ y $ 使用公鑰。
- 數據封裝機制,DEM:使用 $ k $ 進行身份驗證和加密 $ m $ 給出一個經過驗證的密文 $ c $ .
- 傳輸封裝 $ y $ 連同密文 $ c $ .
接收者可以通過密鑰恢復 $ k $ 從 $ y $ 然後解密 $ c $ .
對於 RSA,您可以使用公鑰製作如下 KEM $ n $ :
- 選擇一個整數 $ x $ 之間 $ 0 $ 和 $ n $ 均勻隨機。
- 計算 $ y = x^3 \bmod n $ .
- 計算 $ k = H(x) $ , 在哪裡 $ H $ 是(比如說)SHA-256。
收件人使用解決方案的秘密知識 $ d $ 至 $ 3d \equiv 1 \pmod{\lambda(n)} $ , 在哪裡 $ \lambda(n) = \operatorname{lcm}(p - 1, q - 1) $ 如果 $ n = pq $ , 恢復 $ x = y^d \bmod n $ , 然後計算相同的 $ k = H(x) $ .
DEM 的安全要求適中。像 AES-GCM 或 NaCl crypto_secretbox_xsalsa20poly1305 這樣的經過身份驗證的密碼,將 nonce 設置為零,就可以了。(如果必須使用 AES,我推薦使用 AES-256,以避免多目標攻擊;我推薦使用 AES-GCM 上的 crypto_secretbox_xsalsa20poly1305,以避免在快速軟體實現中對 AES 和 GHASH 進行側通道攻擊。)
ECIES 是 KEM/DEM 結構的一個範例——用於公鑰 $ A $ 在具有標準基點的橢圓曲線上 $ B $ , 你選擇一個標量 $ t $ 均勻隨機,計算 $ T = [t]B $ , 導出密鑰 $ k = H([t]A) $ , 並使用 $ T $ 作為密鑰的封裝 $ k $ 您在經過身份驗證的密碼中使用它來加密消息;收件人知道秘密 $ a $ 這樣 $ A = [a]B $ , 並給定 $ T $ 恢復 $ H([a]T) = H([a\cdot t] B) = H([t\cdot a]B) = H([t]A) = k $ 解密經過身份驗證的密文。
你也可以生成 $ k $ 獨立並將其硬塞到像 RSAES-OAEP 這樣的封裝中。但是,雖然這可能是出於慣性進行 RSA 加密的最常見方法,但它比必要的複雜得多。
因此,為了回答實際問題並在@eckes 的幫助下:
- 完全推薦使用橢圓曲線密碼進行新的開發。避免 RSA:你所知道的關於公鑰加密的一切都是錯誤的
ECIES 是一個不錯的選擇,在 C# 中實現它的一個很好的庫是 Inferno:https ://securitydriven.net/inferno
在 Java(以及 C#)中有 BouncyCastle,儘管 Inferno 的作者抨擊它說這是“一個巨大的(145k LOC),表現不佳的加密博物館目錄(其中一些是古老的),舊的 Java 實現同樣移植到 -舊的.NET(2.0?)”。這是相關的,因為它知道儘管加密算法在其定義中是安全的,但糟糕的實現會導致不安全的系統。
- 請記住,加密與身份驗證不同: 如果您將字母 AES 輸入到您的程式碼中,那麼您做錯了。實際的集成加密方案需要經過身份驗證的加密方法和密鑰派生功能。
- 如果使用 JSON 的 REST API,則 JWE 的建議庫是:https ://github.com/jwtk/jjwt 但是,請注意:使用 JWT 進行會話。