DEV Community

Cover image for How to Automate Encryption with C++ Script
Marcos Oliveira
Marcos Oliveira

Posted on

1

How to Automate Encryption with C++ Script

The other day I noticed that I had compressed several files as backups on a DVD media (the DVDs were at least 15 years old) and I had also encrypted all of them with GnuPG.

And all of these files had the same password for .gpg and I needed to know what was inside them.

Since many of the files were very long, there were even files larger than 5GB =)

I was about to start writing the shell script code to decrypt and unpack them all at once to find out what was inside them.

But, I remembered the limpeza command and this could be quick to write the code, but it would take me a lot of time to execute.

I could use the GPGME API and create it directly via C++ code, but it's not a complete application, it's just a basic little script!!!

So, I decided, once again, to create a script that could be done with GNU Bash in C++.


Introduction

First, what is GnuPG?

GnuPG is the acronym for: "GNU Privacy Guard (GnuPG or GPG)" is a free software alternative to Symantec's PGP cryptographic software suite.

GnuPG is part of the Free Software Foundation and the GNU Project. In addition, it received great sponsorship from the German Government.

Installing GnuPG

Use your operating system's package manager, examples:

winget install --id=GnuPG.GnuPG -e
Enter fullscreen mode Exit fullscreen mode

Via: https://winstall.app/apps/GnuPG.GnuPG or https://winget.run/pkg/GnuPG/GnuPG.

brew install gnupg
Enter fullscreen mode Exit fullscreen mode

Via: https://formulae.brew.sh/formula/gnupg

  • On Ubuntu
sudo apt install gnupg
Enter fullscreen mode Exit fullscreen mode

Basic use of GnuPG

Let's suppose you have a folder named files/ and you compressed it in .zip format and it became: files.zip.

If you want to protect it with a password and encryption, just run the command:

gpg -c files.zip
Enter fullscreen mode Exit fullscreen mode

Next, you will be asked for a password and confirmation of the password to create the file: files.zip.gpg. Only those who have access to this password will be able to decrypt it.

The cool (and dangerous) thing is that you can enter the password via the command line, both for encryption and decryption, and this can save you time from having to enter interactive mode and type password after password...

And it was thinking about not suffering from this repetitive boredom/stress that I had this idea!


Creating the C++ script

First of all, these .gpg type files were mixed with other types of files and I didn't want to filter them, because keeping them where they were was ideal before sending them to my local server here at home. So, they will also include the <filesystem> header to handle these files:

#include <iostream>
#include <filesystem>
#include <vector>

namespace fs = std::filesystem;

int main(){
    // Indicate the path of the folder, in this case, where the script is
    std::string directory_path = "./"; std::vector<std::string> gpg_files {};

    // Check if directory exists
    if (!fs::exists(directory_path) || !fs::is_directory(directory_path)) {
        std::cerr << "Directory does not exist or is not valid." << std::endl;
        return 1;
    }

    // Iterate over files in directory
    for (const auto& entry : fs::directory_iterator(directory_path)) {
        if (entry.is_regular_file() && entry.path().extension() == ".gpg") {
            gpg_files.push_back(entry.path().filename().string()); }
    }

    // Optional
    // Displays the names of the .gpg files found
    std::cout << "Found .gpg files:" << std::endl;
    for (const auto& file : gpg_files) {
        std::cout << file << ' ';
    }
    std::cout.put('\n');

    // Set the password for all files
    std::string str = "SECRET_PASSWORD";
}
Enter fullscreen mode Exit fullscreen mode

Now just run the command to decrypt the files found and listed:

for (const auto& file : gpg_files) {
    std::string com = "gpg --yes --batch --passphrase=" + str + " " + file + " 2>/dev/null"; std::cout << "Decrypting: " << file << std::endl;
    std::system(com.data());
}
Enter fullscreen mode Exit fullscreen mode

I would still automatically unpack them by adding them to the loop, but I gave up, in this case using the extract command because the types could vary: zip, rar, tar.gz,...

// filename equals file to separate the logic
std::string filename = file;

// Remove the .gpg from the filename
if (filename.size() >= 4) {
    filename = filename.substr(0, filename.size() - 4);
}

// Execute
std::string extract = "/usr/bin/extract " + filename;
std::cout << extract << std::endl;
std::system(extract.data());
Enter fullscreen mode Exit fullscreen mode

I gave up doing this because it would mix up my specific task, and then I tried it, but the result was not so good.

The complete code is: decript.cpp

#include <iostream>
#include <filesystem>
#include <vector>

namespace fs = std::filesystem;

int main(){
    // Indicate the path of the folder, in this case, where the script is
    std::string directory_path = "./";
    std::vector<std::string> gpg_files {};

    // Check if the directory exists
    if (!fs::exists(directory_path) || !fs::is_directory(directory_path)) {
        std::cerr << "The directory does not exist or is not valid." << std::endl;
        return 1; }

    // Iterate over the files in the directory
    for (const auto& entry : fs::directory_iterator(directory_path)) {
        if (entry.is_regular_file() && entry.path().extension() == ".gpg") {
            gpg_files.push_back(entry.path().filename().string());
        }
    }

    // Optional
    // Print the names of the .gpg files found
    std::cout << "Found .gpg files:" << std::endl;
    for (const auto& file : gpg_files) {
        std::cout << file << ' ';
    }
    std::cout.put('\n');

    // Set the password for all files
    std::string str = "SECRET_PASSWORD"; }

Enter fullscreen mode Exit fullscreen mode

If you want to do the same script, but to create .gpg files with passwords dynamically, replace com with:

std::string com = "gpg --yes --batch --passphrase=" + str + " -c " + file;
Enter fullscreen mode Exit fullscreen mode

Note the use of -c.


Final script

decript.cpp

#include <iostream>
#include <filesystem>
#include <vector>

namespace fs = std::filesystem;

int main(){
    std::string directory_path = "./";
    std::vector<std::string> gpg_files {};

    if (!fs::exists(directory_path) || !fs::is_directory(directory_path)) {
        std::cerr << "The directory does not exist or is not valid." << std::endl;
        return 1;
    }

    for (const auto& entry : fs::directory_iterator(directory_path)) {
        if (entry.is_regular_file() && entry.path().extension() == ".gpg") {
            gpg_files.push_back(entry.path().filename().string());
        }
    }

    std::cout << ".gpg files found:" << std::endl;
    for (const auto& file : gpg_files) {
        std::cout << file << ' ';
    }
    std::cout << "\n\n";

    std::string str = "SECRET_PASSWORD";

    for (const auto& file : gpg_files) {
        std::string com = "gpg --yes --batch --passphrase=" + str + " " + file + " 2>/dev/null";
        std::cout << "Decrypting: " << file << std::endl;
        int run = std::system(com.data());
        if(run != 0){
            std::cerr << "Failed to run: " << com << std::endl;
        }
    }

    return EXIT_SUCCESS;
}
Enter fullscreen mode Exit fullscreen mode

If you want to ensure that there is no memory violation, compile:

g++ -g -Wpedantic -Wall -Werror -fsanitize=address decript.cpp
Enter fullscreen mode Exit fullscreen mode

But, to run, add more speed in execution:

g++ -Ofast decript.cpp
Enter fullscreen mode Exit fullscreen mode

Then just run: ./a.out.

To extract, I used a script in Terlang:

vim unzip.ter

auto files = {"TheDir.tar.gz", "MyFolder.zip", "BigData.tar.gz"}
auto filesSize = 3

for(auto i = 0; i < filesSize; ++i){
    output("Unpacking: " + files[i])
    exec("extract " + files[i])
}
Enter fullscreen mode Exit fullscreen mode

And so, I did, in my own way, a task that could take me a long time, quickly and practically! 😃

Top comments (0)