|
| 1 | +// generate CRC32 lookup table |
| 2 | +const crctable = (new Uint32Array(256)).map((t,crc)=>{ |
| 3 | + for(let j=0;j<8;j++){ |
| 4 | + if (0 !== (crc & 1)){ |
| 5 | + crc = (crc >>> 1) ^ 0xEDB88320 |
| 6 | + }else{ |
| 7 | + crc >>>= 1 |
| 8 | + } |
| 9 | + } |
| 10 | + return crc>>>0; |
| 11 | +}); |
| 12 | + |
| 13 | +function make_decrypter(/*Buffer*/pwd){ |
| 14 | + // C-style uInt32 Multiply |
| 15 | + const uMul = (a,b) => Math.imul(a, b) >>> 0; |
| 16 | + // Initialize keys with default values |
| 17 | + const keys = new Uint32Array([0x12345678, 0x23456789, 0x34567890]); |
| 18 | + // crc32 byte update |
| 19 | + const crc32update = (pCrc32, bval) => { |
| 20 | + return crctable[(pCrc32 ^ bval) & 0xff] ^ (pCrc32 >>> 8); |
| 21 | + } |
| 22 | + // update keys with byteValues |
| 23 | + const updateKeys = (byteValue) => { |
| 24 | + keys[0] = crc32update(keys[0], byteValue); |
| 25 | + keys[1] += keys[0] & 0xff; |
| 26 | + keys[1] = uMul(keys[1], 134775813) + 1; |
| 27 | + keys[2] = crc32update(keys[2], keys[1] >>> 24); |
| 28 | + } |
| 29 | + |
| 30 | + // 1. Stage initialize key |
| 31 | + const pass = (Buffer.isBuffer(pwd)) ? pwd : Buffer.from(pwd); |
| 32 | + for(let i=0; i< pass.length; i++){ |
| 33 | + updateKeys(pass[i]); |
| 34 | + } |
| 35 | + |
| 36 | + // return decrypter function |
| 37 | + return function (/*Buffer*/data){ |
| 38 | + if (!Buffer.isBuffer(data)){ |
| 39 | + throw 'decrypter needs Buffer' |
| 40 | + } |
| 41 | + // result - we create new Buffer for results |
| 42 | + const result = Buffer.alloc(data.length); |
| 43 | + let pos = 0; |
| 44 | + // process input data |
| 45 | + for(let c of data){ |
| 46 | + const k = (keys[2] | 2) >>> 0; // key |
| 47 | + c ^= (uMul(k, k^1) >> 8) & 0xff; // decode |
| 48 | + result[pos++] = c; // Save Value |
| 49 | + updateKeys(c); // update keys with decoded byte |
| 50 | + } |
| 51 | + return result; |
| 52 | + } |
| 53 | +} |
| 54 | + |
| 55 | +function decrypt(/*Buffer*/ data, /*Object*/header, /*String, Buffer*/ pwd){ |
| 56 | + if (!data || !Buffer.isBuffer(data) || data.length < 12) { |
| 57 | + return Buffer.alloc(0); |
| 58 | + } |
| 59 | + |
| 60 | + // We Initialize and generate decrypting function |
| 61 | + const decrypter = make_decrypter(pwd); |
| 62 | + |
| 63 | + // check - for testing password |
| 64 | + const check = header.crc >>> 24; |
| 65 | + // decrypt salt what is always 12 bytes and is a part of file content |
| 66 | + const testbyte = decrypter(data.slice(0, 12))[11]; |
| 67 | + |
| 68 | + // does password meet expectations |
| 69 | + if (check !== testbyte){ |
| 70 | + throw 'ADM-ZIP: Wrong Password'; |
| 71 | + } |
| 72 | + |
| 73 | + // decode content |
| 74 | + return decrypter(data.slice(12)); |
| 75 | +} |
| 76 | + |
| 77 | +module.exports = {decrypt}; |
0 commit comments