SubtleCrypto:sign() 方法
sign()
方法是 SubtleCrypto
接口的方法,用于生成数字签名。
它以 密钥、一些特定于算法的参数和要签名的数据作为参数。它返回一个 Promise
,该承诺将通过签名来完成。
可以使用相应的 SubtleCrypto.verify()
方法来验证签名。
语法
sign(algorithm, key, data)
参数
algorithm
-
一个字符串或对象,指定要使用的签名算法及其参数
- 要使用 RSASSA-PKCS1-v1_5,请传递字符串
RSASSA-PKCS1-v1_5
或一个形如{ name: "RSASSA-PKCS1-v1_5" }
的对象。 - 要使用 RSA-PSS,请传递一个
RsaPssParams
对象。 - 要使用 ECDSA,请传递一个
EcdsaParams
对象。 - 要使用 HMAC,请传递字符串
HMAC
或一个形如{ name: "HMAC" }
的对象。 - 要使用 Ed25519,请传递字符串
Ed25519
或一个形如{ name: "Ed25519" }
的对象。
- 要使用 RSASSA-PKCS1-v1_5,请传递字符串
key
-
一个
CryptoKey
对象,包含用于签名的密钥。如果algorithm
标识了公钥密码系统,则这是私钥。 data
-
一个
ArrayBuffer
、一个TypedArray
或一个DataView
对象,包含要签名的数据。
返回值
一个 Promise
,它通过包含签名的 ArrayBuffer
来完成。
异常
当遇到以下异常时,承诺将被拒绝
InvalidAccessError
DOMException
-
当签名密钥不是请求签名算法的密钥,或者尝试使用未知或不适合签名的算法时,就会引发此错误。
支持的算法
Web Crypto API 提供了以下可用于签名和签名验证的算法。
RSASSA-PKCS1-v1_5、RSA-PSS、ECDSA 和 Ed25519 是公钥密码系统,它们使用私钥签名,使用公钥验证。这些系统都使用摘要算法 将消息哈希到一个较短的固定大小,然后再签名。
- 对于 RSASSA-PKCS1-v1_5 和 RSA-PSS,摘要算法的选择传递给
generateKey()
或importKey()
函数。 - 对于 ECDSA,摘要算法的选择包含在传递给
sign()
函数的algorithm
参数中。 - 对于 Ed25519,摘要算法始终是 SHA-512。
HMAC 算法与其他算法不同,它不是公钥密码系统:它使用相同的算法和密钥进行签名和验证。这意味着验证密钥必须保密,这也意味着此算法不适合许多签名用例。但是,当签名者和验证者是同一个实体时,它是一个不错的选择。
RSASSA-PKCS1-v1_5
RSASSA-PKCS1-v1_5 算法在 RFC 3447 中定义。
RSA-PSS
ECDSA
Ed25519
Ed25519 是一种基于 Curve25519 椭圆曲线的数字签名算法,它是 RFC 8032 中定义的 Edwards-Curve 数字签名算法 (EdDSA) 算法系列的一部分。
HMAC
HMAC 算法根据 FIPS 198-1 标准 (PDF) 计算和验证基于哈希的消息认证码。
要使用的摘要算法在您传递给 generateKey()
的 HmacKeyGenParams
对象或传递给 importKey()
的 HmacImportParams
对象中指定。
HMAC 算法使用相同的算法和密钥进行签名和验证:这意味着验证密钥必须保密,这也意味着此算法不适合许多签名用例。但是,当签名者和验证者是同一个实体时,它是一个不错的选择。
示例
注意: 您可以在 GitHub 上尝试这些工作示例。
RSASSA-PKCS1-v1_5
此代码获取文本框的内容,对其进行编码以供签名,并使用私钥对其进行签名。在 GitHub 上查看完整源代码。
/*
Fetch the contents of the "message" textbox, and encode it
in a form we can use for the sign operation.
*/
function getMessageEncoding() {
const messageBox = document.querySelector(".rsassa-pkcs1 #message");
let message = messageBox.value;
let enc = new TextEncoder();
return enc.encode(message);
}
let encoded = getMessageEncoding();
let signature = await window.crypto.subtle.sign(
"RSASSA-PKCS1-v1_5",
privateKey,
encoded,
);
RSA-PSS
此代码获取文本框的内容,对其进行编码以供签名,并使用私钥对其进行签名。在 GitHub 上查看完整源代码。
/*
Fetch the contents of the "message" textbox, and encode it
in a form we can use for the sign operation.
*/
function getMessageEncoding() {
const messageBox = document.querySelector(".rsa-pss #message");
let message = messageBox.value;
let enc = new TextEncoder();
return enc.encode(message);
}
let encoded = getMessageEncoding();
let signature = await window.crypto.subtle.sign(
{
name: "RSA-PSS",
saltLength: 32,
},
privateKey,
encoded,
);
ECDSA
此代码获取文本框的内容,对其进行编码以供签名,并使用私钥对其进行签名。在 GitHub 上查看完整源代码。
/*
Fetch the contents of the "message" textbox, and encode it
in a form we can use for the sign operation.
*/
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,
);
HMAC
此代码获取文本框的内容,对其进行编码以供签名,并使用密钥对其进行签名。在 GitHub 上查看完整源代码。
/*
Fetch the contents of the "message" textbox, and encode it
in a form we can use for the sign operation.
*/
function getMessageEncoding() {
const messageBox = document.querySelector(".hmac #message");
let message = messageBox.value;
let enc = new TextEncoder();
return enc.encode(message);
}
let encoded = getMessageEncoding();
let signature = await window.crypto.subtle.sign("HMAC", key, encoded);
Ed25519(密钥生成、签名和验证)
此代码生成一个 Ed25519 签名密钥对,使用私钥对文本 <input>
的(编码)内容进行签名,然后使用公钥验证签名。它来自 GitHub 上的此源代码,您可以在 此处实时运行。
HTML
HTML 定义了一个包含要签名的文本的 <input>
元素,以及一个启动创建密钥、签名文本然后验证签名的操作的按钮。
<label for="message">Enter a message to sign:</label>
<input
type="text"
id="message"
name="message"
size="25"
value="The lion roars near dawn" />
<input id="sign-button" type="button" value="Run" />
JavaScript
JavaScript 首先获取 #sign-button
和 #message
<input>
元素,然后为按钮添加 click
事件的监听器。事件处理程序清除日志并运行其他操作,并将 <input>
元素的内容传递给它们。
const button = document.querySelector("#sign-button");
const input = document.querySelector("#message");
button.addEventListener("click", () => {
// Clear log
logElement.innerText = "";
logElement.scrollTop = logElement.scrollHeight;
// Run test
test(input.value);
});
首先,它使用 Ed25519 算法生成密钥,然后使用私钥对文本进行编码和签名。最后,它使用公钥调用 SubtleCrypto.verify()
来验证签名。
async function test(data) {
log(`Message: ${data}`);
try {
// Generate keys
const { publicKey, privateKey } = await crypto.subtle.generateKey(
{
name: "Ed25519",
},
true,
["sign", "verify"],
);
log(`publicKey: ${publicKey}, type: ${publicKey.type}`);
log(`privateKey: ${privateKey}, type: ${privateKey.type}`);
// Encode data prior to signing
const encoder = new TextEncoder();
encodedData = encoder.encode(data);
// Log the first part of the encoded data
const shorterEncodedBuffer = new Uint8Array(encodedData.buffer, 0, 14);
log(
`encodedData: ${shorterEncodedBuffer}...[${encodedData.byteLength} bytes total]`,
);
//log(`encodedData: ${encodedData}`);
// Sign the data using the private key.
const signature = await crypto.subtle.sign(
{
name: "Ed25519",
},
privateKey,
encodedData,
);
// Log the first part of the signature data
const signatureBuffer = new Uint8Array(signature, 0, 14);
log(
`signature: ${signatureBuffer}...[${signature.byteLength} bytes total]`,
);
// Verify the signature using the public key
const verifyResult = await crypto.subtle.verify(
{
name: "Ed25519",
},
publicKey,
signature,
encodedData,
);
// Log result - true if the text was signed with the corresponding public key.
log(`signature verified?: ${verifyResult}`);
} catch (error) {
log(error);
}
}
结果
规范
规范 |
---|
Web 加密 API # SubtleCrypto-method-sign |
浏览器兼容性
BCD 表格仅在浏览器中加载
另请参阅
SubtleCrypto.verify()
.- RFC 3447 指定 RSASSA-PKCS1-v1_5。
- RFC 3447 指定 RSA-PSS。
- FIPS-186 指定 ECDSA。
- FIPS 198-1 指定 HMAC。