使用JavaScript Crypto Subtle签名:需签编码消息还是其哈希值?
使用Web Crypto Subtle API进行消息签名:直接传编码消息还是哈希值?
问题背景
在使用浏览器内置的JavaScript Crypto Subtle API进行消息签名时,我们应当签名编码消息的哈希值,还是编码消息本身?
根据密码学领域的共识:
如果签名前不对数据进行哈希,就无法拥有统一的签名算法,因为只能对特定大小以内的消息签名,消息过大时仍需哈希,这并非签名方案的良好实践。更重要的是,部分签名方案(如RSA)在不哈希数据时易被伪造。为保证签名安全性不受消息大小影响,通常采用哈希后签名的范式,即先对明文消息哈希,再执行签名操作,这样算法可兼容任意大小的消息。
但查看MDN官方示例代码时发现,示例直接将编码后的消息传入sign函数:
function getMessageEncoding() { const messageBox = document.querySelector(".ecdsa #message"); let message = messageBox.value; let enc = new TextEncoder(); return enc.encode(message); } let encoded = getMessageEncoding(); let signature = await window.crypto.subtle.sign( { name: "ECDSA", hash: { name: "SHA-384" }, }, privateKey, encoded );
示例仅在算法参数中指定了hash: { name: "SHA-384" },却直接签名编码消息而非其哈希值。这让人产生疑问:示例的做法是否有误?sign函数是否会自动对编码消息进行哈希后再签名?是否无需手动执行哈希操作?
解答
MDN示例的做法完全正确,无需手动哈希消息。
SubtleCrypto的sign函数在指定了hash参数的情况下,会自动完成「哈希消息→签名哈希值」的完整流程,开发者只需要传入编码后的原始消息即可,原因如下:
- 对于ECDSA、RSA-PSS这类标准签名算法,「先哈希再签名」是算法本身要求的安全流程,API将这一步封装起来,既符合密码学最佳实践,也避免了开发者手动哈希时可能出现的错误(比如哈希算法不匹配、编码错误等)。
- 这种设计完全契合哈希后签名的范式:API自动处理任意大小的消息哈希,保证签名算法对消息大小的兼容性,同时规避了未哈希签名带来的伪造风险。
需要注意:如果手动对消息哈希后再传入sign函数,会导致双重哈希,最终签名的是「消息哈希的哈希值」,这不符合标准签名流程,会导致后续验证签名失败。
内容的提问来源于stack exchange,提问作者sudoExclamationExclamation
相关产品推荐
相关产品推荐

