SubtleCrypto: sign() 方法
Baseline 广泛可用 *
注意:此功能在 Web Workers 中可用。
sign() 是 SubtleCrypto 接口的一个方法,用于生成数字 签名。
它接受以下参数:用于签名的 密钥、算法特定的参数以及要签名的数据。它返回一个 Promise,该 Promise 将以签名结果 fulfilled。
您可以使用相应的 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,它 fulfilled 一个包含签名的 ArrayBuffer。
异常
当遇到以下异常时,Promise 将被拒绝
InvalidAccessErrorDOMException-
当签名密钥不是请求签名算法的密钥,或者尝试使用未知算法或不适用于签名的算法时抛出。
支持的算法
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
RFC 3447 中指定了 RSASSA-PKCS1-v1_5 算法。
RSA-PSS
RFC 3447 中指定了 RSA-PSS 算法。
它与 RSASSA-PKCS1-v1_5 不同之处在于,它在签名操作中包含了一个随机盐,因此用同一密钥签名同一消息每次生成的签名都会不同。在调用 sign() 和 verify() 函数时,会传入一个定义盐长度的附加属性。
ECDSA
ECDSA(椭圆曲线数字签名算法)是数字签名算法 (DSA) 的一个变体,在 FIPS-186 中指定,它使用了椭圆曲线密码学(RFC 6090)。
签名被编码为 RFC 6090 中指定的 s1 和 s2 值(在 RFC 4754 中分别称为 r 和 s),每个值都以大端字节数组的形式表示,其长度为曲线的比特大小向上舍入到最接近的整数字节。这些值按此顺序连接在一起。
此编码也是由 IEEE 1363-2000 标准提出的,有时也被称为 IEEE P1363 格式。它与 X.509 签名结构不同,后者是一些工具和库(如 OpenSSL)默认生成的格式。
Ed25519
Ed25519 是一种基于 Curve25519 椭圆曲线的数字签名算法,该曲线属于 RFC 8032 中定义的爱德华兹曲线数字签名算法 (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 加密级别 2 # SubtleCrypto-method-sign |
浏览器兼容性
加载中…
另见
SubtleCrypto.verify().- RFC 3447 指定了 RSASSA-PKCS1-v1_5。
- RFC 3447 指定了 RSA-PSS。
- FIPS-186 指定了 ECDSA。
- FIPS 198-1 指定了 HMAC。