quake 3 | make pk3 indexes | crc checksum file | Search

This JavaScript code implements the core logic of the MD4 cryptographic hash function, processing 64-byte chunks of data through a series of rounds involving bitwise operations and constant additions. It does not, however, include the full implementation, which would also require initialization, padding, and finalization steps.

Run example

npm run import -- "md4 checksum"

md4 checksum


/* NOTE: This code makes no attempt to be fast!

It assumes that an int is at least 32 bits long
*/

var m

function F(X,Y,Z) {return (((X)&(Y)) | ((~(X))&(Z)))}
function G(X,Y,Z) {return (((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)))}
function H(X,Y,Z) {return ((X)^(Y)^(Z))}
function lshift(x,s) {return (((x)<<(s)) | ((x)>>>(32-(s))))}

/* this applies md4 to 64 byte chunks */
function mdfour64(M)
{
    var AA, BB, CC, DD
    var X = new Uint32Array(16)
    var A, B, C, D

    for (var j=0;j<16;j++)
        X[j] = M[j];

    function ROUND1(a,b,c,d,k,s) { return lshift(a + F(b,c,d) + X[k], s) }
    function ROUND2(a,b,c,d,k,s) { return lshift(a + G(b,c,d) + X[k] + 0x5A827999,s) }
    function ROUND3(a,b,c,d,k,s) { return lshift(a + H(b,c,d) + X[k] + 0x6ED9EBA1,s) }

 	A = m.A; B = m.B; C = m.C; D = m.D;
	AA = A; BB = B; CC = C; DD = D;

    A = ROUND1(A,B,C,D,  0,  3)
    D = ROUND1(D,A,B,C,  1,  7)
    C = ROUND1(C,D,A,B,  2, 11)
    B = ROUND1(B,C,D,A,  3, 19)
   
    A = ROUND1(A,B,C,D,  4,  3)
    D = ROUND1(D,A,B,C,  5,  7)
    C = ROUND1(C,D,A,B,  6, 11)
    B = ROUND1(B,C,D,A,  7, 19)
    
    A = ROUND1(A,B,C,D,  8,  3)
    D = ROUND1(D,A,B,C,  9,  7)
    C = ROUND1(C,D,A,B, 10, 11)
    B = ROUND1(B,C,D,A, 11, 19)
    
    A = ROUND1(A,B,C,D, 12,  3)
    D = ROUND1(D,A,B,C, 13,  7)
    C = ROUND1(C,D,A,B, 14, 11)
    B = ROUND1(B,C,D,A, 15, 19)

    
    A = ROUND2(A,B,C,D,  0,  3)
    D = ROUND2(D,A,B,C,  4,  5)
    C = ROUND2(C,D,A,B,  8,  9)
    B = ROUND2(B,C,D,A, 12, 13)
    
    A = ROUND2(A,B,C,D,  1,  3)
    D = ROUND2(D,A,B,C,  5,  5)
    C = ROUND2(C,D,A,B,  9,  9)
    B = ROUND2(B,C,D,A, 13, 13)
    
    A = ROUND2(A,B,C,D,  2,  3)
    D = ROUND2(D,A,B,C,  6,  5)
    C = ROUND2(C,D,A,B, 10,  9)
    B = ROUND2(B,C,D,A, 14, 13)
    
    A = ROUND2(A,B,C,D,  3,  3)
    D = ROUND2(D,A,B,C,  7,  5)
    C = ROUND2(C,D,A,B, 11,  9)
    B = ROUND2(B,C,D,A, 15, 13)

    
    A = ROUND3(A,B,C,D,  0,  3)
    D = ROUND3(D,A,B,C,  8,  9)
    C = ROUND3(C,D,A,B,  4, 11)
    B = ROUND3(B,C,D,A, 12, 15)
    
    A = ROUND3(A,B,C,D,  2,  3)
    D = ROUND3(D,A,B,C, 10,  9)
    C = ROUND3(C,D,A,B,  6, 11)
    B = ROUND3(B,C,D,A, 14, 15)
    
    A = ROUND3(A,B,C,D,  1,  3)
    D = ROUND3(D,A,B,C,  9,  9)
    C = ROUND3(C,D,A,B,  5, 11)
    B = ROUND3(B,C,D,A, 13, 15)
    
    A = ROUND3(A,B,C,D,  3,  3)
    D = ROUND3(D,A,B,C, 11,  9)
    C = ROUND3(C,D,A,B,  7, 11)
    B = ROUND3(B,C,D,A, 15, 15)

    A += AA; B += BB; C += CC; D += DD;

    for (var j=0;j<16;j++)
        X[j] = 0;

    m.A = A; m.B = B; m.C = C; m.D = D;
}

function copy64(M, input)
{
    for (var i=0;i<16;i++)
        M[i] =
            (input[i*4+3] << 24) |
            (input[i*4+2] << 16) |
            (input[i*4+1] << 8) |
            (input[i*4+0] << 0)
}

function mdfour_begin(md)
{
    md.A = 0x67452301
    md.B = 0xefcdab89
    md.C = 0x98badcfe
    md.D = 0x10325476
    md.totalN = 0
}


function mdfour_tail(input, n)
{
    var buf = new Uint8Array(128)
    var M = new Uint32Array(16)
    var b

    m.totalN += n

    b = m.totalN * 8

    if (n) for(var i=0;i<n;i++) buf[i] = input[i]
    buf[n] = 0x80

    if (n <= 55) {
        buf[56] = (b&0xFF)
        buf[57] = (b>>8)&0xFF
        buf[58] = (b>>16)&0xFF
        buf[59] = (b>>24)&0xFF
        copy64(M, buf)
        mdfour64(M)
    } else {
        buf[120] = (b&0xFF)
        buf[121] = (b>>8)&0xFF
        buf[122] = (b>>16)&0xFF
        buf[123] = (b>>24)&0xFF
        copy64(M, buf)
        mdfour64(M)
        copy64(M, buf.slice(64))
        mdfour64(M)
    }
}

function mdfour_update(md, input, n)
{
    var M = new Uint32Array(16)

    m = md

    if (n == 0) mdfour_tail(input, n)

    while (n - m.totalN >= 64) {
        copy64(M, input.slice(m.totalN, m.totalN + 64))
        mdfour64(M)
        m.totalN += 64
    }

    mdfour_tail(input.slice(m.totalN, m.totalN + 64), n - m.totalN)
}


function mdfour_result(md, out)
{
    out[0] = md.A
    out[1] = md.B
    out[2] = md.C
    out[3] = md.D
}

function mdfour(out, input, n)
{
    var md = {
        A: 0,
        B: 0,
        C: 0,
        D: 0,
        totalN: 0
    }
    mdfour_begin(md)
    mdfour_update(md, input, n)
    mdfour_result(md, out)
}

module.exports = mdfour

What the code could have been:

/**
 * A Markdown representation of the MD4 algorithm implementation in JavaScript.
 *
 * This implementation is based on the MD4 specification available at
 * https://en.wikipedia.org/wiki/MD4.
 *
 * @module mdfour
 */

class MD4 {
  /**
   * Initializes the MD4 state variables.
   *
   * @param {Object} md - The MD4 state object.
   */
  static begin(md) {
    md.A = 0x67452301;
    md.B = 0xefcdab89;
    md.C = 0x98badcfe;
    md.D = 0x10325476;
    md.totalN = 0;
  }

  /**
   * Copies 64 bytes from the input array to the MD4 block array.
   *
   * @param {Uint32Array} M - The MD4 block array.
   * @param {Uint8Array} input - The input array.
   */
  static copy64(M, input) {
    for (let i = 0; i < 16; i++) {
      M[i] =
        (input[i * 4 + 3] << 24) |
        (input[i * 4 + 2] << 16) |
        (input[i * 4 + 1] << 8) |
        (input[i * 4 + 0] << 0);
    }
  }

  /**
   * Processes the MD4 block.
   *
   * @param {Uint32Array} M - The MD4 block array.
   */
  static mdfour64(M) {
    const X = new Uint32Array(16);
    const AA = M.A;
    const BB = M.B;
    const CC = M.C;
    const DD = M.D;

    for (let j = 0; j < 16; j++) {
      X[j] = M[j];
    }

    const ROUND1 = (a, b, c, d, k, s) => MD4.lshift(a + MD4.F(b, c, d) + X[k], s);
    const ROUND2 = (a, b, c, d, k, s) =>
      MD4.lshift(a + MD4.G(b, c, d) + X[k] + 0x5A827999, s);
    const ROUND3 = (a, b, c, d, k, s) =>
      MD4.lshift(a + MD4.H(b, c, d) + X[k] + 0x6ED9EBA1, s);

    const A = MD4.lshift(AA, 3);
    const D = ROUND1(D, A, B, C, 0, 7);
    const C = ROUND1(C, D, A, B, 2, 11);
    const B = ROUND1(B, C, D, A, 3, 19);

    A = ROUND1(A, B, C, D, 4, 3);
    D = ROUND1(D, A, B, C, 5, 7);
    C = ROUND1(C, D, A, B, 6, 11);
    B = ROUND1(B, C, D, A, 7, 19);

    A = ROUND1(A, B, C, D, 8, 3);
    D = ROUND1(D, A, B, C, 9, 7);
    C = ROUND1(C, D, A, B, 10, 11);
    B = ROUND1(B, C, D, A, 11, 19);

    A = ROUND1(A, B, C, D, 12, 3);
    D = ROUND1(D, A, B, C, 13, 7);
    C = ROUND1(C, D, A, B, 14, 11);
    B = ROUND1(B, C, D, A, 15, 19);

    A = ROUND2(A, B, C, D, 0, 3);
    D = ROUND2(D, A, B, C, 4, 5);
    C = ROUND2(C, D, A, B, 8, 9);
    B = ROUND2(B, C, D, A, 12, 13);

    A = ROUND2(A, B, C, D, 1, 3);
    D = ROUND2(D, A, B, C, 5, 5);
    C = ROUND2(C, D, A, B, 9, 9);
    B = ROUND2(B, C, D, A, 13, 13);

    A = ROUND2(A, B, C, D, 2, 3);
    D = ROUND2(D, A, B, C, 6, 5);
    C = ROUND2(C, D, A, B, 10, 9);
    B = ROUND2(B, C, D, A, 14, 13);

    A = ROUND2(A, B, C, D, 3, 3);
    D = ROUND2(D, A, B, C, 7, 5);
    C = ROUND2(C, D, A, B, 11, 9);
    B = ROUND2(B, C, D, A, 15, 13);

    A = ROUND3(A, B, C, D, 0, 3);
    D = ROUND3(D, A, B, C, 8, 9);
    C = ROUND3(C, D, A, B, 4, 11);
    B = ROUND3(B, C, D, A, 12, 15);

    A = ROUND3(A, B, C, D, 2, 3);
    D = ROUND3(D, A, B, C, 10, 9);
    C = ROUND3(C, D, A, B, 6, 11);
    B = ROUND3(B, C, D, A, 14, 15);

    A = ROUND3(A, B, C, D, 1, 3);
    D = ROUND3(D, A, B, C, 9, 9);
    C = ROUND3(C, D, A, B, 5, 11);
    B = ROUND3(B, C, D, A, 13, 15);

    A = ROUND3(A, B, C, D, 3, 3);
    D = ROUND3(D, A, B, C, 11, 9);
    C = ROUND3(C, D, A, B, 7, 11);
    B = ROUND3(B, C, D, A, 15, 15);

    A += AA;
    B += BB;
    C += CC;
    D += DD;

    for (let j = 0; j < 16; j++) {
      X[j] = 0;
    }

    M.A = A;
    M.B = B;
    M.C = C;
    M.D = D;
  }

  /**
   * Shifts the 32-bit integer to the left by the specified number of bits.
   *
   * @param {number} x - The 32-bit integer to be shifted.
   * @param {number} s - The number of bits to be shifted.
   * @returns {number} The shifted 32-bit integer.
   */
  static lshift(x, s) {
    return ((x << s) | (x >>> (32 - s)));
  }

  /**
   * Calculates the F function for the MD4 algorithm.
   *
   * @param {number} x - The first input value.
   * @param {number} y - The second input value.
   * @param {number} z - The third input value.
   * @returns {number} The result of the F function.
   */
  static F(x, y, z) {
    return (x & y) | ((~x) & z);
  }

  /**
   * Calculates the G function for the MD4 algorithm.
   *
   * @param {number} x - The first input value.
   * @param {number} y - The second input value.
   * @param {number} z - The third input value.
   * @returns {number} The result of the G function.
   */
  static G(x, y, z) {
    return (x & y) | (x & z) | (y & z);
  }

  /**
   * Calculates the H function for the MD4 algorithm.
   *
   * @param {number} x - The first input value.
   * @param {number} y - The second input value.
   * @param {number} z - The third input value.
   * @returns {number} The result of the H function.
   */
  static H(x, y, z) {
    return x ^ y ^ z;
  }

  /**
   * Processes the MD4 block.
   *
   * @param {Uint32Array} M - The MD4 block array.
   */
  static mdfour64(M) {
    MD4.mdfour6464(M);
  }

  /**
   * Processes the MD4 block.
   *
   * @param {Uint32Array} M - The MD4 block array.
   */
  static mdfour64_64(M) {
    MD4.copy64(M, M);
  }

  /**
   * Processes the MD4 block.
   *
   * @param {Uint32Array} M - The MD4 block array.
   */
  static mdfour64_tail(M) {
    MD4.mdfour64_64(M);
  }
}

/**
 * Copies 64 bytes from the input array to the MD4 block array.
 *
 * @param {Uint32Array} M - The MD4 block array.
 * @param {Uint8Array} input - The input array.
 */
MD4.copy64 = function (M, input) {
  for (let i = 0; i < 16; i++) {
    M[i] =
      (input[i * 4 + 3] << 24) |
      (input[i * 4 + 2] << 16) |
      (input[i * 4 + 1] << 8) |
      (input[i * 4 + 0] << 0);
  }
};

/**
 * Processes the MD4 block.
 *
 * @param {Uint32Array} M - The MD4 block array.
 */
MD4.mdfour64 = function (M) {
  const X = new Uint32Array(16);
  const AA = M.A;
  const BB = M.B;
  const CC = M.C;
  const DD = M.D;

  for (let j = 0; j < 16; j++) {
    X[j] = M[j];
  }

  const ROUND1 = (a, b, c, d, k, s) => MD4.lshift(a + MD4.F(b, c, d) + X[k], s);
  const ROUND2 = (a, b, c, d, k, s) =>
    MD4.lshift(a + MD4.G(b, c, d) + X[k] + 0x5A827999, s);
  const ROUND3 = (a, b, c, d, k, s) =>
    MD4.lshift(a + MD4.H(b, c, d) + X[k] + 0x6ED9EBA1, s);

  const A = MD4.lshift(AA, 3);
  const D = ROUND1(D, A, B, C, 0, 7);
  const C = ROUND1(C, D, A, B, 2, 11);
  const B = ROUND1(B, C, D, A, 3, 19);

  A = ROUND1(A, B, C, D, 4, 3);
  D = ROUND1(D, A, B, C, 5, 7);
  C = ROUND1(C, D, A, B, 6, 11);
  B = ROUND1(B, C, D, A, 7, 19);

  A = ROUND1(A, B, C, D, 8, 3);
  D = ROUND1(D, A, B, C, 9, 7);
  C = ROUND1(C, D, A, B, 10, 11);
  B = ROUND1(B, C, D, A, 11, 19);

  A = ROUND1(A, B, C, D, 12, 3);
  D = ROUND1(D, A, B, C, 13, 7);
  C = ROUND1(C, D, A, B, 14, 11);
  B = ROUND1(B, C, D, A, 15, 19);

  A = ROUND2(A, B, C, D, 0, 3);
  D = ROUND2(D, A, B, C, 4, 5);
  C = ROUND2(C, D, A, B, 8, 9);
  B = ROUND2(B, C, D, A, 12, 13);

  A = ROUND2(A, B, C, D, 1, 3);
  D = ROUND2(D, A, B, C, 5, 5);
  C = ROUND2(C, D, A, B, 9, 9);
  B = ROUND2(B, C, D, A, 13, 13);

  A = ROUND2(A, B, C, D, 2, 3);
  D = ROUND2(D, A, B, C, 6, 5);
  C = ROUND2(C, D, A, B, 10, 9);
  B = ROUND2(B, C, D, A, 14, 13);

  A = ROUND2(A, B, C, D, 3, 3);
  D = ROUND2(D, A, B, C, 7, 5);
  C = ROUND2(C, D, A, B, 11, 9);
  B = ROUND2(B, C, D, A, 15, 13);

  A = ROUND3(A, B, C, D, 0, 3);
  D = ROUND3(D, A, B, C, 8, 9);
  C = ROUND3(C, D, A, B, 4, 11);
  B = ROUND3(B, C, D, A, 12, 15);

  A = ROUND3(A, B, C, D, 2, 3);
  D = ROUND3(D, A, B, C, 10, 9);
  C = ROUND3(C, D, A, B, 6, 11);
  B = ROUND3(B, C, D, A, 14, 15);

  A = ROUND3(A, B, C, D, 1, 3);
  D = ROUND3(D, A, B, C, 9, 9);
  C = ROUND3(C, D, A, B, 5, 11);
  B = ROUND3(B, C, D, A, 13, 15);

  A = ROUND3(A, B, C, D, 3, 3);
  D = ROUND3(D, A, B, C, 11, 9);
  C = ROUND3(C, D, A, B, 7, 11);
  B = ROUND3(B, C, D, A, 15, 15);

  A += AA;
  B += BB;
  C += CC;
  D += DD;

  for (let j = 0; j < 16; j++) {
    X[j] = 0;
  }

  M.A = A;
  M.B = B;
  M.C = C;
  M.D = D;
};

/**
 * Copies 64 bytes from the input array to the MD4 block array.
 *
 * @param {Uint32Array} M - The MD4 block array.
 * @param {Uint8Array} input - The input array.
 */
MD4.copy64 = function (M, input) {
  for (let i = 0; i < 16; i++) {
    M[i] =
      (input[i * 4 + 3] << 24) |
      (input[i * 4 + 2] << 16) |
      (input[i * 4 + 1] << 8) |
      (input[i * 4 + 0] << 0);
  }
};

function mdfour_begin(md) {
  MD4.begin(md);
}

function mdfour_update(md, input, n) {
  if (n == 0) {
    MD4.mdfour_tail(md, input);
    return;
  }

  let M = new Uint32Array(16);
  let totalN = md.totalN;

  while (n - totalN >= 64) {
    const chunk = input.slice(totalN, totalN + 64);
    MD4.copy64(M, chunk);
    MD4.mdfour64(M);
    totalN += 64;
  }

  MD4.mdfour_tail(md, input.slice(totalN, totalN + n));
  md.totalN = totalN + n;
}

function mdfour_tail(md, input) {
  const buf = new Uint8Array(128);
  const M = new Uint32Array(16);
  const b = md.totalN * 8;

  buf.fill(0);
  const len = input.length;

  for (let i = 0; i < len; i++) {
    buf[i] = input[i];
  }

  buf[len] = 0x80;

  if (len <= 55) {
    buf[56] = b & 0xFF;
    buf[57] = (b >> 8) & 0xFF;
    buf[58] = (b >> 16) & 0xFF;
    buf[59] = (b >> 24) & 0xFF;
    MD4.copy64(M, buf);
    MD4.mdfour64(M);
  } else {
    buf[120] = b & 0xFF;
    buf[121] = (b >> 8) & 0xFF;
    buf[122] = (b >> 16) & 0xFF;
    buf[123] = (b >> 24) & 0xFF;
    MD4.copy64(M, buf);
    MD4.mdfour64(M);
    MD4.copy64(M, buf.slice(64));
    MD4.mdfour64(M);
  }
}

function mdfour_result(md, out) {
  out[0] = md.A;
  out[1] = md.B;
  out[2] = md.C;
  out[3] = md.D;
}

function mdfour(input, n, out) {
  const md = {
    A: 0,
    B: 0,
    C: 0,
    D: 0,
    totalN: 0,
  };

  MD4.begin(md);
  MD4.mdfour_update(md, input, n);
  MD4.mdfour_result(md, out);

  return md;
}

module.exports = mdfour;

This code implements the MD4 cryptographic hash function in JavaScript.

Here's a breakdown:

Initialization:

lshift Function:

mdfour64 Function:

Overall:

This code implements the core logic of the MD4 hash function, designed to process 64-byte chunks of data. It's important to note that this code snippet doesn't include the full MD4 implementation, as it only handles the processing of individual chunks. A complete implementation would also include: