I've designed a Password Generator for review. It takes the minimum length and adds 25% to produce a minimum and maximum length. My thought is to introduce a slight random variance in the length.
I used the Mersenne Twist 19937 64 bit generator, mt19937_64
and the uniform_int_distribution
. Instead of creating a new uniform_int_distribution
object for each range that I'll be using, my thought was to use a range that will be a multiple of all the ranges I'll be using. This way a modulus operation using the specific range size should still produce evenly distributed numbers.
Header
#include <string>
#include <vector>
#include <random>
using std::string;
using std::vector;
using std::mt19937_64;
using std::uniform_int_distribution;
using std::istream;
class PasswordGenerator
{
const static size_t MIN_LENGTH = 8;
const static double MAX_LENGTH_OFFSET;
vector<string> stringsSets =
{
"abccefghijklmnopqrstuvwxyz",
"ABCDEFJHIJKLMNOPQRSTUVWXYZ",
"0123456789",
"`~!@#$%^&*()_+-=[]{}\\|;':\",./<>?"
};
enum Options
{
NONE = 0,
UPPER = 1,
LOWER = 2,
DIGIT = 4,
PUNCTUATION = 8
};
Options usage = NONE;
double minLen = MIN_LENGTH;
double maxLen = MIN_LENGTH * (MAX_LENGTH_OFFSET + 1);
int numOptions = 0;
size_t maxRange = 1;
void CalcMaxRange();
void AddRange(const size_t);
string MakeSubstring(string*, size_t, uniform_int_distribution<int>&, mt19937_64&);
public:
PasswordGenerator(size_t minLength, bool lower, bool upper, bool digit, bool punct);
PasswordGenerator();
~PasswordGenerator();
string Generate();
};`
Body
#include "PasswordGenerator.h"
#include <cmath>
#include <functional>
#include <sstream>
#include <algorithm>
using std::bind;
using std::stringstream;
using std::random_shuffle;
using std::random_device;
using std::pow;
const double PasswordGenerator::MAX_LENGTH_OFFSET = .25;
void PasswordGenerator::CalcMaxRange()
{
maxRange = stringsSets.size();
for (auto s : stringsSets)
{
size_t rangeTemp = s.size();
AddRange(rangeTemp);
}
return;
}
void PasswordGenerator::AddRange(const size_t range)
{
if ( range != 0 && maxRange % range != 0)
{
maxRange *= range;
}
}
PasswordGenerator::PasswordGenerator(size_t minLength = MIN_LENGTH, bool lower = true, bool upper = true, bool digit = true, bool punct = true)
{
CalcMaxRange();
if (minLength > MIN_LENGTH)
{
minLen = minLength;
maxLen = minLength * (1 + MAX_LENGTH_OFFSET);
}
if (lower)
{
usage = (Options)(usage | LOWER);
numOptions++;
}
if (upper)
{
usage = (Options)(usage | UPPER);
numOptions++;
}
if (digit)
{
usage = (Options)(usage | DIGIT);
numOptions++;
}
if (punct)
{
usage = (Options)(usage | PUNCTUATION);
numOptions++;
}
}
PasswordGenerator::PasswordGenerator()
{
CalcMaxRange();
usage = (Options)(UPPER | LOWER | DIGIT | PUNCTUATION);
numOptions = 4;
}
PasswordGenerator::~PasswordGenerator()
{
}
string PasswordGenerator::Generate()
{
int subLimit = ceil(maxLen / numOptions);
AddRange(subLimit);
random_device rd;
mt19937_64 mt64{ rd() };
uniform_int_distribution<int> dist(0, maxRange);
auto rnd = bind(dist, mt64);
stringstream ss;
size_t stringsSize = stringsSets.size();
int start = rnd() % stringsSize;
size_t limit = stringsSize + start;
for (int i = start; i < limit; i++)
{
Options tempOption = (Options)(int)pow(2, i % stringsSize);
bool allowed = usage & tempOption;
if (allowed)
{
string* temp = &stringsSets[i % stringsSize];
ss << MakeSubstring(temp, rnd() % subLimit, dist, mt64);
}
}
size_t currSize = ss.str().size();
if (currSize < minLen)
{
size_t limitTemp = (maxLen - currSize) + (rnd() % (int)(maxLen - minLen));
for (int i = 0; i < limitTemp; i++)
{
Options tempOption = NONE;
bool allowed = false;
while (!allowed)
{
size_t index = rnd() % stringsSize;
tempOption = (Options)(int)pow(2, index);
allowed = usage & tempOption;
if (allowed)
{
string* tempString = &stringsSets[index];
ss << (*tempString)[rnd() % (*tempString).size()];
}
}
}
}
string retVal = ss.str();
random_shuffle(retVal.begin(), retVal.end());
return retVal;
}
string PasswordGenerator::MakeSubstring(string* chars, size_t length, uniform_int_distribution<int>& dist, mt19937_64& mt64)
{
auto rnd = bind(dist, mt64);
string retVal = string(length, '\0');
size_t stringSize = (*chars).size();
for (size_t i = 0; i < length; i++)
{
retVal[i] = (*chars)[rnd() % stringSize];
}
return retVal;
}
Options
intentionally misaligned withstringsSets
(upper/lower interchanged)? \$\endgroup\$