SubtleCrypto.encrypt()

Baseline Widely available

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

安全上下文: 此项功能仅在一些支持的浏览器安全上下文(HTTPS)中可用。

SubtleCrypto 接口的 encrypt() 方法用于加密数据。

它以用于加密的密钥、一些特定于算法的参数,以及待加密的数据(也称为“明文”)为参数;返回一个 Promise,会兑现加密后的数据(也称为“密文”)。

语法

js
encrypt(algorithm, key, data)

参数

algorithm

一个对象,用于指定使用的算法,以及需要的任何额外的参数:

key

一个包含了密钥的、用于加密的 CryptoKey 对象。

data

一个包含了待加密的数据(也称为明文)的 ArrayBufferTypedArrayDataView 对象。

返回值

一个 Promise,会兑现一个包含密文的 ArrayBuffer

异常

当遇到以下异常时,promise 将会被拒绝:

InvalidAccessError DOMException

当针对提供的密钥执行的操作无效时(如:加密算法无效,或特定于加密算法的密钥无效),将抛出该错误。

OperationError DOMException

当特定于操作的原因使得操作失败时(如:算法参数的大小无效,或 AES-GCM 明文长度超过 239−256 字节),将抛出该错误。

支持的算法

Web Crypto API 提供了支持 encrypt()decrypt() 操作的四种算法。

其中的 RSA-OAEP 算法是一种公钥加密系统

其他三种算法则都是对称加密算法,并且它们都是基于同一种基础加密,即 AES(Advanced Encryption Standard)。它们不同之处在于模式。Web Crypto API 支持以下三种 AES 模式:

  • CTR(Counter Mode,计数器模式)
  • CBC (Cipher Block Chaining,密码块链接)
  • GCM (Galois/Counter Mode,伽罗瓦/计数器模式)

强烈建议使用认证加密authenticated encryption),它可以检测密文是否已被攻击者篡改。使用认证也可以避免选择密文攻击chosen-ciphertext attack),即攻击者可以请求系统解密任意的消息,然后使用解密结果来倒推出关于密钥的一些信息。虽然 CTR 和 CBC 模式可以添加认证,但是它们默认不提供该操作,并且在手动实现它们的时候,很容易犯一些微小但严重的错误。GCM 提供了内置的认证,因此常常推荐使用这种模式。

RSA-OAEP

RSA-OAEP 公钥加密系统,规范定于 RFC 3447

AES-CTR

使用计数器模式的 AES 算法,规范定于 NIST SP800-38A

AES 是一种分组加密算法,这意味着它将消息分成多个模块,然后逐块进行加密。在计数器模式下,每加密一个消息块,就会混入一个额外的数据块。这个额外的模块被称为“计数器模块”(counter block)。

给定的计数器模块绝不能与同一个密钥一起使用超过一次:

  • 给定一条 n 个模块长的消息,其中的每一个模块必须使用不同的计数器模块。
  • 如果使用同一个密钥加密多条消息,则必须对所有消息的所有模块使用不同的计数器模块。

通常,这是通过将初始计数器模块拆分为两个拼接起来的部分来实现:

  • 一个 nonce(即,仅能使用一次的数字)。对于消息中的每一个模块,模块的 nonce 部分保持不变。每次要加密一条新消息时,都会选择一个新的 nonce。nonce 不必是私密的,但不能将同一 nonce 与相同的密钥重复使用。
  • 一个计数器。每次加密一个模块时,这一部分的值会递增。

本质上:nonce 应该确保计数器模块不会在不同的消息间重复使用,而计数器应能确保计数器模块不会在单条消息中重复使用。

备注: 参见 NIST SP800-38A 标准的附录 B 以了解详情。

AES-CBC

使用密码块链接模式的 AES 算法,规范定于 NIST SP800-38A

AES-GCM

使用伽罗瓦/计数器模式的 AES 算法,规范定于 NIST SP800-38D

这种模式与上面的模式不同之处在于,GCM 是一种“认证”(authenticated)模式,意味着它包含了检测密文是否被攻击者篡改的功能。

示例

备注: 你可以在 GitHub 上尝试这个可用的示例

RSA-OAEP

以下代码获取文本框中的内容,并对其编码以进行加密,然后使用 RSA-OAEP 加密数据。在 GitHub 中查看完整的代码。

js
function getMessageEncoding() {
  const messageBox = document.querySelector(".rsa-oaep #message");
  let message = messageBox.value;
  let enc = new TextEncoder();
  return enc.encode(message);
}

function encryptMessage(publicKey) {
  let encoded = getMessageEncoding();
  return window.crypto.subtle.encrypt(
    {
      name: "RSA-OAEP",
    },
    publicKey,
    encoded,
  );
}

AES-CTR

以下代码同样获取文本框内容,进行编码后使用 AES 的计数器(CTR)模式加密,完整代码:以下代码获取文本框中的内容,并对其编码以进行加密,然后使用计数器(CTR)模式的 AES 加密数据。在 GitHub 中查看完整的代码。

js
function getMessageEncoding() {
  const messageBox = document.querySelector(".aes-ctr #message");
  let message = messageBox.value;
  let enc = new TextEncoder();
  return enc.encode(message);
}

function encryptMessage(key) {
  let encoded = getMessageEncoding();
  // 解密时也需要使用 counter
  counter = window.crypto.getRandomValues(new Uint8Array(16));
  return window.crypto.subtle.encrypt(
    {
      name: "AES-CTR",
      counter,
      length: 64,
    },
    key,
    encoded,
  );
}
js
let iv = window.crypto.getRandomValues(new Uint8Array(16));
let key = window.crypto.getRandomValues(new Uint8Array(16));
let data = new Uint8Array(12345);
// 加密函数使用 promise 包裹,因此我们必须使用 await,
// 并确保包含此代码的函数是一个异步函数
// 加密函数需要一个 cryptokey 对象
const key_encoded = await window.crypto.subtle.importKey(
  "raw",
  key.buffer,
  "AES-CTR",
  false,
  ["encrypt", "decrypt"],
);
const encrypted_content = await window.crypto.subtle.encrypt(
  {
    name: "AES-CTR",
    counter: iv,
    length: 128,
  },
  key_encoded,
  data,
);

// Uint8Array
console.log(encrypted_content);

AES-CBC

以下代码获取文本框中的内容,并对其编码以进行加密,然后使用密码块链接(CBC)模式的 AES 加密数据。在 GitHub 中查看完整的代码。

js
function getMessageEncoding() {
  const messageBox = document.querySelector(".aes-cbc #message");
  let message = messageBox.value;
  let enc = new TextEncoder();
  return enc.encode(message);
}

function encryptMessage(key) {
  let encoded = getMessageEncoding();
  // 解密时也需要使用 iv
  iv = window.crypto.getRandomValues(new Uint8Array(16));
  return window.crypto.subtle.encrypt(
    {
      name: "AES-CBC",
      iv: iv,
    },
    key,
    encoded,
  );
}

AES-GCM

以下代码获取文本框中的内容,并对其编码以进行加密,然后使用伽罗瓦/计数器(GCM)模式的 AES 加密数据。在 GitHub 中查看完整的代码。

js
function getMessageEncoding() {
  const messageBox = document.querySelector(".aes-gcm #message");
  const message = messageBox.value;
  const enc = new TextEncoder();
  return enc.encode(message);
}

function encryptMessage(key) {
  const encoded = getMessageEncoding();
  // 解密时也需要使用 iv
  const iv = window.crypto.getRandomValues(new Uint8Array(12));
  return window.crypto.subtle.encrypt(
    { name: "AES-GCM", iv: iv },
    key,
    encoded,
  );
}

规范

Specification
Web Cryptography API
# SubtleCrypto-method-encrypt

浏览器兼容性

Report problems with this compatibility data on GitHub
desktopmobileserver
Chrome
Edge
Firefox
Opera
Safari
Chrome Android
Firefox for Android
Opera Android
Safari on iOS
Samsung Internet
WebView Android
WebView on iOS
Deno
Node.js
encrypt

Legend

Tip: you can click/tap on a cell for more information.

Full support
Full support
Partial support
Partial support
Has more compatibility info.

参见