SubtleCrypto.deriveBits()

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

SubtleCrypto 接口的 deriveBits() 方法用于从一个基本密钥派生比特序列(数组)。

它以基本密钥、使用的派生算法和需要派生的比特长度为参数。返回一个 Promise,会兑现一个包含派生比特序列的 ArrayBuffer

此方法与 SubtleCrypto.deriveKey() 非常类似,区别在于 deriveKey() 返回的是 CryptoKey 对象,而不是 ArrayBuffer。本质上,deriveKey() 是由 deriveBits()importKey() 这两个方法组合而成的。

该函数支持的派生算法与 deriveKey() 相同:ECDH、HKDF 和 PBKDF2。参见支持的算法以了解这些算法的详细信息。

语法

js
deriveBits(algorithm, baseKey, length)

参数

algorithm

一个对象,用于定义使用的派生算法

baseKey

一个 CryptoKey,表示派生算法的输入。如果算法(algorithm)是 ECDH,则该对象为 ECDH 的私钥。否则,它为派生函数的初始密钥材料(key material):例如,对于 PBKDF2,它可能是一个密码(使用 SubtleCrypto.importKey() 导入为一个 CryptoKey 对象)。

length

一个数字,表示要派生的比特位数。为了兼容所有浏览器,此数字应为 8 的倍数。

返回值

一个 Promise,会兑现一个包含派生的比特序列的 ArrayBuffer

异常

当发生一下几种异常时,promise 会被拒绝:

OperationError DOMException

deriveBits()length 参数为 null,或在某些情况下如果 length 参数不是 8 的倍数,则会抛出此异常。

InvalidAccessError DOMException

若基本密钥不是要求的派生算法的密钥,或 CryptoKey.usages 的值不包含 deriveBits,则会抛出此异常。

NotSupported DOMException

若尝试使用未知或不适用于派生的算法,则会抛出此异常。

支持的算法

示例

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

ECDH

在此示例中,Alice 和 Bob 分别生成了一个 ECDH 密钥对。

然后,我们使用 Alice 的私钥和 Bob 的公钥来派生一个共享密钥(shared secret)。在 GitHub 上查看完整代码

js
async function deriveSharedSecret(privateKey, publicKey) {
  const sharedSecret = await window.crypto.subtle.deriveBits(
    {
      name: "ECDH",
      namedCurve: "P-384",
      public: publicKey,
    },
    privateKey,
    128,
  );

  const buffer = new Uint8Array(sharedSecret, 0, 5);
  const sharedSecretValue = document.querySelector(".ecdh .derived-bits-value");
  sharedSecretValue.classList.add("fade-in");
  sharedSecretValue.addEventListener("animationend", () => {
    sharedSecretValue.classList.remove("fade-in");
  });
  sharedSecretValue.textContent = `${buffer}…[共 ${sharedSecret.byteLength} 字节]`;
}

// 生成两个 ECDH 密钥对:一个是 Alice 的,一个是 Bob 的
// 在正常的使用情况下,他们会单独生成密钥对,并安全地交换公钥。
const generateAlicesKeyPair = window.crypto.subtle.generateKey(
  {
    name: "ECDH",
    namedCurve: "P-384",
  },
  false,
  ["deriveBits"],
);

const generateBobsKeyPair = window.crypto.subtle.generateKey(
  {
    name: "ECDH",
    namedCurve: "P-384",
  },
  false,
  ["deriveBits"],
);

Promise.all([generateAlicesKeyPair, generateBobsKeyPair]).then((values) => {
  const alicesKeyPair = values[0];
  const bobsKeyPair = values[1];

  const deriveBitsButton = document.querySelector(".ecdh .derive-bits-button");
  deriveBitsButton.addEventListener("click", () => {
    // 然后 Alice 使用她的私钥和 Bob 的公钥生成一个密钥(secret)。
    // Bob 可以使用他的私钥和 Alice 的公钥来生成相同的密钥。
    deriveSharedSecret(alicesKeyPair.privateKey, bobsKeyPair.publicKey);
  });
});

PBKDF2

在此示例中,我们要求用户提供密码,然后使用 PBKDF2 派生比特序列。在 GitHub 上查看完整代码

js
let salt;

/*
获取用于作为 deriveBits 方法的输入的密钥材料。
密钥材料是用户提供的密码。
*/
function getKeyMaterial() {
  const password = window.prompt("请输入你的密码");
  const enc = new TextEncoder();
  return window.crypto.subtle.importKey(
    "raw",
    enc.encode(password),
    { name: "PBKDF2" },
    false,
    ["deriveBits", "deriveKey"],
  );
}

/*
通过用户提供的密码派生比特序列。
*/
async function getDerivedBits() {
  const keyMaterial = await getKeyMaterial();
  salt = window.crypto.getRandomValues(new Uint8Array(16));
  const derivedBits = await window.crypto.subtle.deriveBits(
    {
      name: "PBKDF2",
      salt,
      iterations: 100000,
      hash: "SHA-256",
    },
    keyMaterial,
    256,
  );

  const buffer = new Uint8Array(derivedBits, 0, 5);
  const derivedBitsValue = document.querySelector(
    ".pbkdf2 .derived-bits-value",
  );
  derivedBitsValue.classList.add("fade-in");
  derivedBitsValue.addEventListener("animationend", () => {
    derivedBitsValue.classList.remove("fade-in");
  });
  derivedBitsValue.textContent = `${buffer}…[共 ${derivedBits.byteLength} 字节]`;
}

const deriveBitsButton = document.querySelector(".pbkdf2 .derive-bits-button");
deriveBitsButton.addEventListener("click", () => {
  getDerivedBits();
});

规范

Specification
Web Cryptography API
# SubtleCrypto-method-deriveBits

浏览器兼容性

BCD tables only load in the browser

参见