SubtleCrypto: phương thức sign()

Baseline Widely available *

This feature is well established and works across many devices and browser versions. It’s been available across browsers since January 2020.

* Some parts of this feature may have varying levels of support.

Secure context: This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

Note: This feature is available in Web Workers.

Phương thức sign() của giao diện SubtleCrypto tạo một signature số.

Nó nhận làm đối số một key để ký, một số tham số cụ thể cho thuật toán, và dữ liệu cần ký. Nó trả về một Promise sẽ được fulfill với chữ ký.

Bạn có thể sử dụng phương thức SubtleCrypto.verify() tương ứng để xác minh chữ ký.

Cú pháp

js
sign(algorithm, key, data)

Tham số

algorithm

Một chuỗi hoặc đối tượng chỉ định thuật toán chữ ký sẽ sử dụng và các tham số của nó:

  • Để sử dụng RSASSA-PKCS1-v1_5, truyền chuỗi RSASSA-PKCS1-v1_5 hoặc một đối tượng có dạng { name: "RSASSA-PKCS1-v1_5" }.
  • Để sử dụng RSA-PSS, truyền một đối tượng RsaPssParams.
  • Để sử dụng ECDSA, truyền một đối tượng EcdsaParams.
  • Để sử dụng HMAC, truyền chuỗi HMAC hoặc một đối tượng có dạng { name: "HMAC" }.
  • Để sử dụng Ed25519, truyền chuỗi Ed25519 hoặc một đối tượng có dạng { name: "Ed25519" }.
key

Một đối tượng CryptoKey chứa khóa sẽ dùng để ký. Nếu algorithm xác định một hệ mật mã khóa công khai, đây là khóa riêng tư.

data

Một đối tượng ArrayBuffer, TypedArray hoặc DataView chứa dữ liệu cần ký.

Giá trị trả về

Một Promise được fulfill với một ArrayBuffer chứa chữ ký.

Ngoại lệ

Promise bị reject khi gặp ngoại lệ sau:

InvalidAccessError DOMException

Ném lên khi khóa ký không phải là khóa cho thuật toán ký được yêu cầu hoặc khi cố sử dụng một thuật toán không xác định hoặc không phù hợp để ký.

Các thuật toán được hỗ trợ

Web Crypto API cung cấp các thuật toán sau có thể được sử dụng để ký và xác minh chữ ký.

RSASSA-PKCS1-v1_5, RSA-PSS, ECDSA và Ed25519 là các hệ mật mã khóa công khai sử dụng khóa riêng tư để ký và khóa công khai để xác minh. Tất cả các hệ thống này đều sử dụng thuật toán digest để hash thông báo thành một giá trị cố định ngắn trước khi ký.

  • Đối với RSASSA-PKCS1-v1_5 và RSA-PSS, lựa chọn thuật toán digest được truyền vào các hàm generateKey() hoặc importKey().
  • Đối với ECDSA, lựa chọn thuật toán digest được bao gồm trong tham số algorithm truyền vào hàm sign().
  • Đối với Ed25519, thuật toán digest luôn là SHA-512.

Thuật toán HMAC khác với các thuật toán còn lại ở chỗ nó không phải là hệ mật mã khóa công khai: nó sử dụng cùng thuật toán và khóa để ký và xác minh. Điều này có nghĩa là khóa xác minh phải được giữ bí mật, do đó thuật toán này không phù hợp cho nhiều trường hợp sử dụng chữ ký. Tuy nhiên, nó có thể là lựa chọn tốt khi người ký và người xác minh là cùng một thực thể.

RSASSA-PKCS1-v1_5

Thuật toán RSASSA-PKCS1-v1_5 được chỉ định trong RFC 3447.

RSA-PSS

Thuật toán RSA-PSS được chỉ định trong RFC 3447.

Nó khác với RSASSA-PKCS1-v1_5 ở chỗ nó kết hợp một salt ngẫu nhiên trong thao tác ký, vì vậy cùng một thông báo được ký với cùng một khóa sẽ không cho ra cùng chữ ký mỗi lần. Một thuộc tính bổ sung, xác định độ dài salt, được truyền vào các hàm sign()verify() khi chúng được gọi.

ECDSA

ECDSA (Elliptic Curve Digital Signature Algorithm - Thuật toán chữ ký số đường cong elliptic) là một biến thể của Thuật toán chữ ký số, được chỉ định trong FIPS-186, sử dụng Mật mã đường cong Elliptic (RFC 6090).

Chữ ký được mã hóa dưới dạng các giá trị s1s2 được chỉ định trong RFC 6090 (tương ứng được gọi là rs trong RFC 4754), mỗi giá trị trong mảng byte big-endian, với độ dài là kích thước bit của đường cong được làm tròn lên thành số nguyên byte. Các giá trị này được nối liền nhau theo thứ tự này.

Cách mã hóa này cũng đã được đề xuất bởi tiêu chuẩn IEEE 1363-2000, và đôi khi được gọi là định dạng IEEE P1363. Nó khác với cấu trúc chữ ký X.509, vốn là định dạng mặc định được tạo ra bởi một số công cụ và thư viện như OpenSSL.

Ed25519

Ed25519 là một thuật toán chữ ký số được xây dựng trên đường cong elliptic Curve25519, là một phần của họ thuật toán EdDSA (Edwards-Curve Digital Signature Algorithm) được định nghĩa trong RFC 8032.

HMAC

Thuật toán HMAC tính toán và xác minh các mã xác thực thông báo dựa trên hash theo tiêu chuẩn FIPS 198-1 (PDF).

Thuật toán digest sẽ sử dụng được chỉ định trong đối tượng HmacKeyGenParams mà bạn truyền vào generateKey(), hoặc trong đối tượng HmacImportParams mà bạn truyền vào importKey().

Thuật toán HMAC sử dụng cùng thuật toán và khóa để ký và xác minh: điều này có nghĩa là khóa xác minh phải được giữ bí mật, do đó thuật toán này không phù hợp cho nhiều trường hợp sử dụng chữ ký. Tuy nhiên, nó có thể là lựa chọn tốt khi người ký và người xác minh là cùng một thực thể.

Ví dụ

Note: Bạn có thể thử các ví dụ hoạt động trên GitHub.

RSASSA-PKCS1-v1_5

Đoạn mã này lấy nội dung của một hộp văn bản, mã hóa nó để ký, và ký nó bằng khóa riêng tư. Xem mã nguồn đầy đủ trên GitHub.

js
/*
Lấy nội dung của hộp văn bản "message", và mã hóa nó
thành dạng chúng ta có thể sử dụng cho thao tác ký.
*/
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

Đoạn mã này lấy nội dung của một hộp văn bản, mã hóa nó để ký, và ký nó bằng khóa riêng tư. Xem mã nguồn đầy đủ trên GitHub.

js
/*
Lấy nội dung của hộp văn bản "message", và mã hóa nó
thành dạng chúng ta có thể sử dụng cho thao tác ký.
*/
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

Đoạn mã này lấy nội dung của một hộp văn bản, mã hóa nó để ký, và ký nó bằng khóa riêng tư. Xem mã nguồn đầy đủ trên GitHub.

js
/*
Lấy nội dung của hộp văn bản "message", và mã hóa nó
thành dạng chúng ta có thể sử dụng cho thao tác ký.
*/
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

Đoạn mã này lấy nội dung của một hộp văn bản, mã hóa nó để ký, và ký nó bằng khóa bí mật. Xem mã nguồn đầy đủ trên GitHub.

js
/*
Lấy nội dung của hộp văn bản "message", và mã hóa nó
thành dạng chúng ta có thể sử dụng cho thao tác ký.
*/
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 (tạo cặp khóa, ký và xác minh)

Đoạn mã này tạo cặp khóa ký Ed25519, sử dụng khóa riêng tư để ký nội dung (đã mã hóa) của một <input> văn bản, sau đó xác minh chữ ký bằng khóa công khai. Nó được dẫn xuất từ mã nguồn này trên GitHub, mà bạn có thể chạy trực tiếp tại đây.

HTML

HTML định nghĩa một phần tử <input> chứa văn bản cần ký, và một nút bắt đầu thao tác tạo khóa, ký văn bản rồi xác minh chữ ký.

html
<label for="message">Nhập thông báo cần ký:</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 đầu tiên lấy các phần tử <input> #sign-button#message, sau đó thêm trình lắng nghe cho sự kiện click trên nút. Trình xử lý sự kiện xóa log và chạy các thao tác khác truyền nội dung của phần tử <input>.

js
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);
});

Đầu tiên nó tạo khóa bằng thuật toán Ed25519, sau đó mã hóa văn bản và ký văn bản đó bằng khóa riêng tư. Cuối cùng nó gọi SubtleCrypto.verify() với khóa công khai để xác minh chữ ký.

js
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);
  }
}

Kết quả

Đặc tả kỹ thuật

Specification
Web Cryptography Level 2
# SubtleCrypto-method-sign

Tương thích trình duyệt

Xem thêm