Created
September 21, 2019 01:12
-
-
Save ashafq/bcbdb8bb772619b1c7ab022afff20f23 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * @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