artem-karpenko/archiver-zip-encrypted

Is there a way to decrypt a 'zip20' file using this library?

shanetorres opened this issue · 5 comments

I need functionality to decrypt a zip file from within my code, is that possible with this library?

Hi @shanetorres,
while there is a decrypto-stream class in the library that's capable of decrypting zip20 streams, archiver library does not support decompression in general (it seems to be out of scope for that project). This means that I cannot design this library to be used for decompression and decryption in archiver.

@artem-karpenko got it, thanks for the response.

ralmo commented

Really sorry to butt in but have you ever been able to solve your issue, @shanetorres ?

I'm slowly getting desperate... The "node-unzipper" library appears to be the only one which is (in theory) capable of decrypting zip20. However, it takes about approx. 8 minutes per MB on my target device making it useless for my ~50 MB archives.

@artem-karpenko Funny: encryption and compression using your library and "archiver" would only take about 1-2 minutes on the same device for the same size...

@ralmo I think i just ended up doing it with the crypto library, i don't remember too much about this since it was about a year ago, but I was able to dig up some of the code i used.

I used aes-256-ctr to create a cypher like this

function generateCipher() {
  return crypto.createCipher('aes-256-ctr', aesKey(key));
}

and then created a decipher in a similar way

function generateDecipher() {
  return crypto.createDecipher('aes-256-ctr', aesKey(key));
}

i was downloading zip files and encrypting them on download, i did this with pipe

 return new Promise(function(resolve, reject) {
    const request = http.get(fileURI.href).on('response', function(res) {
      // Encrypt and then write the file to disk
      res.pipe(cipher).pipe(file);

      // variables used for the download percentage.
      const len = parseInt(res.headers['content-length'], 10);
      let downloaded = 0;
      let percent = 0;
      res.on('data', function(chunk) {
        // update the download percentage on each chunk downloaded.
        downloaded += chunk.length;
        percent = (100.0 * downloaded / len).toFixed(0);
        actionText.text(percent + '%');
      })
      .on('end', function() {
        resolve()
      }).on('error', function (err) {
        reject(err)
      })
    })
  })
}

and then i would simply decrypt using pipe as well

async function decryptZip(zip, decryptedZipWritePath) {
  const encryptedZipReadPath = path;
  let readStream = fs.createReadStream(encryptedZipReadPath);
  let writeStream = fs.createWriteStream(decryptedZipWritePath);
  let decipher = key.generateDecipher();

  return new Promise(function(resolve, reject) {
    // pipe data from readstream into decipher, write decrypted data to file.
    readStream.pipe(decipher).pipe(writeStream);
    readStream.on("error", (err) => reject(err));

    writeStream.on("finish", () => resolve());
  })
}

then i'd just unzip the decrypted file somewhere

not sure if that will necessarily work for you but thats the route i ended up taking. hope it helps

ralmo commented

Thank you very much for your code examples and your quick response! This might indeed help me with an alternative approach.

Just for the purpose of clarity: I assume that this is not compatible to "real" aes256-encrypted ZIP-archives, correct? Meaning I will not be able to open those files with e.g. 7zip?

edit: As expected, it's not possible. On the other hand it's blazing fast, even on my slow device so I might end up using this. Thank you for the input again.