Pure TypeScript/JavaScript streaming implementation of the complete Secure Hash Standard (SHA) family with HMAC support
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Hash-based Message Authentication Code (HMAC) functionality for creating and verifying message authenticity and integrity. jsSHA provides built-in HMAC support for all applicable SHA variants with flexible key input formats.
The preferred method for HMAC operations is to specify the HMAC key during object instantiation.
/**
* HMAC options for TEXT input format with encoding support
*/
interface FixedLengthOptionsEncodingType {
hmacKey?: GenericInputType;
encoding?: EncodingType;
} | {
numRounds?: number;
encoding?: EncodingType;
}
/**
* HMAC options for non-TEXT input formats
*/
interface FixedLengthOptionsNoEncodingType {
hmacKey?: GenericInputType;
} | {
numRounds?: number;
}
/**
* Generic input specification for HMAC keys
*/
interface GenericInputType {
value: string;
format: "TEXT";
encoding?: EncodingType;
} | {
value: string;
format: "B64" | "HEX" | "BYTES";
} | {
value: ArrayBuffer;
format: "ARRAYBUFFER";
} | {
value: Uint8Array;
format: "UINT8ARRAY";
}
type EncodingType = "UTF8" | "UTF16BE" | "UTF16LE";Usage Examples:
import jsSHA from "jssha";
// HMAC with text key
const hmacText = new jsSHA("SHA-256", "TEXT", {
hmacKey: { value: "secret-key", format: "TEXT" },
encoding: "UTF8"
});
hmacText.update("Message to authenticate");
const hmac1 = hmacText.getHash("HEX");
// HMAC with hex key
const hmacHex = new jsSHA("SHA-512", "TEXT", {
hmacKey: { value: "deadbeef", format: "HEX" }
});
hmacHex.update("Another message");
const hmac2 = hmacHex.getHash("B64");
// HMAC with Base64 key
const hmacB64 = new jsSHA("SHA-1", "HEX", {
hmacKey: { value: "c2VjcmV0LWtleQ==", format: "B64" }
});
hmacB64.update("48656c6c6f"); // "Hello" in hex
const hmac3 = hmacB64.getHash("HEX");
// HMAC with ArrayBuffer key
const keyBuffer = new TextEncoder().encode("binary-key").buffer;
const hmacBuffer = new jsSHA("SHA-384", "ARRAYBUFFER", {
hmacKey: { value: keyBuffer, format: "ARRAYBUFFER" }
});
const messageBuffer = new TextEncoder().encode("Message").buffer;
hmacBuffer.update(messageBuffer);
const hmac4 = hmacBuffer.getHash("UINT8ARRAY");
// HMAC with Uint8Array key
const keyArray = new TextEncoder().encode("array-key");
const hmacArray = new jsSHA("SHA3-256", "UINT8ARRAY", {
hmacKey: { value: keyArray, format: "UINT8ARRAY" }
});
const messageArray = new TextEncoder().encode("Message");
hmacArray.update(messageArray);
const hmac5 = hmacArray.getHash("ARRAYBUFFER");The setHMACKey method is deprecated in favor of specifying the HMAC key in constructor options, but remains available for backward compatibility.
/**
* Sets the HMAC key for TEXT format keys (DEPRECATED)
* @param key - The HMAC key as a string
* @param inputFormat - Must be "TEXT"
* @param options - Optional encoding configuration
*/
setHMACKey(key: string, inputFormat: "TEXT", options?: { encoding?: EncodingType }): void;
/**
* Sets the HMAC key for string-based formats (DEPRECATED)
* @param key - The HMAC key as a string
* @param inputFormat - Key format: B64, HEX, or BYTES
*/
setHMACKey(key: string, inputFormat: "B64" | "HEX" | "BYTES"): void;
/**
* Sets the HMAC key for ArrayBuffer format (DEPRECATED)
* @param key - The HMAC key as ArrayBuffer
* @param inputFormat - Must be "ARRAYBUFFER"
*/
setHMACKey(key: ArrayBuffer, inputFormat: "ARRAYBUFFER"): void;
/**
* Sets the HMAC key for Uint8Array format (DEPRECATED)
* @param key - The HMAC key as Uint8Array
* @param inputFormat - Must be "UINT8ARRAY"
*/
setHMACKey(key: Uint8Array, inputFormat: "UINT8ARRAY"): void;Usage Example (Deprecated Pattern):
import jsSHA from "jssha";
// Deprecated approach - avoid in new code
const shaObj = new jsSHA("SHA-256", "TEXT");
shaObj.setHMACKey("secret-key", "TEXT", { encoding: "UTF8" });
shaObj.update("Message to authenticate");
const hmac = shaObj.getHash("HEX"); // Use getHash, not getHMACThe getHMAC method is deprecated in favor of using getHash after setting up HMAC in the constructor.
/**
* Returns the HMAC in hexadecimal format (DEPRECATED)
* @param format - Must be "HEX"
* @param options - Optional formatting options
* @returns HMAC as hexadecimal string
*/
getHMAC(format: "HEX", options?: { outputUpper?: boolean }): string;
/**
* Returns the HMAC in Base64 format (DEPRECATED)
* @param format - Must be "B64"
* @param options - Optional formatting options
* @returns HMAC as Base64 string
*/
getHMAC(format: "B64", options?: { b64Pad?: string }): string;
/**
* Returns the HMAC as a byte string (DEPRECATED)
* @param format - Must be "BYTES"
* @returns HMAC as byte string
*/
getHMAC(format: "BYTES"): string;
/**
* Returns the HMAC as a Uint8Array (DEPRECATED)
* @param format - Must be "UINT8ARRAY"
* @returns HMAC as Uint8Array
*/
getHMAC(format: "UINT8ARRAY"): Uint8Array;
/**
* Returns the HMAC as an ArrayBuffer (DEPRECATED)
* @param format - Must be "ARRAYBUFFER"
* @returns HMAC as ArrayBuffer
*/
getHMAC(format: "ARRAYBUFFER"): ArrayBuffer;HMAC is supported for the following SHA variants:
Note: HMAC is not applicable to variable-length variants (SHAKE, cSHAKE) or KMAC variants (which have their own keyed authentication mechanism).
When using TEXT format keys, the encoding parameter determines how the string is converted to bytes:
// UTF-8 encoding (default and recommended)
const hmac1 = new jsSHA("SHA-256", "TEXT", {
hmacKey: { value: "secret-key", format: "TEXT", encoding: "UTF8" }
});
// UTF-16 Big Endian encoding
const hmac2 = new jsSHA("SHA-256", "TEXT", {
hmacKey: { value: "secret-key", format: "TEXT", encoding: "UTF16BE" }
});
// UTF-16 Little Endian encoding
const hmac3 = new jsSHA("SHA-256", "TEXT", {
hmacKey: { value: "secret-key", format: "TEXT", encoding: "UTF16LE" }
});For keys that are already in binary format or need specific byte representations:
// Hexadecimal key (useful for keys generated as hex strings)
const hmacHex = new jsSHA("SHA-256", "TEXT", {
hmacKey: { value: "deadbeefcafebabe", format: "HEX" }
});
// Base64 key (useful for keys stored in Base64 format)
const hmacB64 = new jsSHA("SHA-256", "TEXT", {
hmacKey: { value: "c2VjcmV0LWtleQ==", format: "B64" }
});
// Raw bytes key (for precise byte control)
const hmacBytes = new jsSHA("SHA-256", "TEXT", {
hmacKey: { value: "\x00\x01\x02\x03", format: "BYTES" }
});For keys provided as JavaScript binary objects:
// ArrayBuffer key
const keyBuffer = new Uint8Array([0x00, 0x01, 0x02, 0x03]).buffer;
const hmacBuffer = new jsSHA("SHA-256", "TEXT", {
hmacKey: { value: keyBuffer, format: "ARRAYBUFFER" }
});
// Uint8Array key
const keyArray = new Uint8Array([0x00, 0x01, 0x02, 0x03]);
const hmacArray = new jsSHA("SHA-256", "TEXT", {
hmacKey: { value: keyArray, format: "UINT8ARRAY" }
});import jsSHA from "jssha";
function signRequest(method: string, url: string, body: string, secretKey: string): string {
const message = `${method}\n${url}\n${body}`;
const hmac = new jsSHA("SHA-256", "TEXT", {
hmacKey: { value: secretKey, format: "TEXT" }
});
hmac.update(message);
return hmac.getHash("B64");
}
const signature = signRequest("POST", "/api/users", '{"name":"John"}', "my-secret-key");
// Use signature in Authorization headerimport jsSHA from "jssha";
function verifyMessage(message: string, expectedHmac: string, secretKey: string): boolean {
const hmac = new jsSHA("SHA-256", "TEXT", {
hmacKey: { value: secretKey, format: "TEXT" }
});
hmac.update(message);
const computedHmac = hmac.getHash("HEX");
// Constant-time comparison to prevent timing attacks
return computedHmac === expectedHmac;
}
const isValid = verifyMessage("Hello, World!", "expected-hmac-hex", "shared-secret");import jsSHA from "jssha";
function createToken(header: string, payload: string, secret: string): string {
const message = `${header}.${payload}`;
const hmac = new jsSHA("SHA-256", "TEXT", {
hmacKey: { value: secret, format: "TEXT" }
});
hmac.update(message);
const signature = hmac.getHash("B64");
return `${message}.${signature}`;
}
const token = createToken("eyJhbGciOiJIUzI1NiJ9", "eyJ1c2VyIjoiam9obiJ9", "jwt-secret");HMAC operations can fail if:
numRounds parameter is used with HMAC (not supported)// This will work correctly
const validHmac = new jsSHA("SHA-256", "TEXT", {
hmacKey: { value: "secret", format: "TEXT" }
});
// This will NOT work - numRounds cannot be used with HMAC
try {
const invalidHmac = new jsSHA("SHA-256", "TEXT", {
hmacKey: { value: "secret", format: "TEXT" },
numRounds: 5 // Error: numRounds not valid with HMAC
});
} catch (error) {
console.error("Invalid HMAC configuration");
}