可以使用數字簽名生成 AES 加密的密鑰嗎?
我想看看使用數字簽名是否是一種安全且合理的方式來生成 AES 加密的密鑰。
流程如下:
使用者
m
使用他們的私鑰簽署消息。他們實際上對 的雜湊進行簽名,m
但這作為數字簽名創建功能的一部分進行了處理。這將返回數字簽名s
。提供的保密資訊
s
是用於為 AESs
創建密鑰的安全摘要。k
它們的密鑰
k
將按如下方式創建:const crypto = require('crypto'); crypto.scrypt(s, 'unique-salt', keyLength, (err, key) => { console.log(key.toString('hex')); // 12dd454fb... });
其中函式的第一個參數
s
是使用者創建的數字簽名。Node 加密包的文件沒有具體說明此參數的任何要求。
我了解,如果數字簽名是由其他人獲得的,那麼該人可以解密和加密消息,但是如果該人獲得用作該參數的任何字元串,也可以這樣說。
所以這兩個問題是:
- 這是為 AES 生成密鑰的安全且合適的方式嗎?假設數字簽名是唯一的,並且難以被無權訪問私鑰的人猜測。並假設用於創建密鑰的數字簽名是保密的。
- 安全性是否取決於
m
已簽名的消息?這也需要保密嗎?我的假設是,消息是什麼並不重要,即使槌知道這條消息,他們也無法創建正確的數字簽名,因為他們沒有私鑰。謝謝
是的,你可以使用它。根據定義,攻擊者不應該能夠在沒有私鑰的情況下對*任何特定消息進行簽名。*因此,如果是這種情況,那麼簽名確實可以用作對稱密鑰,並且我知道一個這樣使用它的實例(或至少作為秘密,而不是秘密密鑰)。
但是,您在這樣做時應該小心。一些簽名算法是不確定的,這可能會使事情複雜化。在最壞的情況下,它可能使簽名算法完全不安全。充其量您可能必須更改簽名生成常式以注入種子或隨機值。它還需要您儲存該種子或隨機值,這可能與您的案例要求背道而馳。請注意,如果有關隨機數生成的任何內容髮生了變化——算法、提取機製或整數提取——那麼您可能會得到錯誤的密鑰(是的,我已經看到了這種情況)。
但是,如果您使用確定性版本的 RSA(PKCS#1 v1.5 填充)或確定性 ECDSA,那麼您應該沒問題。
但是,在數據之後使用 KDF 是正確的。對稱密鑰應提取簽名中的所有隨機性以確保安全(可能隨後進行密鑰擴展以達到正確的大小,但這通常不是必需的)。
scrypt
但是通常用於密碼。這很好,但是您可能不需要鹽或工作因子來拉伸密鑰(因為簽名中的隨機性無論如何都應該足夠高)。因此,如果scrypt
需要也可以,但通常您寧願使用 KBKDF,例如 HKDF 或僅使用 HKDF-Extract。如果您有權訪問私鑰值,您不妨使用 KDF。
我絕對建議您使用至少與對稱密鑰具有相同強度的簽名生成算法。當然,KDF 函式也是如此;您可以在keylength.com找到詳細資訊。
此外,您可能要記住,對稱密碼學很難使用成熟的量子電腦進行攻擊,而非對稱算法則不然(儘管此方案可能比通用簽名生成方案更難攻擊,具體取決於它的使用方式)。
另一個實現說明:簽名生成函式不希望您對簽名保密。例如,硬體模組可能能夠將正常派生的對稱密鑰保存在 HSM 內。另一方面,它可能會毫不費力地導出簽名,因為簽名值應該是公開的。
對簽名值的側通道攻擊也可能是可能的,很難提前判斷。所以雖然這個方案理論上應該是合理的,但除非沒有其他辦法,否則還是極不建議這樣做。