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.
npm run import -- "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
/**
* 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:
m
: This variable likely holds the initial state of the MD4 hash function (A, B, C, D).F
, G
, H
: These functions define the three basic operations used in MD4's compression function.lshift
Function:
x
by s
bits. It handles potential overflow by shifting the bits that wrap around back into the lower bits.mdfour64
Function:
M
) as input and processes it using the MD4 algorithm.AA
, BB
, CC
, DD
with the current state of the hash function (m
).ROUND1
, ROUND2
, and ROUND3
functions to update the hash state.F
, G
, or H
) to the current state variables.m
) with the new values of AA
, BB
, CC
, and DD
.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: