-
-
Notifications
You must be signed in to change notification settings - Fork 394
Home
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.
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 })
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.
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 astring
, you must specify aformat
with the literal string "TEXT", and you may specifyencoding
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 astring
and aformat
which must be one of the literal strings "B64", "HEX", or "BYTES". - For
ArrayBuffer
inputs, you must specify bothvalue
which is anArrayBuffer
and aformat
which must be the literal string "ARRAYBUFFER". - For
Uint8Array
inputs, you must specify bothvalue
which is anUint8Array
and aformat
which must be the literal string "UINT8ARRAY".
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.
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.
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.
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.
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()
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
.