2024-04-28 15:07:47 +00:00
|
|
|
#include <cctype>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <functional>
|
2024-04-28 10:01:50 +00:00
|
|
|
#include <iostream>
|
2024-04-28 10:32:48 +00:00
|
|
|
#include <fstream>
|
2024-04-28 15:07:47 +00:00
|
|
|
#include <optional>
|
|
|
|
#include <ostream>
|
2024-04-28 11:53:52 +00:00
|
|
|
#include <random>
|
2024-04-28 10:32:48 +00:00
|
|
|
#include <string>
|
2024-04-28 15:07:47 +00:00
|
|
|
#include <sstream>
|
2024-04-28 10:32:48 +00:00
|
|
|
#include <vector>
|
2024-04-28 10:01:50 +00:00
|
|
|
|
2024-04-28 11:03:20 +00:00
|
|
|
#include "pcg_random.hpp"
|
2024-04-28 15:07:47 +00:00
|
|
|
#include "eff_large_wordlist.txt.hpp"
|
|
|
|
#include "eff_short_wordlist_1.txt.hpp"
|
2024-04-28 11:03:20 +00:00
|
|
|
|
2024-04-28 15:07:47 +00:00
|
|
|
enum WordlistType { WORDLIST_EFF_LARGE, WORDLIST_EFF_SHORT, WORDLIST_CUSTOM };
|
|
|
|
|
|
|
|
struct PassgenOptions {
|
|
|
|
bool help = false;
|
2024-04-28 15:17:10 +00:00
|
|
|
WordlistType wordlist_type = WORDLIST_EFF_SHORT;
|
2024-04-28 15:07:47 +00:00
|
|
|
int wordcount = 5;
|
|
|
|
bool camelcase = false;
|
|
|
|
std::string seperator = "-";
|
|
|
|
std::optional<std::string> wordlist_path;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef std::function<void(PassgenOptions&)> NoArgHandle;
|
|
|
|
typedef std::function<void(PassgenOptions&, const std::string&)> OneArgHandle;
|
|
|
|
|
|
|
|
const std::unordered_map<std::string, NoArgHandle> NoArgs {
|
|
|
|
{"-h", [](PassgenOptions& s) { s.help = true; }},
|
|
|
|
{"--help", [](PassgenOptions& s) { s.help = true; }},
|
|
|
|
|
|
|
|
{"-s", [](PassgenOptions& s) { s.wordlist_type = WORDLIST_EFF_SHORT; }},
|
|
|
|
{"--short", [](PassgenOptions& s) { s.wordlist_type = WORDLIST_EFF_SHORT; }},
|
|
|
|
|
|
|
|
{"-l", [](PassgenOptions& s) { s.wordlist_type = WORDLIST_EFF_LARGE; }},
|
|
|
|
{"--large", [](PassgenOptions& s) { s.wordlist_type = WORDLIST_EFF_LARGE; }},
|
|
|
|
|
|
|
|
{"--camelcase", [](PassgenOptions& s) { s.camelcase = true; }},
|
|
|
|
{"-cc", [](PassgenOptions& s) { s.camelcase = true; }},
|
|
|
|
};
|
|
|
|
|
|
|
|
const std::unordered_map<std::string, OneArgHandle> OneArgs {
|
2024-04-28 17:04:57 +00:00
|
|
|
{"-wl", [](PassgenOptions& s, const std::string& arg) {
|
2024-04-28 15:07:47 +00:00
|
|
|
s.wordlist_path = arg;
|
|
|
|
s.wordlist_type = WORDLIST_CUSTOM;
|
|
|
|
}},
|
2024-04-28 17:04:57 +00:00
|
|
|
{"--wordlist", [](PassgenOptions& s, const std::string& arg) {
|
2024-04-28 15:07:47 +00:00
|
|
|
s.wordlist_path = arg;
|
|
|
|
s.wordlist_type = WORDLIST_CUSTOM;
|
|
|
|
}},
|
|
|
|
{"-wc", [](PassgenOptions& s, const std::string& arg) {
|
|
|
|
s.wordcount = std::stoi(arg);
|
|
|
|
}},
|
|
|
|
{"--wordcount", [](PassgenOptions& s, const std::string& arg) {
|
|
|
|
s.wordcount = std::stoi(arg);
|
|
|
|
}},
|
|
|
|
{"--seperator", [](PassgenOptions& s, const std::string& arg) {
|
|
|
|
s.seperator = arg;
|
|
|
|
}},
|
|
|
|
};
|
|
|
|
|
|
|
|
PassgenOptions parse_options(int argc, const char* argv[]) {
|
|
|
|
PassgenOptions settings;
|
|
|
|
|
|
|
|
for(int i = 1; i < argc; i++) {
|
|
|
|
std::string opt = argv[i];
|
|
|
|
|
|
|
|
if (auto j = NoArgs.find(opt); j != NoArgs.end()) {
|
|
|
|
j->second(settings);
|
|
|
|
} else if(auto k = OneArgs.find(opt); k != OneArgs.end()) {
|
|
|
|
if(++i < argc) {
|
|
|
|
k->second(settings, {argv[i]});
|
|
|
|
} else {
|
|
|
|
throw std::runtime_error {"missing param after " + opt};
|
2024-04-28 15:17:10 +00:00
|
|
|
std::exit(1);
|
2024-04-28 15:07:47 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
std::cerr << "unrecognized command-line option " << opt << std::endl;
|
2024-04-28 15:17:10 +00:00
|
|
|
std::exit(1);
|
2024-04-28 15:07:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return settings;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> getWordlist(PassgenOptions opts)
|
2024-04-28 10:32:48 +00:00
|
|
|
{
|
|
|
|
std::vector<std::string> map;
|
|
|
|
|
2024-04-28 15:17:10 +00:00
|
|
|
if (opts.wordlist_type != WORDLIST_CUSTOM)
|
2024-04-28 15:07:47 +00:00
|
|
|
{
|
|
|
|
std::stringstream ss;
|
2024-04-28 17:04:57 +00:00
|
|
|
if (opts.wordlist_type == WORDLIST_EFF_SHORT) {
|
2024-04-28 15:17:10 +00:00
|
|
|
ss.write(reinterpret_cast<const char*>(eff_short_wordlist_1_txt), eff_short_wordlist_1_txt_len);
|
|
|
|
} else {
|
|
|
|
ss.write(reinterpret_cast<const char*>(eff_large_wordlist_txt), eff_large_wordlist_txt_len);
|
2024-04-28 10:32:48 +00:00
|
|
|
}
|
2024-04-28 15:07:47 +00:00
|
|
|
std::string line;
|
|
|
|
while (std::getline(ss, line)) {
|
|
|
|
map.push_back(line);
|
|
|
|
}
|
|
|
|
}
|
2024-04-28 15:17:10 +00:00
|
|
|
else if (opts.wordlist_path.has_value())
|
2024-04-28 15:07:47 +00:00
|
|
|
{
|
|
|
|
std::string path = opts.wordlist_path.value();
|
|
|
|
std::ifstream file(path);
|
|
|
|
if (file.is_open()) {
|
|
|
|
std::string line;
|
|
|
|
while (std::getline(file, line)) {
|
|
|
|
map.push_back(line);
|
|
|
|
}
|
|
|
|
} else {
|
2024-04-28 15:17:10 +00:00
|
|
|
std::cout << "ERROR: failed to open '" << path << "'" << std::endl;
|
2024-04-28 15:07:47 +00:00
|
|
|
}
|
2024-04-28 15:17:10 +00:00
|
|
|
} else {
|
|
|
|
std::cout << "ERROR: no wordlist specified" << std::endl;
|
2024-04-28 10:32:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return map;
|
|
|
|
}
|
|
|
|
|
2024-04-28 15:07:47 +00:00
|
|
|
int main(int argc, const char *argv[]) {
|
|
|
|
PassgenOptions opts = parse_options(argc, argv);
|
|
|
|
|
|
|
|
if (opts.help) {
|
|
|
|
std::cout << R"(
|
|
|
|
Usage: passgen [options]
|
|
|
|
|
|
|
|
Options:
|
|
|
|
-h, --help Display this help message and exit
|
2024-04-28 15:17:10 +00:00
|
|
|
-s, --short Use the short EFF wordlist (dfault)
|
|
|
|
-l, --large Use the large EFF wordlist
|
2024-04-28 15:07:47 +00:00
|
|
|
--camelcase, -cc Generate passphrase in CamelCase format
|
2024-04-28 17:04:57 +00:00
|
|
|
-wl <path>, --wordlist <path>
|
2024-04-28 15:07:47 +00:00
|
|
|
Use a custom wordlist file located at <path>
|
|
|
|
-wc <count>, --wordcount <count>
|
2024-04-28 15:17:10 +00:00
|
|
|
Amount of words to use for passphrase, default = 5
|
2024-04-28 15:07:47 +00:00
|
|
|
--separator <seperator> Specify a character to use as a separator between words, default = `-`
|
|
|
|
|
|
|
|
Description:
|
|
|
|
Generate passphrases based on wordlists.
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
passgen -h
|
|
|
|
passgen --short 4
|
2024-04-28 17:04:57 +00:00
|
|
|
passgen -wl /path/to/custom_wordlist.txt --wordcount 4
|
2024-04-28 15:07:47 +00:00
|
|
|
)";
|
|
|
|
return 0;
|
2024-04-28 10:32:48 +00:00
|
|
|
}
|
|
|
|
|
2024-04-28 15:07:47 +00:00
|
|
|
std::vector<std::string> wordlist = getWordlist(opts);
|
2024-04-28 10:32:48 +00:00
|
|
|
|
|
|
|
if (wordlist.size() == 0) {
|
2024-04-28 15:07:47 +00:00
|
|
|
std::cerr << "Wordlist is empty";
|
2024-04-28 10:32:48 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2024-04-28 12:02:45 +00:00
|
|
|
pcg_extras::seed_seq_from<std::random_device> seed_source;
|
|
|
|
pcg32 rng(seed_source);
|
|
|
|
|
2024-04-28 15:07:47 +00:00
|
|
|
for (int i = 0; i < opts.wordcount; i++) {
|
2024-04-28 11:53:52 +00:00
|
|
|
int random_int = std::uniform_int_distribution<int>(0, wordlist.size())(rng);
|
|
|
|
|
2024-04-28 15:07:47 +00:00
|
|
|
if (opts.camelcase) {
|
|
|
|
wordlist[random_int][0] = toupper(wordlist[random_int][0]);
|
|
|
|
}
|
2024-04-28 11:53:52 +00:00
|
|
|
std::cout << wordlist[random_int];
|
|
|
|
|
2024-04-28 15:07:47 +00:00
|
|
|
if (i+1 == opts.wordcount) {
|
2024-04-28 11:53:52 +00:00
|
|
|
std::cout << "\n";
|
|
|
|
} else {
|
2024-04-28 15:07:47 +00:00
|
|
|
std::cout << opts.seperator;
|
2024-04-28 11:53:52 +00:00
|
|
|
}
|
|
|
|
}
|
2024-04-28 10:01:50 +00:00
|
|
|
}
|