CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-jssha

Pure TypeScript/JavaScript streaming implementation of the complete Secure Hash Standard (SHA) family with HMAC support

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

advanced-sha3.mddocs/

Advanced SHA3 Features

Advanced SHA-3 functionality including variable-length SHAKE algorithms, customizable cSHAKE variants, and KMAC (Keccak-based Message Authentication Code). These modern cryptographic functions provide enhanced security features and flexibility beyond traditional fixed-length hash functions.

Capabilities

SHAKE (Secure Hash Algorithm Keccak) - Variable Length

SHAKE algorithms provide variable-length output based on the Keccak sponge construction, offering configurable output sizes for specific security requirements.

/**
 * SHAKE constructor for TEXT input format
 * @param variant - SHAKE variant: SHAKE128 or SHAKE256
 * @param inputFormat - Must be "TEXT"
 * @param options - Optional configuration including encoding and numRounds
 */
constructor(variant: "SHAKE128" | "SHAKE256", inputFormat: "TEXT", options?: SHAKEOptionsEncodingType);

/**
 * SHAKE constructor for binary input formats
 * @param variant - SHAKE variant: SHAKE128 or SHAKE256
 * @param inputFormat - Binary format: HEX, B64, BYTES, ARRAYBUFFER, UINT8ARRAY
 * @param options - Optional configuration including numRounds
 */
constructor(variant: "SHAKE128" | "SHAKE256", inputFormat: FormatNoTextType, options?: SHAKEOptionsNoEncodingType);

interface SHAKEOptionsEncodingType {
  numRounds?: number;
  encoding?: EncodingType;
}

interface SHAKEOptionsNoEncodingType {
  numRounds?: number;
}

type EncodingType = "UTF8" | "UTF16BE" | "UTF16LE";
type FormatNoTextType = "HEX" | "B64" | "BYTES" | "ARRAYBUFFER" | "UINT8ARRAY";

Usage Examples:

import jsSHA from "jssha";

// SHAKE128 with 256-bit output
const shake128 = new jsSHA("SHAKE128", "TEXT", { encoding: "UTF8" });
shake128.update("Hello, SHAKE128!");
const hash256 = shake128.getHash("HEX", { outputLen: 256 });

// SHAKE256 with 512-bit output
const shake256 = new jsSHA("SHAKE256", "TEXT");
shake256.update("Hello, SHAKE256!");
const hash512 = shake256.getHash("HEX", { outputLen: 512 });

// Variable output lengths
const shake = new jsSHA("SHAKE128", "TEXT");
shake.update("Same input");
const short = shake.getHash("HEX", { outputLen: 128 });  // 128-bit output
const medium = shake.getHash("HEX", { outputLen: 384 }); // 384-bit output
const long = shake.getHash("HEX", { outputLen: 1024 });  // 1024-bit output

// SHAKE with hex input
const shakeHex = new jsSHA("SHAKE256", "HEX");
shakeHex.update("48656c6c6f"); // "Hello" in hex
const result = shakeHex.getHash("B64", { outputLen: 256 });

cSHAKE (Customizable SHAKE) - Domain Separation

cSHAKE extends SHAKE with domain separation through customization strings and function names, providing enhanced security in multi-purpose applications.

/**
 * cSHAKE constructor for TEXT input format
 * @param variant - cSHAKE variant: CSHAKE128 or CSHAKE256
 * @param inputFormat - Must be "TEXT"
 * @param options - Customization options including funcName and customization
 */
constructor(variant: "CSHAKE128" | "CSHAKE256", inputFormat: "TEXT", options?: CSHAKEOptionsEncodingType);

/**
 * cSHAKE constructor for binary input formats
 * @param variant - cSHAKE variant: CSHAKE128 or CSHAKE256
 * @param inputFormat - Binary format: HEX, B64, BYTES, ARRAYBUFFER, UINT8ARRAY
 * @param options - Customization options including funcName and customization
 */
constructor(variant: "CSHAKE128" | "CSHAKE256", inputFormat: FormatNoTextType, options?: CSHAKEOptionsNoEncodingType);

interface CSHAKEOptionsEncodingType {
  customization?: GenericInputType;
  funcName?: GenericInputType;
  encoding?: EncodingType;
}

interface CSHAKEOptionsNoEncodingType {
  customization?: GenericInputType;
  funcName?: GenericInputType;
}

interface GenericInputType {
  value: string;
  format: "TEXT";
  encoding?: EncodingType;
} | {
  value: string;
  format: "B64" | "HEX" | "BYTES";
} | {
  value: ArrayBuffer;
  format: "ARRAYBUFFER";
} | {
  value: Uint8Array;
  format: "UINT8ARRAY";
}

Usage Examples:

import jsSHA from "jssha";

// cSHAKE with customization string
const cshake1 = new jsSHA("CSHAKE128", "TEXT", {
  customization: { value: "MyApp", format: "TEXT" },
  encoding: "UTF8"
});
cshake1.update("Hello, cSHAKE!");
const result1 = cshake1.getHash("HEX", { outputLen: 256 });

// cSHAKE with function name and customization
const cshake2 = new jsSHA("CSHAKE256", "TEXT", {
  funcName: { value: "KeyDerivation", format: "TEXT" },
  customization: { value: "UserAuth-v1.0", format: "TEXT" }
});
cshake2.update("sensitive-data");
const result2 = cshake2.getHash("B64", { outputLen: 384 });

// cSHAKE with hex customization
const cshake3 = new jsSHA("CSHAKE128", "HEX", {
  customization: { value: "deadbeef", format: "HEX" }
});
cshake3.update("48656c6c6f"); // "Hello" in hex
const result3 = cshake3.getHash("UINT8ARRAY", { outputLen: 512 });

// Domain separation example
const emailHash = new jsSHA("CSHAKE256", "TEXT", {
  funcName: { value: "EmailHash", format: "TEXT" },
  customization: { value: "MyCompany-2024", format: "TEXT" }
});
emailHash.update("user@example.com");
const emailDigest = emailHash.getHash("HEX", { outputLen: 256 });

const passwordHash = new jsSHA("CSHAKE256", "TEXT", {
  funcName: { value: "PasswordHash", format: "TEXT" },
  customization: { value: "MyCompany-2024", format: "TEXT" }
});
passwordHash.update("user-password");
const passwordDigest = passwordHash.getHash("HEX", { outputLen: 256 });

KMAC (Keccak-based Message Authentication Code)

KMAC provides authenticated hashing based on cSHAKE, offering strong security guarantees for message authentication and integrity verification.

/**
 * KMAC constructor for TEXT input format
 * @param variant - KMAC variant: KMAC128 or KMAC256
 * @param inputFormat - Must be "TEXT"
 * @param options - Required kmacKey and optional customization
 */
constructor(variant: "KMAC128" | "KMAC256", inputFormat: "TEXT", options: KMACOptionsEncodingType);

/**
 * KMAC constructor for binary input formats
 * @param variant - KMAC variant: KMAC128 or KMAC256
 * @param inputFormat - Binary format: HEX, B64, BYTES, ARRAYBUFFER, UINT8ARRAY
 * @param options - Required kmacKey and optional customization
 */
constructor(variant: "KMAC128" | "KMAC256", inputFormat: FormatNoTextType, options: KMACOptionsNoEncodingType);

interface KMACOptionsEncodingType {
  kmacKey: GenericInputType;
  customization?: GenericInputType;
  encoding?: EncodingType;
}

interface KMACOptionsNoEncodingType {
  kmacKey: GenericInputType;
  customization?: GenericInputType;
}

Usage Examples:

import jsSHA from "jssha";

// Basic KMAC with text key
const kmac1 = new jsSHA("KMAC128", "TEXT", {
  kmacKey: { value: "secret-key", format: "TEXT" },
  encoding: "UTF8"
});
kmac1.update("Message to authenticate");
const mac1 = kmac1.getHash("HEX", { outputLen: 256 });

// KMAC with customization string
const kmac2 = new jsSHA("KMAC256", "TEXT", {
  kmacKey: { value: "another-secret", format: "TEXT" },
  customization: { value: "MyProtocol-v2", format: "TEXT" }
});
kmac2.update("Authenticated message");
const mac2 = kmac2.getHash("B64", { outputLen: 512 });

// KMAC with hex key
const kmac3 = new jsSHA("KMAC128", "HEX", {
  kmacKey: { value: "deadbeefcafebabe", format: "HEX" }
});
kmac3.update("48656c6c6f"); // "Hello" in hex
const mac3 = kmac3.getHash("UINT8ARRAY", { outputLen: 256 });

// KMAC with ArrayBuffer key
const keyBuffer = new TextEncoder().encode("binary-key").buffer;
const kmac4 = new jsSHA("KMAC256", "ARRAYBUFFER", {
  kmacKey: { value: keyBuffer, format: "ARRAYBUFFER" },
  customization: { value: "FileIntegrity", format: "TEXT" }
});
const messageBuffer = new TextEncoder().encode("File content").buffer;
kmac4.update(messageBuffer);
const mac4 = kmac4.getHash("ARRAYBUFFER", { outputLen: 384 });

// API authentication with KMAC
function authenticateAPICall(endpoint: string, payload: string, apiKey: string): string {
  const message = `${endpoint}:${payload}`;
  const kmac = new jsSHA("KMAC256", "TEXT", {
    kmacKey: { value: apiKey, format: "TEXT" },
    customization: { value: "APIAuth-v1", format: "TEXT" }
  });
  kmac.update(message);
  return kmac.getHash("B64", { outputLen: 256 });
}

Output Length Requirements

All variable-length variants (SHAKE, cSHAKE, KMAC) require the outputLen parameter in the getHash() method. Note that shakeLen is a deprecated alias for outputLen and should not be used in new code:

// outputLen is required and specifies output length in BITS
const shake = new jsSHA("SHAKE128", "TEXT");
shake.update("Hello");

// Valid output lengths (multiples of 8 bits)
const hash128 = shake.getHash("HEX", { outputLen: 128 });  // 16 bytes
const hash256 = shake.getHash("HEX", { outputLen: 256 });  // 32 bytes
const hash512 = shake.getHash("HEX", { outputLen: 512 });  // 64 bytes
const hash1024 = shake.getHash("HEX", { outputLen: 1024 }); // 128 bytes

// Invalid - outputLen must be specified
try {
  const invalid = shake.getHash("HEX"); // Error: outputLen required
} catch (error) {
  console.error("outputLen parameter is required for variable-length variants");
}

// Invalid - outputLen must be multiple of 8
try {
  const invalid = shake.getHash("HEX", { outputLen: 129 }); // Error: not multiple of 8
} catch (error) {
  console.error("outputLen must be multiple of 8 bits");
}

Security Levels and Recommendations

SHAKE Security Levels

  • SHAKE128: 128-bit security level, suitable for most applications
  • SHAKE256: 256-bit security level, recommended for high-security applications

Output Length Guidelines

  • Minimum Output: Use at least the security level length (128 bits for SHAKE128, 256 bits for SHAKE256)
  • Authentication: For KMAC, use output lengths of 256 bits or more for strong authentication
  • Key Derivation: For key derivation, match the output length to the required key size
  • Digital Signatures: Use output lengths appropriate for the signature scheme

Customization Best Practices

// Good: Descriptive customization strings
const cshake = new jsSHA("CSHAKE256", "TEXT", {
  funcName: { value: "KeyDerivation", format: "TEXT" },
  customization: { value: "MyApp-UserAuth-v1.2", format: "TEXT" }
});

// Good: Domain-specific KMAC customization
const kmac = new jsSHA("KMAC256", "TEXT", {
  kmacKey: { value: "secret", format: "TEXT" },
  customization: { value: "FileIntegrity-SHA3", format: "TEXT" }
});

// Avoid: Empty or generic customization strings reduce security benefits

Advanced Use Cases

Key Derivation Function (KDF)

import jsSHA from "jssha";

function deriveKey(masterKey: string, salt: string, info: string, keyLength: number): Uint8Array {
  const cshake = new jsSHA("CSHAKE256", "TEXT", {
    funcName: { value: "KeyDerivation", format: "TEXT" },
    customization: { value: `${salt}:${info}`, format: "TEXT" }
  });
  cshake.update(masterKey);
  return cshake.getHash("UINT8ARRAY", { outputLen: keyLength * 8 });
}

const derivedKey = deriveKey("master-secret", "random-salt", "encryption-key", 32);

Stream Cipher Keystream Generation

import jsSHA from "jssha";

function generateKeystream(seed: string, nonce: string, length: number): Uint8Array {
  const shake = new jsSHA("SHAKE256", "TEXT");
  shake.update(`${seed}:${nonce}`);
  return shake.getHash("UINT8ARRAY", { outputLen: length * 8 });
}

const keystream = generateKeystream("cipher-seed", "unique-nonce", 1024);

Merkle Tree Construction

import jsSHA from "jssha";

function hashNode(left: string, right: string): string {
  const cshake = new jsSHA("CSHAKE256", "TEXT", {
    funcName: { value: "MerkleNode", format: "TEXT" },
    customization: { value: "MerkleTree-v1", format: "TEXT" }
  });
  cshake.update(`${left}${right}`);
  return cshake.getHash("HEX", { outputLen: 256 });
}

const rootHash = hashNode(hashNode("leaf1", "leaf2"), hashNode("leaf3", "leaf4"));

Error Handling

Advanced SHA-3 variants have specific requirements that can cause errors:

// KMAC requires kmacKey
try {
  const invalid = new jsSHA("KMAC128", "TEXT", {}); // Error: kmacKey required
} catch (error) {
  console.error("KMAC variants require kmacKey parameter");
}

// Variable-length variants require outputLen
try {
  const shake = new jsSHA("SHAKE128", "TEXT");
  shake.update("Hello");
  const invalid = shake.getHash("HEX"); // Error: outputLen required
} catch (error) {
  console.error("Variable-length variants require outputLen parameter");
}

// numRounds not supported with some variants
try {
  const invalid = new jsSHA("CSHAKE256", "TEXT", {
    numRounds: 2, // Error: numRounds not valid with cSHAKE
    customization: { value: "test", format: "TEXT" }
  });
} catch (error) {
  console.error("numRounds parameter not supported with MAC or cSHAKE variants");
}

Compatibility Notes

  • NIST Standards: cSHAKE and KMAC implementations follow NIST SP 800-185 specifications
  • Test Vectors: Implementation passes official NIST test vectors for all variants
  • Interoperability: Compatible with other standard-compliant SHA-3 implementations
  • Performance: Variable-length variants may have different performance characteristics than fixed-length variants

docs

advanced-sha3.md

core-hashing.md

hmac-operations.md

index.md

variant-classes.md

tile.json