Examples#
Generating keys#
The <SubtleCrypto> class can be used to generate symmetric (secret) keys
or asymmetric key pairs (public key and private key).
AES keys#
const { subtle } = globalThis.crypto;
async function generateAesKey(length = 256) {
const key = await subtle.generateKey({
name: 'AES-CBC',
length,
}, true, ['encrypt', 'decrypt']);
return key;
}
ECDSA key pairs#
const { subtle } = globalThis.crypto;
async function generateEcKey(namedCurve = 'P-521') {
const {
publicKey,
privateKey,
} = await subtle.generateKey({
name: 'ECDSA',
namedCurve,
}, true, ['sign', 'verify']);
return { publicKey, privateKey };
}
Ed25519/X25519 key pairs#
const { subtle } = globalThis.crypto;
async function generateEd25519Key() {
return subtle.generateKey({
name: 'Ed25519',
}, true, ['sign', 'verify']);
}
async function generateX25519Key() {
return subtle.generateKey({
name: 'X25519',
}, true, ['deriveKey']);
}
HMAC keys#
const { subtle } = globalThis.crypto;
async function generateHmacKey(hash = 'SHA-256') {
const key = await subtle.generateKey({
name: 'HMAC',
hash,
}, true, ['sign', 'verify']);
return key;
}
RSA key pairs#
const { subtle } = globalThis.crypto;
const publicExponent = new Uint8Array([1, 0, 1]);
async function generateRsaKey(modulusLength = 2048, hash = 'SHA-256') {
const {
publicKey,
privateKey,
} = await subtle.generateKey({
name: 'RSASSA-PKCS1-v1_5',
modulusLength,
publicExponent,
hash,
}, true, ['sign', 'verify']);
return { publicKey, privateKey };
}
Encryption and decryption#
const crypto = globalThis.crypto;
async function aesEncrypt(plaintext) {
const ec = new TextEncoder();
const key = await generateAesKey();
const iv = crypto.getRandomValues(new Uint8Array(16));
const ciphertext = await crypto.subtle.encrypt({
name: 'AES-CBC',
iv,
}, key, ec.encode(plaintext));
return {
key,
iv,
ciphertext,
};
}
async function aesDecrypt(ciphertext, key, iv) {
const dec = new TextDecoder();
const plaintext = await crypto.subtle.decrypt({
name: 'AES-CBC',
iv,
}, key, ciphertext);
return dec.decode(plaintext);
}
Exporting and importing keys#
const { subtle } = globalThis.crypto;
async function generateAndExportHmacKey(format = 'jwk', hash = 'SHA-512') {
const key = await subtle.generateKey({
name: 'HMAC',
hash,
}, true, ['sign', 'verify']);
return subtle.exportKey(format, key);
}
async function importHmacKey(keyData, format = 'jwk', hash = 'SHA-512') {
const key = await subtle.importKey(format, keyData, {
name: 'HMAC',
hash,
}, true, ['sign', 'verify']);
return key;
}
Wrapping and unwrapping keys#
const { subtle } = globalThis.crypto;
async function generateAndWrapHmacKey(format = 'jwk', hash = 'SHA-512') {
const [
key,
wrappingKey,
] = await Promise.all([
subtle.generateKey({
name: 'HMAC', hash,
}, true, ['sign', 'verify']),
subtle.generateKey({
name: 'AES-KW',
length: 256,
}, true, ['wrapKey', 'unwrapKey']),
]);
const wrappedKey = await subtle.wrapKey(format, key, wrappingKey, 'AES-KW');
return { wrappedKey, wrappingKey };
}
async function unwrapHmacKey(
wrappedKey,
wrappingKey,
format = 'jwk',
hash = 'SHA-512') {
const key = await subtle.unwrapKey(
format,
wrappedKey,
wrappingKey,
'AES-KW',
{ name: 'HMAC', hash },
true,
['sign', 'verify']);
return key;
}
Sign and verify#
const { subtle } = globalThis.crypto;
async function sign(key, data) {
const ec = new TextEncoder();
const signature =
await subtle.sign('RSASSA-PKCS1-v1_5', key, ec.encode(data));
return signature;
}
async function verify(key, signature, data) {
const ec = new TextEncoder();
const verified =
await subtle.verify(
'RSASSA-PKCS1-v1_5',
key,
signature,
ec.encode(data));
return verified;
}
Deriving bits and keys#
const { subtle } = globalThis.crypto;
async function pbkdf2(pass, salt, iterations = 1000, length = 256) {
const ec = new TextEncoder();
const key = await subtle.importKey(
'raw',
ec.encode(pass),
'PBKDF2',
false,
['deriveBits']);
const bits = await subtle.deriveBits({
name: 'PBKDF2',
hash: 'SHA-512',
salt: ec.encode(salt),
iterations,
}, key, length);
return bits;
}
async function pbkdf2Key(pass, salt, iterations = 1000, length = 256) {
const ec = new TextEncoder();
const keyMaterial = await subtle.importKey(
'raw',
ec.encode(pass),
'PBKDF2',
false,
['deriveKey']);
const key = await subtle.deriveKey({
name: 'PBKDF2',
hash: 'SHA-512',
salt: ec.encode(salt),
iterations,
}, keyMaterial, {
name: 'AES-GCM',
length,
}, true, ['encrypt', 'decrypt']);
return key;
}
Digest#
const { subtle } = globalThis.crypto;
async function digest(data, algorithm = 'SHA-512') {
const ec = new TextEncoder();
const digest = await subtle.digest(algorithm, ec.encode(data));
return digest;
}
Class: SubtleCrypto#
Added in: v15.0.0
subtle.decrypt(algorithm, key, data)#
Added in: v15.0.0
Using the method and parameters specified in algorithm and the keying
material provided by key, subtle.decrypt() attempts to decipher the
provided data. If successful, the returned promise will be resolved with
an <ArrayBuffer> containing the plaintext result.
The algorithms currently supported include:
'RSA-OAEP'
'AES-CTR'
'AES-CBC'
'AES-GCM'
subtle.deriveBits(algorithm, baseKey[, length])#
Using the method and parameters specified in algorithm and the keying
material provided by baseKey, subtle.deriveBits() attempts to generate
length bits.
When length is not provided or null the maximum number of bits for a given
algorithm is generated. This is allowed for the 'ECDH', 'X25519', and 'X448'
algorithms, for other algorithms length is required to be a number.
If successful, the returned promise will be resolved with an <ArrayBuffer>
containing the generated data.
The algorithms currently supported include:
'ECDH'
'X25519'
'X448' 1
'HKDF'
'PBKDF2'
subtle.deriveKey(algorithm, baseKey, derivedKeyAlgorithm, extractable, keyUsages)
Using the method and parameters specified in algorithm, and the keying
material provided by baseKey, subtle.deriveKey() attempts to generate
a new <CryptoKey> based on the method and parameters in derivedKeyAlgorithm.
Calling subtle.deriveKey() is equivalent to calling subtle.deriveBits() to
generate raw keying material, then passing the result into the
subtle.importKey() method using the deriveKeyAlgorithm, extractable, and
keyUsages parameters as input.
The algorithms currently supported include:
'ECDH'
'X25519'
'X448' 1
'HKDF'
'PBKDF2'
subtle.digest(algorithm, data)#
Added in: v15.0.0
Using the method identified by algorithm, subtle.digest() attempts to
generate a digest of data. If successful, the returned promise is resolved
with an <ArrayBuffer> containing the computed digest.
If algorithm is provided as a <string>, it must be one of:
'SHA-1'
'SHA-256'
'SHA-384'
'SHA-512'
If algorithm is provided as an <Object>, it must have a name property
whose value is one of the above.
subtle.encrypt(algorithm, key, data)#
Added in: v15.0.0
Using the method and parameters specified by algorithm and the keying
material provided by key, subtle.encrypt() attempts to encipher data.
If successful, the returned promise is resolved with an <ArrayBuffer>
containing the encrypted result.
The algorithms currently supported include:
'RSA-OAEP'
'AES-CTR'
'AES-CBC'
'AES-GCM'
subtle.exportKey(format, key)#
Exports the given key into the specified format, if supported.
If the <CryptoKey> is not extractable, the returned promise will reject.
When format is either 'pkcs8' or 'spki' and the export is successful,
the returned promise will be resolved with an <ArrayBuffer> containing the
exported key data.
When format is 'jwk' and the export is successful, the returned promise
will be resolved with a JavaScript object conforming to the JSON Web Key
specification.
| Supported Key Algorithm | 'spki' | 'pkcs8' | 'jwk' | 'raw' |
|---|
'AES-CBC' | | | ✔ | ✔ |
'AES-CTR' | | | ✔ | ✔ |
'AES-GCM' | | | ✔ | ✔ |
'AES-KW' | | | ✔ | ✔ |
'ECDH' | ✔ | ✔ | ✔ | ✔ |
'ECDSA' | ✔ | ✔ | ✔ | ✔ |
'Ed25519' | ✔ | ✔ | ✔ | ✔ |
'Ed448' 1 | ✔ | ✔ | ✔ | ✔ |
'HMAC' | | | ✔ | ✔ |
'RSA-OAEP' | ✔ | ✔ | ✔ | |
'RSA-PSS' | ✔ | ✔ | ✔ | |
'RSASSA-PKCS1-v1_5' | ✔ | ✔ | ✔ | |
subtle.generateKey(algorithm, extractable, keyUsages)
Added in: v15.0.0
Using the parameters provided in algorithm, this method
attempts to generate new keying material. Depending on the algorithm used
either a single <CryptoKey> or a <CryptoKeyPair> is generated.
The <CryptoKeyPair> (public and private key) generating algorithms supported
include:
'RSASSA-PKCS1-v1_5'
'RSA-PSS'
'RSA-OAEP'
'ECDSA'
'Ed25519'
'Ed448' 1
'ECDH'
'X25519'
'X448' 1
The <CryptoKey> (secret key) generating algorithms supported include:
'HMAC'
'AES-CTR'
'AES-CBC'
'AES-GCM'
'AES-KW'
subtle.importKey(format, keyData, algorithm, extractable, keyUsages)
This method attempts to interpret the provided keyData
as the given format to create a <CryptoKey> instance using the provided
algorithm, extractable, and keyUsages arguments. If the import is
successful, the returned promise will be resolved with a <CryptoKey>
representation of the key material.
If importing a 'PBKDF2' key, extractable must be false.
The algorithms currently supported include:
| Supported Key Algorithm | 'spki' | 'pkcs8' | 'jwk' | 'raw' |
|---|
'AES-CBC' | | | ✔ | ✔ |
'AES-CTR' | | | ✔ | ✔ |
'AES-GCM' | | | ✔ | ✔ |
'AES-KW' | | | ✔ | ✔ |
'ECDH' | ✔ | ✔ | ✔ | ✔ |
'X25519' | ✔ | ✔ | ✔ | ✔ |
'X448' 1 | ✔ | ✔ | ✔ | ✔ |
'ECDSA' | ✔ | ✔ | ✔ | ✔ |
'Ed25519' | ✔ | ✔ | ✔ | ✔ |
'Ed448' 1 | ✔ | ✔ | ✔ | ✔ |
'HDKF' | | | | ✔ |
'HMAC' | | | ✔ | ✔ |
'PBKDF2' | | | | ✔ |
'RSA-OAEP' | ✔ | ✔ | ✔ | |
'RSA-PSS' | ✔ | ✔ | ✔ | |
'RSASSA-PKCS1-v1_5' | ✔ | ✔ | ✔ | |
subtle.sign(algorithm, key, data)#
Using the method and parameters given by algorithm and the keying material
provided by key, subtle.sign() attempts to generate a cryptographic
signature of data. If successful, the returned promise is resolved with
an <ArrayBuffer> containing the generated signature.
The algorithms currently supported include:
'RSASSA-PKCS1-v1_5'
'RSA-PSS'
'ECDSA'
'Ed25519'
'Ed448' 1
'HMAC'
subtle.unwrapKey(format, wrappedKey, unwrappingKey, unwrapAlgo, unwrappedKeyAlgo, extractable, keyUsages)
Added in: v15.0.0
In cryptography, "wrapping a key" refers to exporting and then encrypting the
keying material. The subtle.unwrapKey() method attempts to decrypt a wrapped
key and create a <CryptoKey> instance. It is equivalent to calling
subtle.decrypt() first on the encrypted key data (using the wrappedKey,
unwrapAlgo, and unwrappingKey arguments as input) then passing the results
in to the subtle.importKey() method using the unwrappedKeyAlgo,
extractable, and keyUsages arguments as inputs. If successful, the returned
promise is resolved with a <CryptoKey> object.
The wrapping algorithms currently supported include:
'RSA-OAEP'
'AES-CTR'
'AES-CBC'
'AES-GCM'
'AES-KW'
The unwrapped key algorithms supported include:
'RSASSA-PKCS1-v1_5'
'RSA-PSS'
'RSA-OAEP'
'ECDSA'
'Ed25519'
'Ed448' 1
'ECDH'
'X25519'
'X448' 1
'HMAC'
'AES-CTR'
'AES-CBC'
'AES-GCM'
'AES-KW'
subtle.verify(algorithm, key, signature, data)#
Using the method and parameters given in algorithm and the keying material
provided by key, subtle.verify() attempts to verify that signature is
a valid cryptographic signature of data. The returned promise is resolved
with either true or false.
The algorithms currently supported include:
'RSASSA-PKCS1-v1_5'
'RSA-PSS'
'ECDSA'
'Ed25519'
'Ed448' 1
'HMAC'
subtle.wrapKey(format, key, wrappingKey, wrapAlgo)#
Added in: v15.0.0
In cryptography, "wrapping a key" refers to exporting and then encrypting the
keying material. The subtle.wrapKey() method exports the keying material into
the format identified by format, then encrypts it using the method and
parameters specified by wrapAlgo and the keying material provided by
wrappingKey. It is the equivalent to calling subtle.exportKey() using
format and key as the arguments, then passing the result to the
subtle.encrypt() method using wrappingKey and wrapAlgo as inputs. If
successful, the returned promise will be resolved with an <ArrayBuffer>
containing the encrypted key data.
The wrapping algorithms currently supported include:
'RSA-OAEP'
'AES-CTR'
'AES-CBC'
'AES-GCM'
'AES-KW'