diff --git a/CMakeLists.txt b/CMakeLists.txt index 72287f4..a5432c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,3 +43,14 @@ target_link_libraries(libzip_extract_file PRIVATE PkgConfig::LIBZIP) add_executable(libzip_add_files src/libzip/add_files.cpp) target_link_libraries(libzip_add_files PRIVATE PkgConfig::LIBZIP) + +# create encrypted archive + +add_executable(libzip_create_encrypted_archive src/libzip/create_encrypted_archive.cpp) +target_link_libraries(libzip_create_encrypted_archive PRIVATE PkgConfig::LIBZIP) + + +# extract encrypted file + +add_executable(libzip_extract_encrypted_file src/libzip/extract_encrypted_file.cpp) +target_link_libraries(libzip_extract_encrypted_file PRIVATE PkgConfig::LIBZIP) diff --git a/README.md b/README.md index a73534d..ebf6223 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ read, write and manipulate zip archives. | [create archive](doc/create_archive.md) | :white_check_mark: | :white_check_mark: | | [extract a single file](doc/extract_single_file.md) | :white_check_mark: | :white_check_mark: | | [add files to an existing archive](doc/add_files.md) | :x: | :white_check_mark: | +| create encrypted archive | ? | :white_check_mark: | +| extract encrypted archive | ? | :white_check_mark: | ## Build examples diff --git a/src/libzip/create_encrypted_archive.cpp b/src/libzip/create_encrypted_archive.cpp new file mode 100644 index 0000000..f1f5df3 --- /dev/null +++ b/src/libzip/create_encrypted_archive.cpp @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: Unlicense + +#include + +#include +#include +#include +#include + +namespace +{ + +void print_usage() +{ + std::cout << R"(libzip_create_encrypted_archive, (c) 2026 Falk Werner +Creates an encrypted archive + +Usage: + libzip_create_encrypted_archive ... + +Arguments: + archive - filename of the newly created archive + password - password used for encryption + filename - name of the file to add + +Example: + libzip_create_encrypted_archive test.zip. secret README.md +)"; +} + +struct entry +{ + std::string local_filename; + std::string archive_filename; +}; + +struct context +{ + context(int argc, char* argv[]) + { + show_help = (argc <= 3); + if (argc > 3) + { + archive_filename = argv[1]; + password = argv[2]; + + for(int i = 3; i < argc; i++) + { + std::string const arg = argv[i]; + if ((arg == "-h") || (arg == "--help")) + { + show_help = true; + break; + } + + entry e = {arg, arg}; + auto const pos = arg.find(':'); + if (pos != std::string::npos) + { + e = { arg.substr(0, pos), arg.substr(pos +1) }; + } + entries.push_back(e); + } + } + } + + bool show_help; + std::string archive_filename; + std::string password; + std::vector entries; +}; + +int create_encrypted_archive( + std::string const & filename, + std::string const & password, + std::vector const & entries) +{ + int exit_code = EXIT_SUCCESS; + + auto * const archive = zip_open(filename.c_str(), ZIP_CREATE | ZIP_TRUNCATE, nullptr); + if (archive == nullptr) + { + std::cerr << "error: failed to create archive" << std::endl; + return EXIT_FAILURE; + } + + for(auto const & e: entries) + { + if (!std::filesystem::is_regular_file(e.local_filename)) + { + continue; + } + + auto * source = zip_source_file(archive, e.local_filename.c_str(), 0, + std::filesystem::file_size(e.local_filename)); + auto const i = zip_add(archive, e.archive_filename.c_str(), source); + if (i == -1) + { + std::cerr << "error: failed to add file: " << e.local_filename << std::endl; + exit_code = EXIT_FAILURE; + zip_source_free(source); + } + + zip_file_set_encryption(archive, i, ZIP_EM_AES_256, password.c_str()); + std::cout << e.local_filename << std::endl; + } + + zip_close(archive); + return exit_code; +} + +} + + +int main(int argc, char* argv[]) +{ + context ctx(argc, argv); + int exit_code = EXIT_SUCCESS; + + if (!ctx.show_help) + { + exit_code = create_encrypted_archive(ctx.archive_filename, ctx.password, ctx.entries); + } + else + { + print_usage(); + } + + return exit_code; +} \ No newline at end of file diff --git a/src/libzip/extract_encrypted_file.cpp b/src/libzip/extract_encrypted_file.cpp new file mode 100644 index 0000000..7f85e44 --- /dev/null +++ b/src/libzip/extract_encrypted_file.cpp @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: Unlicense + +#include + +#include +#include +#include + + +int main(int argc, char* argv[]) +{ + if (argc != 4) + { + std::cout << R"(libzip_extract_encrypted_file, (c) 2026 Falk Werner +Extract file from an encrypted archive + +Usage: + libzip_extrace_encrypted_file + +Arguments: + archive - filename of an existing encrypted zip archive + password - password + filename - name of the file to extract +)"; + } + + std::string const archive_filename = argv[1]; + std::string const password = argv[2]; + std::string const filename = argv[3]; + + auto * const archive = zip_open(archive_filename.c_str(), ZIP_RDONLY, nullptr); + if (archive == nullptr) + { + std::cerr << "error: failed to open archive" << std::endl; + return EXIT_FAILURE; + } + + auto const i = zip_name_locate(archive, filename.c_str(), 0); + if (i == -1) + { + std::cerr << "error: failed to find file in archive" << std::endl; + zip_close(archive); + return EXIT_FAILURE; + } + + auto * const file = zip_fopen_encrypted(archive, filename.c_str(), 0, password.c_str()); + if (file == nullptr) + { + std::cerr << "error: failed to open archived file" << std::endl; + zip_close(archive); + return EXIT_FAILURE; + } + + char buffer[10240]; + auto length = zip_fread(file, buffer, 10240); + while (0 < length) + { + fwrite(buffer, 1, length, stdout); + length = zip_fread(file, buffer, 10240); + } + + zip_fclose(file); + zip_close(archive); + return EXIT_SUCCESS; +} \ No newline at end of file