纯JavaScript实现MD4哈希函数时出现‘offset is out of bounds’错误的修复求助
纯JavaScript实现MD4哈希函数时出现‘offset is out of bounds’错误的修复求助
我正在尝试编写一个用于MD4哈希的JavaScript脚本,已经实现了相应的字节序转换函数,但不确定为什么代码无法正常运行。
完整代码如下:
class Md4Context { constructor() { this.h = new Uint32Array([0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476]); this.digest = new Uint8Array(16); // uint8_t this.x = new Uint32Array(16); // uint32_t this.buffer = new Uint8Array(64); // uint8_t this.size = 0; this.totalSize = BigInt(0); // uint64_t; } } // Helper functions for JS endian conversion const LETOH32 = (value) => { return ( ((value & 0x000000FF) << 24) | ((value & 0x0000FF00) << 8) | ((value & 0x00FF0000) >> 8) | ((value & 0xFF000000) >>> 24) ); } const letoh32 = (buffer, offset) => { return ( (buffer[offset] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24)) >>> 0 ); }; const HTOLE32 = (value) => { return Uint8Array.from([ value & 0xFF, (value >> 8) & 0xFF, (value >> 16) & 0xFF, (value >> 24) & 0xFF, ]); }; const HTOLE32_BI = (value) => { if (typeof value !== 'bigint') throw new TypeError('Value must be a BigInt'); let byteLength = value.toString(2).length; if (byteLength <= 0 || !Number.isInteger(byteLength)) throw new RangeError('byteLength must be a positive integer'); const byteArray = new Uint8Array(byteLength); let tempValue = value; for (let i = 0; i < byteLength; i++) { byteArray[i] = Number(tempValue & 0xFFn); // Extract the least significant byte tempValue >>= 8n; // Shift right by 8 bits to process the next byte } if (tempValue !== 0n) throw new RangeError('Value exceeds the specified byte length'); return byteArray; } /* Start of Essential Process Functinos */ // Rotate 32-bit integer left function ROL32(inputInt, rotationAmount) { return (inputInt << rotationAmount) | (inputInt >>> (32 - rotationAmount)); } const F = (x, y, z) => ((x & y) | (~x & z)); // Round 1 const G = (x, y, z) => ((x & y) | (x & z) | (y & z)); // Round 2 const H = (x, y, z) => (x ^ y ^ z); // Round 3 // FF fn for round 1 const FF = (a, b, c, d, x, s) => { a += F(b, c, d) + x; a = ROL32(a, s); return a; } // GG fn for round 2 const GG = (a, b, c, d, x, s) => { a += G(b, c, d) + x + 0x5A827999; a = ROL32(a, s); return a; } // HH fn for round 3 const HH = (a, b, c, d, x, s) => { a += H(b, c, d) + x + 0x6ED9EBA1; a = ROL32(a, s); return a; } /* End of Essential Process Functinos */ // Initialize padding const padding = new Uint8Array(64); padding[0] = 0x80; function md4Compute(data, length, digest) { // Check parameters if (data === null && length !== 0) throw new Error('ERROR_INVALID_PARAMETER'); if (digest === null) throw new Error('ERROR_INVALID_PARAMETER'); try { const context = new Md4Context(); // Allocate a memory buffer to hold the MD4 context md4Update(context, data, length); // Digest the message // Finalize the MD4 message digest let output = md4Final(context, digest); return output; } catch (error) { throw new Error('Error during MD4 computation: ' + error); } finally { // Clean up context if necessary (JavaScript handles memory management) context = null; } } function md4Update(context, data) { let n; while (data.length > 0) { // The buffer can hold at most 64 bytes n = Math.min(data.length, 64 - context.size); // Copy the data to the buffer for (let i = 0; i < n; i++) { context.buffer[context.size + i] = data[i]; } // Update the MD4 context context.size += n; context.totalSize += BigInt(n); // Advance the data pointer data = data.slice(n); // Process message in 16-word blocks if (context.size === 64) { // Transform the 16-word block md4ProcessBlock(context); // Empty the buffer context.size = 0; } } } function md4Final(context, digest) { let paddingSize; const totalSize = context.totalSize * 8n; // Pad the message so that its length is congruent to 56 modulo 64 if (context.size < 56) { paddingSize = 56 - context.size; } else { paddingSize = 64 + 56 - context.size; } // Append padding md4Update(context, padding, paddingSize); // Append the length of the original message in little-endian context.x[14] = HTOLE32_BI(totalSize & 0xFFFFFFFFn)[0]; context.x[15] = HTOLE32_BI(totalSize >> 32n)[0]; // Process the final block md4ProcessBlock(context); // Convert hash state to little-endian and store it in the digest for (let i = 0; i < 4; i++) { context.h[i] = HTOLE32(context.h[i]); } if (digest !== null && digest !== undefined) { digest.set(context.digest.slice(0, 16)); } return context.digest; } function md4ProcessBlock(context) { let a = context.h[0]; let b = context.h[1]; let c = context.h[2]; let d = context.h[3]; let x = context.x; // Convert from little-endian byte order to host byte order (little-endian) for (let i = 0; i < 16; i++) { x[i] = LETOH32(x[i]); } // Round 1 a = FF(a, b, c, d, x[0], 3); d = FF(d, a, b, c, x[1], 7); c = FF(c, d, a, b, x[2], 11); b = FF(b, c, d, a, x[3], 19); a = FF(a, b, c, d, x[4], 3); d = FF(d, a, b, c, x[5], 7); c = FF(c, d, a, b, x[6], 11); b = FF(b, c, d, a, x[7], 19); a = FF(a, b, c, d, x[8], 3); d = FF(d, a, b, c, x[9], 7); c = FF(c, d, a, b, x[10], 11); b = FF(b, c, d, a, x[11], 19); a = FF(a, b, c, d, x[12], 3); d = FF(d, a, b, c, x[13], 7); c = FF(c, d, a, b, x[14], 11); b = FF(b, c, d, a, x[15], 19); // Round 2 a = GG(a, b, c, d, x[0], 3); d = GG(d, a, b, c, x[4], 5); c = GG(c, d, a, b, x[8], 9); b = GG(b, c, d, a, x[12], 13); a = GG(a, b, c, d, x[1], 3); d = GG(d, a, b, c, x[5], 5); c = GG(c, d, a, b, x[9], 9); b = GG(b, c, d, a, x[13], 13); a = GG(a, b, c, d, x[2], 3); d = GG(d, a, b, c, x[6], 5); c = GG(c, d, a, b, x[10], 9); b = GG(b, c, d, a, x[14], 13); a = GG(a, b, c, d, x[3], 3); d = GG(d, a, b, c, x[7], 5); c = GG(c, d, a, b, x[11], 9); b = GG(b, c, d, a, x[15], 13); // Round 3 a = HH(a, b, c, d, x[0], 3); d = HH(d, a, b, c, x[8], 9); c = HH(c, d, a, b, x[4], 11); b = HH(b, c, d, a, x[12], 15); a = HH(a, b, c, d, x[2], 3); d = HH(d, a, b, c, x[10], 9); c = HH(c, d, a, b, x[6], 11); b = HH(b, c, d, a, x[14], 15); a = HH(a, b, c, d, x[1], 3); d = HH(d, a, b, c, x[9], 9); c = HH(c, d, a, b, x[5], 11); b = HH(b, c, d, a, x[13], 15); a = HH(a, b, c, d, x[3], 3); d = HH(d, a, b, c, x[11], 9); c = HH(c, d, a, b, x[7], 11); b = HH(b, c, d, a, x[15], 15); // Update the hash value context.h[0] = (context.h[0] + a) >>> 0; context.h[1] = (context.h[1] + b) >>> 0; context.h[2] = (context.h[2] + c) >>> 0; context.h[3] = (context.h[3] + d) >>> 0; }
我是这样调用这个函数的,它应该返回一个Uint8Array,之后可以转换成十六进制格式:
let main_string = new TextEncoder().encode('hello world'); let digest = new TextEncoder().encode('digest123'); console.log(md4Compute(main_string, main_string.length, digest));
但运行后出现了如下错误:
RangeError: offset is out of bounds
有没有人知道怎么修复这个问题?
备注:内容来源于stack exchange,提问作者trwartek
相关产品推荐
相关产品推荐

