Skip to content
Brian Turek edited this page Apr 15, 2020 · 5 revisions

API

Starting in v3.1, the jsSHA API changed with the deprecation of setHMACKey and getHMAC in favor of specifying the HMAC key at object instantiation and calling getHash, respectively. I usually loathe changing the jsSHA API and doubly so with a minor version bump. The reasoning behind this change can be read below.

Overview

Usage of jsSHA typically involves three calls:

// See below for constructor arguments
const hash = new jsSHA(...);
// .update() can be called multiple times
hash.update("Stuff to hash")
// The first argument can be one of "HEX" | "B64" | "BYTES" | "ARRAYBUFFER" | "UINT8ARRAY".
hash.getHash("HEX")
// For variable-length hashes (SHAKE, cSHAKE, and KMAC), you must specify the output length, in bits:
// hash.getHash("HEX", { outputLen: 256 })

Constructor

The constructor is most easily understood if you group jsSHA into four usage families: normal hashing, HMAC, cSHAKE, and KMAC. These all use a bag-of-options argument, option, that uses a "basic" input type for many of its key/value pairs.

Option Type

The v3.1+ API options are built on a new "basic" type, called GenericInputType, that describes an input value:

type GenericInputType =
  | {
      value: string;
      format: "TEXT";
      encoding?: "UTF8" | "UTF16LE" | "UTF16BE";
    }
  | {
      value: string;
      format: "B64" | "HEX" | "BYTES";
    }
  | {
      value: ArrayBuffer;
      format: "ARRAYBUFFER";
    }
  | {
      value: Uint8Array;
      format: "UINT8ARRAY";
    };

In human speak:

  • For "TEXT" string-type inputs, you must specify value which is a string, you must specify a format with the literal string "TEXT", and you may specify encoding which must be one of the literal strings "UTF8", "UTF16LE", or "UTF16BE", defaults to "UTF8".
  • For "B64", "HEX", and "BYTES" string-type inputs, you must specify both value which is a string and a format which must be one of the literal strings "B64", "HEX", or "BYTES".
  • For ArrayBuffer inputs, you must specify both value which is an ArrayBuffer and a format which must be the literal string "ARRAYBUFFER".
  • For Uint8Array inputs, you must specify both value which is an Uint8Array and a format which must be the literal string "UINT8ARRAY".

Normal Usage

This is when you wish to perform a SHA hash one or more times. In pseudo-code:

// For future "TEXT" inputs:
const textHash = new jsSHA(
  variant: "SHA-1" | "SHA-224" | "SHA-256" | "SHA-384" | "SHA-512" | "SHA3-224"  | "SHA3-256" | "SHA3-384" | "SHA3-512" | "SHAKE128" | "SHAKE256",
  inputFormat: "TEXT",
  options: {
    encoding?: "UTF8" | "UTF16LE" | "UTF16BE";
    numRounds?: number
  }
);
// For future non-"TEXT" inputs:
const nonTextHash = new jsSHA(
  variant: "SHA-1" | "SHA-224" | "SHA-256" | "SHA-384" | "SHA-512" | "SHA3-224"  | "SHA3-256" | "SHA3-384" | "SHA3-512" | "SHAKE128" | "SHAKE256",
  inputFormat: "B64" | "HEX" | "BYTES" | "ARRAYBUFFER" | "UINT8ARRAY",
  options: {
    numRounds?: number
  }

// True JavaScript Example:
const hash = new jsSHA("SHA-1", "HEX", { numRounds: 1});
);

The only difference between the two is the omission of the encoding key in options as it is only relevant for "TEXT"-type inputs. variant specifies the desired algorithm to use and inputFormat influences how future .update() calls are interpreted. The numRounds key in options specifies the number of SHA hashes to perform on the input (e.g. for a value of 2, the output from the first hash is the input to the next hash iteration); it must be an integer >= 1, defaults to 1.

HMAC Usage

The HMAC constructor is similar to the "normal" constructor but with the addition of an extra options key/value called hmacKey whose value is of type GenericInputType as described earlier. This represents the HMAC key. In pseudo-code:

// For future "TEXT" inputs:
const hash = new jsSHA(
  variant: "SHA-1" | "SHA-224" | "SHA-256" | "SHA-384" | "SHA-512" | "SHA3-224"  | "SHA3-256" | "SHA3-384" | "SHA3-512",
  inputFormat: "TEXT",
  options: {
    encoding?: "UTF8" | "UTF16LE" | "UTF16BE";
    hmacKey: GenericInputType
  }  
);
// For future non-"TEXT" inputs:
const hash = new jsSHA(
  variant: "SHA-1" | "SHA-224" | "SHA-256" | "SHA-384" | "SHA-512" | "SHA3-224"  | "SHA3-256" | "SHA3-384" | "SHA3-512",
  inputFormat: "B64" | "HEX" | "BYTES" | "ARRAYBUFFER" | "UINT8ARRAY",
  options: {
    hmacKey: GenericInputType
  } 

// True JavaScript Example:
const hash = new jsSHA("SHA-1", "HEX", { hmacKey: { value: "Secret Key", format: "TEXT" } });
);

Again, the only difference between the two forms is the omission of the encoding key in the options argument. Also note that SHAKE128/256 do not support HMAC and the numRounds functionality is no longer available.

cSHAKE Usage

The CSHAKE constructor is similar to the "normal" constructor but with the addition of extra options keys/values called customization and funcName whose values are of type GenericInputType as described earlier. These represent the "customization" and "function-name" parameters described in the NIST cSHAKE specification. In pseudo-code:

// For future "TEXT" inputs:
const textHash = new jsSHA(
  variant: "CSHAKE128" | "CSHAKE256",
  inputFormat: "TEXT",
  options: {
    encoding?: "UTF8" | "UTF16LE" | "UTF16BE";
    customization?: GenericInputType;
    funcName?: GenericInputType;
  }  
);
// For future non-"TEXT" inputs:
const nonTextHash = new jsSHA(
  variant: "CSHAKE128" | "CSHAKE256",
  inputFormat: "B64" | "HEX" | "BYTES" | "ARRAYBUFFER" | "UINT8ARRAY",
  options: {
    customization?: GenericInputType;
    funcName?: GenericInputType;
  } 
);

// True JavaScript Example:
const hash = new jsSHA("CSHAKE128", "HEX", { customization: { value: "My Tagged Application", format: "TEXT" } });

Again, the only difference between the two forms is the omission of the encoding key in the options argument. The customization and funcName keys are both optional, as specified by NIST.

KMAC Usage

The KMAC constructor is similar to the "normal" constructor but with the addition of an extra options keys/values called customization and kmacKey whose values are of type GenericInputType as described earlier. These represent the "customization" and KMAC key parameters described in the NIST KMAC specification. In pseudo-code:

// For future "TEXT" inputs:
const textHash = new jsSHA(
  variant: "KMAC128" | "KMAC256",
  inputFormat: "TEXT",
  options: {
    encoding?: "UTF8" | "UTF16LE" | "UTF16BE";
    customization?: GenericInputType;
    kmacKey: GenericInputType;
  }  
);
// For future non-"TEXT" inputs:
const nonTextHash = new jsSHA(
  variant: "KMAC128" | "KMAC256",
  inputFormat: "B64" | "HEX" | "BYTES" | "ARRAYBUFFER" | "UINT8ARRAY",
  options: {
    customization?: GenericInputType;
    kmacKey: GenericInputType;
  } 
);

// True JavaScript Example:
const hash = new jsSHA("KMAC128", "HEX",
  {
    customization: { value: "My Tagged Application", format: "TEXT" },
    kmacKey: { value: "My Secret Key", format: "TEXT" }
  }
);

Again, the only difference between the two forms is the omission of the encoding key in the options argument. The customization is optional, as specified by NIST, whereas kmacKey is required.

.update(arg)

Depending on the inputFormat value specified at instantiation, .update() expects its sole argument to be either a string, ArrayBuffer, or Uint8Array. .update() may be called multiple times.

.getHash(arg, options?)

.getHash() expects the first argument to be one of the string literals "B64", "HEX", "BYTES", "ARRAYBUFFER", "UINT8ARRAY" which affects the output type:

  • "B64", "HEX" and "BYTES" cause a string to be returned.
  • "ARRAYBUFFER" causes an ArrayBuffer to be returned.
  • "UINT8ARRAY" causes an Uint8Array to be returned.

For variable-length hashes (SHAKE, cSHAKE, and KMAC), options must be in the form of {outputLen: number} where outputLen is the desired output length, in bits, and must be a multiple of 8.

For "B64" output type, options may in the form of {b64Pad: string} where b64Pad is the extra padding associated with Base-64 encoding, defaults to "=".

For "HEX" output type, options may in the form of {outputUpper: boolean} where outputUpper causes the output to be capitalized if true, defaults to false.