The deriveBits()
method of the SubtleCrypto
interface can be used to derive an array of bits from a base key.
It takes as its arguments the base key, the derivation algorithm to use, and the length of the bit string to derive. It returns a Promise
which will be fulfilled with an ArrayBuffer
containing the derived bits.
This method is very similar to SubtleCrypto.deriveKey()
, except that deriveKey()
returns a CryptoKey
object rather than an ArrayBuffer
. Essentially deriveKey()
is composed of deriveBits()
followed by importKey()
.
This function supports the same derivation algorithms as deriveKey()
: ECDH, HKDF, and PBKDF2. See Supported algorithms for some more detail on these algorithms.
deriveBits(algorithm, baseKey, length)
A Promise
that fulfills with an ArrayBuffer
containing the derived bits.
The promise is rejected when one of the following exceptions are encountered:
-
OperationError
DOMException
-
Raised if the length parameter of the deriveBits()
call is null, and also in some cases if the length parameter is not a multiple of 8.
-
InvalidAccessError
DOMException
-
Raised when the base key is not a key for the requested derivation algorithm or if the CryptoKey.usages
value of that key doesn't contain deriveBits
.
-
NotSupported
DOMException
-
Raised when trying to use an algorithm that is either unknown or isn't suitable for derivation, or if the algorithm requested for the derived key doesn't define a key length.
In this example Alice and Bob each generate an ECDH key pair.
We then use Alice's private key and Bob's public key to derive a shared secret. See the complete code on GitHub.
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} bytes total]`;
}
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", () => {
deriveSharedSecret(alicesKeyPair.privateKey, bobsKeyPair.publicKey);
});
});
In this example we ask the user for a password, then use it to derive some bits using PBKDF2. See the complete code on GitHub.
let salt;
function getKeyMaterial() {
const password = window.prompt("Enter your password");
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: 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} bytes total]`;
}
const deriveBitsButton = document.querySelector(".pbkdf2 .derive-bits-button");
deriveBitsButton.addEventListener("click", () => {
getDerivedBits();
});