| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- import {
- WordArray,
- Hasher,
- } from './core.js';
- import { X64Word } from './x64-core.js';
- // Constants tables
- const RHO_OFFSETS = [];
- const PI_INDEXES = [];
- const ROUND_CONSTANTS = [];
- // Compute Constants
- // Compute rho offset constants
- let _x = 1;
- let _y = 0;
- for (let t = 0; t < 24; t += 1) {
- RHO_OFFSETS[_x + 5 * _y] = ((t + 1) * (t + 2) / 2) % 64;
- const newX = _y % 5;
- const newY = (2 * _x + 3 * _y) % 5;
- _x = newX;
- _y = newY;
- }
- // Compute pi index constants
- for (let x = 0; x < 5; x += 1) {
- for (let y = 0; y < 5; y += 1) {
- PI_INDEXES[x + 5 * y] = y + ((2 * x + 3 * y) % 5) * 5;
- }
- }
- // Compute round constants
- let LFSR = 0x01;
- for (let i = 0; i < 24; i += 1) {
- let roundConstantMsw = 0;
- let roundConstantLsw = 0;
- for (let j = 0; j < 7; j += 1) {
- if (LFSR & 0x01) {
- const bitPosition = (1 << j) - 1;
- if (bitPosition < 32) {
- roundConstantLsw ^= 1 << bitPosition;
- } else /* if (bitPosition >= 32) */ {
- roundConstantMsw ^= 1 << (bitPosition - 32);
- }
- }
- // Compute next LFSR
- if (LFSR & 0x80) {
- // Primitive polynomial over GF(2): x^8 + x^6 + x^5 + x^4 + 1
- LFSR = (LFSR << 1) ^ 0x71;
- } else {
- LFSR <<= 1;
- }
- }
- ROUND_CONSTANTS[i] = X64Word.create(roundConstantMsw, roundConstantLsw);
- }
- // Reusable objects for temporary values
- const T = [];
- for (let i = 0; i < 25; i += 1) {
- T[i] = X64Word.create();
- }
- /**
- * SHA-3 hash algorithm.
- */
- export class SHA3Algo extends Hasher {
- constructor(cfg) {
- /**
- * Configuration options.
- *
- * @property {number} outputLength
- * The desired number of bits in the output hash.
- * Only values permitted are: 224, 256, 384, 512.
- * Default: 512
- */
- super(Object.assign(
- { outputLength: 512 },
- cfg,
- ));
- }
- _doReset() {
- this._state = [];
- const state = this._state;
- for (let i = 0; i < 25; i += 1) {
- state[i] = new X64Word();
- }
- this.blockSize = (1600 - 2 * this.cfg.outputLength) / 32;
- }
- _doProcessBlock(M, offset) {
- // Shortcuts
- const state = this._state;
- const nBlockSizeLanes = this.blockSize / 2;
- // Absorb
- for (let i = 0; i < nBlockSizeLanes; i += 1) {
- // Shortcuts
- let M2i = M[offset + 2 * i];
- let M2i1 = M[offset + 2 * i + 1];
- // Swap endian
- M2i = (((M2i << 8) | (M2i >>> 24)) & 0x00ff00ff)
- | (((M2i << 24) | (M2i >>> 8)) & 0xff00ff00);
- M2i1 = (((M2i1 << 8) | (M2i1 >>> 24)) & 0x00ff00ff)
- | (((M2i1 << 24) | (M2i1 >>> 8)) & 0xff00ff00);
- // Absorb message into state
- const lane = state[i];
- lane.high ^= M2i1;
- lane.low ^= M2i;
- }
- // Rounds
- for (let round = 0; round < 24; round += 1) {
- // Theta
- for (let x = 0; x < 5; x += 1) {
- // Mix column lanes
- let tMsw = 0;
- let tLsw = 0;
- for (let y = 0; y < 5; y += 1) {
- const lane = state[x + 5 * y];
- tMsw ^= lane.high;
- tLsw ^= lane.low;
- }
- // Temporary values
- const Tx = T[x];
- Tx.high = tMsw;
- Tx.low = tLsw;
- }
- for (let x = 0; x < 5; x += 1) {
- // Shortcuts
- const Tx4 = T[(x + 4) % 5];
- const Tx1 = T[(x + 1) % 5];
- const Tx1Msw = Tx1.high;
- const Tx1Lsw = Tx1.low;
- // Mix surrounding columns
- const tMsw = Tx4.high ^ ((Tx1Msw << 1) | (Tx1Lsw >>> 31));
- const tLsw = Tx4.low ^ ((Tx1Lsw << 1) | (Tx1Msw >>> 31));
- for (let y = 0; y < 5; y += 1) {
- const lane = state[x + 5 * y];
- lane.high ^= tMsw;
- lane.low ^= tLsw;
- }
- }
- // Rho Pi
- for (let laneIndex = 1; laneIndex < 25; laneIndex += 1) {
- let tMsw;
- let tLsw;
- // Shortcuts
- const lane = state[laneIndex];
- const laneMsw = lane.high;
- const laneLsw = lane.low;
- const rhoOffset = RHO_OFFSETS[laneIndex];
- // Rotate lanes
- if (rhoOffset < 32) {
- tMsw = (laneMsw << rhoOffset) | (laneLsw >>> (32 - rhoOffset));
- tLsw = (laneLsw << rhoOffset) | (laneMsw >>> (32 - rhoOffset));
- } else /* if (rhoOffset >= 32) */ {
- tMsw = (laneLsw << (rhoOffset - 32)) | (laneMsw >>> (64 - rhoOffset));
- tLsw = (laneMsw << (rhoOffset - 32)) | (laneLsw >>> (64 - rhoOffset));
- }
- // Transpose lanes
- const TPiLane = T[PI_INDEXES[laneIndex]];
- TPiLane.high = tMsw;
- TPiLane.low = tLsw;
- }
- // Rho pi at x = y = 0
- const T0 = T[0];
- const state0 = state[0];
- T0.high = state0.high;
- T0.low = state0.low;
- // Chi
- for (let x = 0; x < 5; x += 1) {
- for (let y = 0; y < 5; y += 1) {
- // Shortcuts
- const laneIndex = x + 5 * y;
- const lane = state[laneIndex];
- const TLane = T[laneIndex];
- const Tx1Lane = T[((x + 1) % 5) + 5 * y];
- const Tx2Lane = T[((x + 2) % 5) + 5 * y];
- // Mix rows
- lane.high = TLane.high ^ (~Tx1Lane.high & Tx2Lane.high);
- lane.low = TLane.low ^ (~Tx1Lane.low & Tx2Lane.low);
- }
- }
- // Iota
- const lane = state[0];
- const roundConstant = ROUND_CONSTANTS[round];
- lane.high ^= roundConstant.high;
- lane.low ^= roundConstant.low;
- }
- }
- _doFinalize() {
- // Shortcuts
- const data = this._data;
- const dataWords = data.words;
- const nBitsLeft = data.sigBytes * 8;
- const blockSizeBits = this.blockSize * 32;
- // Add padding
- dataWords[nBitsLeft >>> 5] |= 0x1 << (24 - (nBitsLeft % 32));
- dataWords[((Math.ceil((nBitsLeft + 1) / blockSizeBits) * blockSizeBits) >>> 5) - 1] |= 0x80;
- data.sigBytes = dataWords.length * 4;
- // Hash final blocks
- this._process();
- // Shortcuts
- const state = this._state;
- const outputLengthBytes = this.cfg.outputLength / 8;
- const outputLengthLanes = outputLengthBytes / 8;
- // Squeeze
- const hashWords = [];
- for (let i = 0; i < outputLengthLanes; i += 1) {
- // Shortcuts
- const lane = state[i];
- let laneMsw = lane.high;
- let laneLsw = lane.low;
- // Swap endian
- laneMsw = (((laneMsw << 8) | (laneMsw >>> 24)) & 0x00ff00ff)
- | (((laneMsw << 24) | (laneMsw >>> 8)) & 0xff00ff00);
- laneLsw = (((laneLsw << 8) | (laneLsw >>> 24)) & 0x00ff00ff)
- | (((laneLsw << 24) | (laneLsw >>> 8)) & 0xff00ff00);
- // Squeeze state to retrieve hash
- hashWords.push(laneLsw);
- hashWords.push(laneMsw);
- }
- // Return final computed hash
- return new WordArray(hashWords, outputLengthBytes);
- }
- clone() {
- const clone = super.clone.call(this);
- clone._state = this._state.slice(0);
- const state = clone._state;
- for (let i = 0; i < 25; i += 1) {
- state[i] = state[i].clone();
- }
- return clone;
- }
- }
- /**
- * Shortcut function to the hasher's object interface.
- *
- * @param {WordArray|string} message The message to hash.
- *
- * @return {WordArray} The hash.
- *
- * @static
- *
- * @example
- *
- * var hash = CryptoJS.SHA3('message');
- * var hash = CryptoJS.SHA3(wordArray);
- */
- export const SHA3 = Hasher._createHelper(SHA3Algo);
- /**
- * Shortcut function to the HMAC's object interface.
- *
- * @param {WordArray|string} message The message to hash.
- * @param {WordArray|string} key The secret key.
- *
- * @return {WordArray} The HMAC.
- *
- * @static
- *
- * @example
- *
- * var hmac = CryptoJS.HmacSHA3(message, key);
- */
- export const HmacSHA3 = Hasher._createHmacHelper(SHA3Algo);
|