A WebCrypto polyfill for Node.js that provides comprehensive cryptographic operations using standard Web Crypto API
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Key derivation functions for generating cryptographic keys from passwords, shared secrets, or other key material. Supports PBKDF2, HKDF, and HMAC operations.
Derives cryptographic keys from passwords using iterative hashing for brute-force resistance.
/**
* PBKDF2 key derivation parameters
*/
interface Pbkdf2Params extends Algorithm {
name: "PBKDF2";
salt: BufferSource; // Random salt (minimum 64 bits recommended)
iterations: number; // Iteration count (minimum 10,000 recommended)
hash: "SHA-1" | "SHA-256" | "SHA-384" | "SHA-512"; // Hash algorithm
}Usage Example:
// Import password as key material
const password = new TextEncoder().encode("user-password");
const passwordKey = await crypto.subtle.importKey(
"raw",
password,
{ name: "PBKDF2" },
false,
["deriveKey", "deriveBits"]
);
// Generate random salt
const salt = crypto.getRandomValues(new Uint8Array(16));
// Derive AES key from password
const derivedKey = await crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt: salt,
iterations: 100000,
hash: "SHA-256"
},
passwordKey,
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"]
);
// Alternative: derive raw bits
const derivedBits = await crypto.subtle.deriveBits(
{
name: "PBKDF2",
salt: salt,
iterations: 100000,
hash: "SHA-256"
},
passwordKey,
256 // 256 bits output
);Extracts and expands key material using HMAC for key agreement and key stretching.
/**
* HKDF key derivation parameters
*/
interface HkdfParams extends Algorithm {
name: "HKDF";
hash: "SHA-1" | "SHA-256" | "SHA-384" | "SHA-512"; // Hash algorithm
salt: BufferSource; // Salt value (can be empty)
info: BufferSource; // Application-specific context information
}Usage Example:
// Import shared secret as key material
const sharedSecret = crypto.getRandomValues(new Uint8Array(32));
const baseKey = await crypto.subtle.importKey(
"raw",
sharedSecret,
{ name: "HKDF" },
false,
["deriveKey", "deriveBits"]
);
// Derive multiple keys from shared secret
const salt = new TextEncoder().encode("unique-salt");
const info = new TextEncoder().encode("application-context");
// Derive encryption key
const encryptionKey = await crypto.subtle.deriveKey(
{
name: "HKDF",
hash: "SHA-256",
salt: salt,
info: new TextEncoder().encode("encryption-key")
},
baseKey,
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"]
);
// Derive MAC key
const macKey = await crypto.subtle.deriveKey(
{
name: "HKDF",
hash: "SHA-256",
salt: salt,
info: new TextEncoder().encode("mac-key")
},
baseKey,
{ name: "HMAC", hash: "SHA-256" },
false,
["sign", "verify"]
);Provides message authentication and integrity verification using cryptographic hash functions.
/**
* HMAC key generation parameters
*/
interface HmacKeyGenParams extends Algorithm {
name: "HMAC";
hash: "SHA-1" | "SHA-256" | "SHA-384" | "SHA-512";
length?: number; // Key length in bits (optional)
}
/**
* HMAC operation parameters
*/
interface HmacParams extends Algorithm {
name: "HMAC";
}Usage Example:
// Generate HMAC key
const hmacKey = await crypto.subtle.generateKey(
{ name: "HMAC", hash: "SHA-256", length: 256 },
true,
["sign", "verify"]
);
// Create HMAC signature
const data = new TextEncoder().encode("Message to authenticate");
const signature = await crypto.subtle.sign(
{ name: "HMAC" },
hmacKey,
data
);
// Verify HMAC signature
const isValid = await crypto.subtle.verify(
{ name: "HMAC" },
hmacKey,
signature,
data
);
// Import HMAC key from raw bytes
const keyMaterial = crypto.getRandomValues(new Uint8Array(32));
const importedKey = await crypto.subtle.importKey(
"raw",
keyMaterial,
{ name: "HMAC", hash: "SHA-256" },
false,
["sign", "verify"]
);/**
* PBKDF2 key for deriving other keys from passwords
*/
class PbkdfCryptoKey extends SymmetricKey {
public algorithm: PbkdfKeyAlgorithm;
public type: "secret";
public usages: ("deriveKey" | "deriveBits")[];
public extractable: boolean;
}
interface PbkdfKeyAlgorithm extends KeyAlgorithm {
name: "PBKDF2";
}/**
* HKDF key for expanding key material
*/
class HkdfCryptoKey extends SymmetricKey {
public algorithm: HkdfKeyAlgorithm;
public type: "secret";
public usages: ("deriveKey" | "deriveBits")[];
public extractable: boolean;
}
interface HkdfKeyAlgorithm extends KeyAlgorithm {
name: "HKDF";
}/**
* HMAC key for message authentication
*/
class HmacCryptoKey extends SymmetricKey {
public algorithm: HmacKeyAlgorithm;
public type: "secret";
public usages: ("sign" | "verify")[];
public extractable: boolean;
}
interface HmacKeyAlgorithm extends KeyAlgorithm {
name: "HMAC";
hash: KeyAlgorithm;
length: number;
}async function stretchPassword(
password: string,
salt: Uint8Array,
iterations: number = 100000
) {
const passwordKey = await crypto.subtle.importKey(
"raw",
new TextEncoder().encode(password),
{ name: "PBKDF2" },
false,
["deriveBits"]
);
return await crypto.subtle.deriveBits(
{
name: "PBKDF2",
salt: salt,
iterations: iterations,
hash: "SHA-256"
},
passwordKey,
256
);
}async function expandKey(
masterKey: ArrayBuffer,
salt: string,
info: string,
keyLength: number = 256
) {
const baseKey = await crypto.subtle.importKey(
"raw",
masterKey,
{ name: "HKDF" },
false,
["deriveBits"]
);
return await crypto.subtle.deriveBits(
{
name: "HKDF",
hash: "SHA-256",
salt: new TextEncoder().encode(salt),
info: new TextEncoder().encode(info)
},
baseKey,
keyLength
);
}async function createHmacChain(
key: CryptoKey,
messages: string[]
): Promise<ArrayBuffer[]> {
const signatures: ArrayBuffer[] = [];
for (const message of messages) {
const data = new TextEncoder().encode(message);
const signature = await crypto.subtle.sign(
{ name: "HMAC" },
key,
data
);
signatures.push(signature);
}
return signatures;
}async function safeDeriveKey(
algorithm: any,
baseKey: CryptoKey,
derivedKeyType: any,
extractable: boolean,
keyUsages: KeyUsage[]
) {
try {
return await crypto.subtle.deriveKey(
algorithm,
baseKey,
derivedKeyType,
extractable,
keyUsages
);
} catch (error) {
if (error.name === "InvalidAccessError") {
throw new Error("Base key doesn't support key derivation");
}
if (error.name === "NotSupportedError") {
throw new Error("Key derivation algorithm not supported");
}
if (error.name === "OperationError") {
throw new Error("Key derivation failed - check parameters");
}
throw error;
}
}Install with Tessl CLI
npx tessl i tessl/npm-peculiar--webcrypto