Skip to content

Commit

Permalink
Added ZipCrypto decrypting ability
Browse files Browse the repository at this point in the history
  • Loading branch information
5saviahv committed Nov 18, 2020
1 parent 63ed6e2 commit 003d4cf
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 10 deletions.
12 changes: 6 additions & 6 deletions adm-zip.js
Expand Up @@ -63,9 +63,9 @@ module.exports = function (/**String*/input) {
*
* @return Buffer or Null in case of error
*/
readFile: function (/**Object*/entry) {
readFile: function (/**Object*/entry, /*String, Buffer*/pass) {
var item = getEntry(entry);
return item && item.getData() || null;
return item && item.getData(pass) || null;
},

/**
Expand Down Expand Up @@ -482,7 +482,7 @@ module.exports = function (/**String*/input) {
* Test the archive
*
*/
test: function () {
test: function (pass) {
if (!_zip) {
return false;
}
Expand All @@ -492,7 +492,7 @@ module.exports = function (/**String*/input) {
if (entry.isDirectory) {
continue;
}
var content = _zip.entries[entry].getData();
var content = _zip.entries[entry].getData(pass);
if (!content) {
return false;
}
Expand All @@ -510,7 +510,7 @@ module.exports = function (/**String*/input) {
* @param overwrite If the file already exists at the target path, the file will be overwriten if this is true.
* Default is FALSE
*/
extractAllTo: function (/**String*/targetPath, /**Boolean*/overwrite) {
extractAllTo: function (/**String*/targetPath, /**Boolean*/overwrite, /*String, Buffer*/pass) {
overwrite = overwrite || false;
if (!_zip) {
throw new Error(Utils.Errors.NO_ZIP);
Expand All @@ -521,7 +521,7 @@ module.exports = function (/**String*/input) {
Utils.makeDir(entryName);
return;
}
var content = entry.getData();
var content = entry.getData(pass);
if (!content) {
throw new Error(Utils.Errors.CANT_EXTRACT_FILE);
}
Expand Down
3 changes: 2 additions & 1 deletion methods/index.js
@@ -1,2 +1,3 @@
exports.Deflater = require("./deflater");
exports.Inflater = require("./inflater");
exports.Inflater = require("./inflater");
exports.ZipCrypto = require("./zipcrypto");
77 changes: 77 additions & 0 deletions methods/zipcrypto.js
@@ -0,0 +1,77 @@
// generate CRC32 lookup table
const crctable = (new Uint32Array(256)).map((t,crc)=>{
for(let j=0;j<8;j++){
if (0 !== (crc & 1)){
crc = (crc >>> 1) ^ 0xEDB88320
}else{
crc >>>= 1
}
}
return crc>>>0;
});

function make_decrypter(/*Buffer*/pwd){
// C-style uInt32 Multiply
const uMul = (a,b) => Math.imul(a, b) >>> 0;
// Initialize keys with default values
const keys = new Uint32Array([0x12345678, 0x23456789, 0x34567890]);
// crc32 byte update
const crc32update = (pCrc32, bval) => {
return crctable[(pCrc32 ^ bval) & 0xff] ^ (pCrc32 >>> 8);
}
// update keys with byteValues
const updateKeys = (byteValue) => {
keys[0] = crc32update(keys[0], byteValue);
keys[1] += keys[0] & 0xff;
keys[1] = uMul(keys[1], 134775813) + 1;
keys[2] = crc32update(keys[2], keys[1] >>> 24);
}

// 1. Stage initialize key
const pass = (Buffer.isBuffer(pwd)) ? pwd : Buffer.from(pwd);
for(let i=0; i< pass.length; i++){
updateKeys(pass[i]);
}

// return decrypter function
return function (/*Buffer*/data){
if (!Buffer.isBuffer(data)){
throw 'decrypter needs Buffer'
}
// result - we create new Buffer for results
const result = Buffer.alloc(data.length);
let pos = 0;
// process input data
for(let c of data){
const k = (keys[2] | 2) >>> 0; // key
c ^= (uMul(k, k^1) >> 8) & 0xff; // decode
result[pos++] = c; // Save Value
updateKeys(c); // update keys with decoded byte
}
return result;
}
}

function decrypt(/*Buffer*/ data, /*Object*/header, /*String, Buffer*/ pwd){
if (!data || !Buffer.isBuffer(data) || data.length < 12) {
return Buffer.alloc(0);
}

// We Initialize and generate decrypting function
const decrypter = make_decrypter(pwd);

// check - for testing password
const check = header.crc >>> 24;
// decrypt salt what is always 12 bytes and is a part of file content
const testbyte = decrypter(data.slice(0, 12))[11];

// does password meet expectations
if (check !== testbyte){
throw 'ADM-ZIP: Wrong Password';
}

// decode content
return decrypter(data.slice(12));
}

module.exports = {decrypt};
8 changes: 5 additions & 3 deletions zipEntry.js
Expand Up @@ -34,7 +34,7 @@ module.exports = function (/*Buffer*/input) {
return true;
}

function decompress(/*Boolean*/async, /*Function*/callback, /*String*/pass) {
function decompress(/*Boolean*/async, /*Function*/callback, /*String, Buffer*/pass) {
if(typeof callback === 'undefined' && typeof async === 'string') {
pass=async;
async=void 0;
Expand All @@ -55,8 +55,10 @@ module.exports = function (/*Buffer*/input) {
}

if (_entryHeader.encripted){
if (async && callback) callback(Buffer.alloc(0), Utils.Errors.UNKNOWN_METHOD);
throw new Error(Utils.Errors.UNKNOWN_METHOD);
if ('string' !== typeof pass && !Buffer.isBuffer(pass)){
throw new Error('ADM-ZIP: Incompatible password parameter');
}
compressedData = Methods.ZipCrypto.decrypt(compressedData, _entryHeader, pass);
}

var data = Buffer.alloc(_entryHeader.size);
Expand Down

0 comments on commit 003d4cf

Please sign in to comment.