https://github.com/itmm/pwg
pwg.cpp
// includes
// globals
int main(int argc, char *argv[]) {
{
// unit-tests
}
// main
}
main
function runs all
unit-tests// ...
// main
// state
// process args
// generate
// ...
main
function initializes the state object and processes
command line argumentsmain
function processes next// ...
// includes
#include <string>
#include <iostream>
// ...
<string>
header for the std::string
class<iostream>
to write them// ...
// generate
std::string pw;
// generate pw
std::cout << pw << '\n';
// ...
pw
// ...
// state
int upper_count = 3;
std::string upper_set { "ABCDEFGHJKLMNPQRSTUVWXYZ" };
// ...
pwg
generates a password from different character groupsstd::string
with all characters in this group// ...
// includes
#include <random>
// ...
<random>
header from C++ is used to generate random numbers// ...
// globals
using Uniform = std::uniform_int_distribution<int>;
template<typename RE> std::string random_select(
const std::string &source,
int count, RE &re
) {
std::string result;
// random select
return result;
}
// ...
random_select
chooses a number of random characters
from a given set// ...
// unit-tests
using TestEngine = std::linear_congruential_engine<
unsigned, 1, 0, 0x7ff
>;
// unit-tests 2
// ...
pwg
uses a simple random engine that will always
return 0
// ...
// includes
#include <exception>
// ...
// ...
// unit-tests 2
{
TestEngine te { 0 };
if (random_select("abc", 4, te) != "aaaa") {
throw std::logic_error("random select");
}
}
// ...
random_select
will always
return the first character the expected number of times// ...
// random select
int max = source.size() - 1;
if (max < 0) {
throw std::invalid_argument("no chars");
}
Uniform d { 0, max };
for (int i = 0; i < count; ++i) {
result += source[d(re)];
}
// ...
random_select
expects that the character set is not empty// ...
// state
auto seed { (std::random_device {})() };
// ...
pwg
generates a random seedseed
with a command line argument to
generate deterministic resultsstd::random_device
can be time consuming to
pwg
uses a Mersenne Twister algorithm instead// ...
// generate pw
std::mt19937 re { seed };
// generate pw 2
// ...
pwg
initialises the Mersenne Twister with the seed value// ...
// generate pw 2
pw += random_select(upper_set, upper_count, re);
// generate pw 3
// ...
pwg
chooses the specified number of upper case letters// ...
// state
int lower_count = 3;
std::string lower_set { "abcdefghijkmnopqrstuvwxyz" };
// ...
pwg
also specifies a default count and
character set// ...
// generate pw 3
pw += random_select(
lower_set, lower_count, re
);
// generate pw 4
// ...
pwg
chooses the specified number of upper case letterspwg
must shuffle the resulting string to generate a stronger
password// ...
// includes
#include <algorithm>
// ...
// ...
// generate pw 4
std::shuffle(pw.begin(), pw.end(), re);
// ...
main
function uses random_shuffle
to perturbate the
letters from the different categories// ...
// state
int digit_count = 2;
std::string digit_set { "23456789" };
// ...
// ...
// generate pw 3
pw += random_select(digit_set, digit_count, re);
// ...
pwg
chooses random digits and adds them to the password before
performing the permutation// ...
// state
int special_count = 2;
std::string special_set { ".,:;!?+-*/[](){}" };
// ...
// ...
// generate pw 3
pw += random_select(
special_set, special_count, re
);
// ...
pwg
chooses random special characters and adds them to the password
before performing the permutation// ...
// globals
int to_int(const std::string &s, int d) {
try {
d = std::stoi(s);
}
catch (...) {
// to int err msg
}
return d;
}
// ...
to_int
can cope with cases that the provided string cannot be
converted to an integer// ...
// to int err msg
std::cerr << "Can't convert `" <<
s << "` to integer; " <<
"will use " << d <<
" instead.\n";
// ...
to_int
prints this error message, if the string cannot be
converted to an integer// ...
// process args
if (argc > 1) {
upper_count = to_int(
argv[1], upper_count
);
}
// ...
// ...
// process args
if (argc > 2) {
lower_count = to_int(
argv[2], lower_count
);
}
// ...
// ...
// process args
if (argc > 3) {
digit_count = to_int(
argv[3], digit_count
);
}
// ...
// ...
// process args
if (argc > 4) {
special_count = to_int(
argv[4], special_count
);
}
// ...
// ...
// process args
if (argc > 5) {
std::string s { argv[5] };
if (s.size()) {
special_set = argv[5];
} else {
std::cerr << "Specials are "
"empty; will use `" <<
special_set <<
"` instead.\n";
}
}
// ...
// ...
// process args
if (argc > 6) {
seed = to_int(argv[6], seed);
}
// ...
pwg
will show deterministic behaviour