Skip to content

Instantly share code, notes, and snippets.

@odzhan
Last active November 16, 2022 21:33
Show Gist options
  • Select an option

  • Save odzhan/2eb5b793cb056eff4d1de978425489cb to your computer and use it in GitHub Desktop.

Select an option

Save odzhan/2eb5b793cb056eff4d1de978425489cb to your computer and use it in GitHub Desktop.
libarchive example to create password protected zip
/**
Compile with MSVC : cl /EHsc ark.cpp /I <path_to_libarchive>
*/
#include <cstdio>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <windows.h>
#include <wincrypt.h>
// libarchive
#include <archive.h>
#include <archive_entry.h>
#pragma comment(lib, "advapi32")
#define SHA_256_HASH_LENGTH 32
bool
SHA256(PBYTE pbInput, DWORD cbInput, BYTE bHash[SHA_256_HASH_LENGTH]) {
HCRYPTHASH hHash = NULL;
ULONG cbHash;
HCRYPTPROV hProvider = NULL;
BOOL bStatus = FALSE;
do {
bStatus = CryptAcquireContext(&hProvider, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
if (!bStatus) break;
bStatus = CryptCreateHash(hProvider, CALG_SHA_256, NULL, 0, &hHash);
if (!bStatus) break;
bStatus = CryptHashData(hHash, pbInput, cbInput, 0);
if (!bStatus) break;
cbHash = SHA_256_HASH_LENGTH;
bStatus = CryptGetHashParam(hHash, HP_HASHVAL, bHash, &cbHash, 0);
if (!bStatus) break;
} while (FALSE);
if (hHash) CryptDestroyHash(hHash);
if (hProvider) CryptReleaseContext(hProvider, 0);
return bStatus;
}
std::vector<BYTE>
ReadFileData(std::string path) {
std::ifstream instream(path, std::ios::in | std::ios::binary);
std::vector<BYTE> data((std::istreambuf_iterator<char>(instream)), std::istreambuf_iterator<char>());
return data;
}
bool
WriteFileData(std::string path, std::vector<BYTE> data) {
std::ofstream outstream(path, std::ios::out | std::ios::binary);
std::copy(data.begin(), data.end(), std::ostreambuf_iterator<char>(outstream));
return outstream.good();
}
size_t
CalcRatio(size_t Before, size_t After) {
if (After <= UINT_MAX / 100) {
After *= 100;
}
else {
Before /= 100;
}
if (Before == 0) {
Before = 1;
}
return (100 - (After / Before));
}
std::string
bin2hex(BYTE bin[], size_t size) {
std::ostringstream s;
for (size_t i=0; i<size; i++)
s << std::hex << std::setfill('0') << std::setw(2) << std::nouppercase << (int)bin[i];
return s.str();
}
void
DumpHash(std::string infile, std::vector<BYTE> inbuf) {
BYTE hash[SHA_256_HASH_LENGTH];
SHA256(inbuf.data(), inbuf.size(), hash);
printf("SHA256(\"%s\") : %s\n", infile.c_str(), bin2hex(hash, 32).c_str());
}
std::vector<BYTE>
zip_pack(std::vector<BYTE> inbuf) {
std::vector<BYTE> outbuf;
struct archive *archive=NULL;
struct archive_entry *entry=NULL;
archive = archive_write_new();
archive_write_set_format_zip(archive);
archive_write_set_options(archive, "encryption=aes256");
archive_write_set_passphrase(archive, "infected");
size_t outlen=0;
outbuf.resize(inbuf.size());
archive_write_open_memory(archive, outbuf.data(), outbuf.size(), &outlen);
entry = archive_entry_new();
archive_entry_set_mode(entry, AE_IFREG | 0444);
archive_entry_set_pathname(entry, "test.txt");
archive_write_header(archive, entry);
archive_write_data(archive, inbuf.data(), inbuf.size());
archive_entry_free(entry);
archive_write_close(archive);
archive_write_free(archive);
outbuf.resize(outlen);
return outbuf;
}
std::vector<BYTE>
zip_depack(std::vector<BYTE> inbuf) {
std::vector<BYTE> outbuf;
struct archive_entry *entry;
struct archive *archive=NULL;
archive = archive_read_new();
archive_read_support_format_zip(archive);
archive_read_add_passphrase(archive, "infected");
archive_read_open_memory(archive, inbuf.data(), inbuf.size());
archive_read_next_header(archive, &entry);
size_t outlen = archive_entry_size(entry);
outbuf.resize(outlen);
archive_read_data(archive, outbuf.data(), outbuf.size());
archive_read_close(archive);
archive_read_free(archive);
return outbuf;
}
int
main(int argc, char *argv[]) {
puts("\nlibarchive Example.");
if (argc != 4) {
printf("usage: ark [e/d] <infile> <outfile>\n");
return 0;
}
if (argv[1][0] != 'e' && argv[1][0] != 'd') {
printf("invalid parameters. first argument should be 'e' for encoding or 'd' for decoding.\n");
return 0;
}
bool depack = (argv[1][0] == 'd');
std::string infile = argv[2];
std::string outfile = argv[3];
std::vector<BYTE> inbuf = ReadFileData(infile);
if (inbuf.empty()) {
printf("%s could not be opened or is empty.\n", infile.c_str());
return 0;
}
DumpHash(infile, inbuf);
printf("%s \"%s\" -> \"%s\"\n",
depack ? "Decompressing" : "Compressing",
infile.c_str(),
outfile.c_str()
);
std::vector<BYTE> outbuf;
size_t ratio = 0;
if (depack) {
outbuf = zip_depack(inbuf);
ratio = CalcRatio(outbuf.size(), inbuf.size());
} else {
outbuf = zip_pack(inbuf);
ratio = CalcRatio(inbuf.size(), outbuf.size());
}
printf("%s ratio : %zd%%\n",
depack ? "Decompressed" : "Compressed",
ratio
);
WriteFileData(outfile, outbuf);
DumpHash(outfile, outbuf);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment