Skip to content

Instantly share code, notes, and snippets.

@ashafq
Created September 21, 2019 01:12
Show Gist options
  • Select an option

  • Save ashafq/bcbdb8bb772619b1c7ab022afff20f23 to your computer and use it in GitHub Desktop.

Select an option

Save ashafq/bcbdb8bb772619b1c7ab022afff20f23 to your computer and use it in GitHub Desktop.
/**
* @brief A shitty password generator in C++
*/
//
// It's 2019, yet no command line parsers in C++ :'(
//
#include <boost/program_options.hpp>
namespace opt = boost::program_options;
//
// Standard includes
//
#include <algorithm>
#include <iostream>
#include <random>
#include <string>
#include <map>
#include <cmath>
enum Charset
{
ALPHA = 1 << 0,
NUM = 1 << 1,
PUNCT = 1 << 2,
SPACE = 1 << 3
};
static const std::string S_ALPHA_CAP("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
static const std::string S_ALPHA_LOW("abcdefghijklmnopqrstuvwxyz");
static const std::string S_DIGITS("0123456789");
static const std::string S_SPACE(" ");
static const std::string S_PUNCT(".,/?'\";:|\\{}[]<>`~!@#$%^&*()-_=+");
#define DEFAULT_PASSWORD_LENGTH (10)
#define DEFAULT_PASSWORD_CHARSET (Charset::ALPHA | Charset::NUM)
std::string GenerateRandomeString(std::size_t len, const std::string &pwset);
std::string GeneratePassword(std::size_t len, Charset charset);
double CalculateStringEntropy(const std::string &s);
int main(int argc, char *argv[])
{
try {
opt::options_description desc("Password generator");
desc.add_options()
("help,h", "Prints help message")
("charset,c", opt::value<std::string>(),
"Password character sets [alpha, num, punct, space]")
("length,l", opt::value<uint>(), "Password length")
("entropy,e", opt::value<std::string>(), "Calculate Shanon's entropy of password")
;
opt::variables_map vm;
opt::store(opt::parse_command_line(argc, argv, desc), vm);
opt::notify(vm);
if (vm.count("help")) {
std::cout << desc << std::endl;
return 0;
}
if (vm.count("entropy")) {
std::string password(vm["entropy"].as<std::string>());
double entropy(CalculateStringEntropy(password));
std::cout << "String: " << password << "\n"
<< "Entropy: " << entropy << std::endl;
return 0;
}
// Setting up default parameter
uint passLen = DEFAULT_PASSWORD_LENGTH;
uint passCharset = DEFAULT_PASSWORD_CHARSET;
// If charset is set via command line argument, then
// defaults are blown away and start anew.
if (vm.count("charset")) {
std::string charsetStr(vm["charset"].as<std::string>());
passCharset = 0;
if (charsetStr.find("alpha") != std::string::npos)
passCharset |= Charset::ALPHA;
if (charsetStr.find("num") != std::string::npos)
passCharset |= Charset::NUM;
if (charsetStr.find("punct") != std::string::npos)
passCharset |= Charset::PUNCT;
if (charsetStr.find("space") != std::string::npos)
passCharset |= Charset::SPACE;
}
// If length is set via command line argument, then length
// is set to the new value.
if (vm.count("length")) {
passLen = vm["length"].as<uint>();
}
std::string password = GeneratePassword(passLen, static_cast<Charset>(passCharset));
double entropy = CalculateStringEntropy(password);
std::cout << "Generated password: "
<< password
<< "\n"
<< "Entropy: "
<< entropy
<< std::endl;
} catch (std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
double CalculateStringEntropy(const std::string &s)
{
std::map<char, uint> freq;
for (auto c: s)
++freq[c];
double len = static_cast<double>(s.length());
double entropy = 0.0;
for (auto elem: freq) {
double prob = elem.second / len;
entropy -= prob * log2(prob);
}
return entropy;
}
std::string GeneratePassword(std::size_t len, Charset charset)
{
std::string pwCharset("");
if (charset & Charset::ALPHA)
pwCharset += S_ALPHA_CAP + S_ALPHA_LOW;
if (charset & Charset::NUM)
pwCharset += S_DIGITS;
if (charset & Charset::PUNCT)
pwCharset += S_PUNCT;
if (charset & Charset::SPACE)
pwCharset += S_SPACE;
return GenerateRandomeString(len, pwCharset);
}
std::string GenerateRandomeString(std::size_t len, const std::string &pwset)
{
std::string randString{""};
auto radix{pwset.length()};
std::random_device rand;
for (std::size_t i = 0; i < len; ++i)
randString += pwset[rand() % radix];
return randString;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment