-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathpassword_generator.cpp
107 lines (91 loc) · 3.93 KB
/
password_generator.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/*!
\file password_generator.cpp
\brief Password generator implementation
\author Ivan Shynkarenka
\date 10.06.2019
\copyright MIT License
*/
#include "security/password_generator.h"
#include "errors/exceptions.h"
#include "memory/memory.h"
#include "utility/countof.h"
#include <cassert>
namespace CppSecurity {
PasswordGenerator::PasswordGenerator(size_t length, PasswordFlags flags)
: _length(length), _flags(flags)
{
assert((length >= 6) && "Password should be at least 6 bytes!");
if (length < 6)
throwex CppCommon::SecurityException("Invalid password length!");
}
std::password PasswordGenerator::Generate() const
{
char lower[] = "abcdefghijklmnopqrstuvwxyz";
char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char digits[] = "012345678901234567890123456789";
char symbols[] = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
std::string cache;
if ((flags() & PasswordFlags::lower) != 0)
cache += lower;
if ((flags() & PasswordFlags::upper) != 0)
cache += upper;
if ((flags() & PasswordFlags::digits) != 0)
cache += digits;
if ((flags() & PasswordFlags::symbols) != 0)
cache += symbols;
size_t offset = 0;
std::password result(length(), 0);
CppCommon::Memory::CryptoFill(result.data(), result.size());
if ((flags() & PasswordFlags::lower) != 0)
result[offset] = lower[result[offset] % (CppCommon::countof(lower) - 1)], ++offset;
if ((flags() & PasswordFlags::upper) != 0)
result[offset] = upper[result[offset] % (CppCommon::countof(upper) - 1)], ++offset;
if ((flags() & PasswordFlags::digits) != 0)
result[offset] = digits[result[offset] % (CppCommon::countof(digits) - 1)], ++offset;
if ((flags() & PasswordFlags::symbols) != 0)
result[offset] = symbols[result[offset] % (CppCommon::countof(symbols) - 1)], ++offset;
for (size_t i = offset; i < length(); ++i)
result[i] = cache[result[i] % cache.size()];
return result;
}
bool PasswordGenerator::Validate(std::string_view password) const
{
// Validate password length requirement
if (password.size() < length())
return false;
// Collect password flags requirements
bool lower = false;
bool upper = false;
bool digits = false;
bool symbols = false;
for (size_t i = 0; i < password.size(); ++i)
{
if ((password[i] >= 'a') && (password[i] <= 'z'))
lower = true;
else if ((password[i] >= 'A') && (password[i] <= 'Z'))
upper = true;
else if ((password[i] >= '0') && (password[i] <= '9'))
digits = true;
else if ((password[i] == '!') || (password[i] == '"') || (password[i] == '#') || (password[i] == '$') || (password[i] == '%') ||
(password[i] == '&') || (password[i] == '\'') || (password[i] == '(') || (password[i] == ')') || (password[i] == '*') ||
(password[i] == '+') ||(password[i] == ',') || (password[i] == '-') || (password[i] == '.') || (password[i] == '/') ||
(password[i] == ':') || (password[i] == ';') || (password[i] == '<') || (password[i] == '=') || (password[i] == '>') ||
(password[i] == '?') || (password[i] == '@') || (password[i] == '[') || (password[i] == '\\') || (password[i] == ']') ||
(password[i] == '^') || (password[i] == '_') || (password[i] == '`') || (password[i] == '{') || (password[i] == '|') ||
(password[i] == '}') || (password[i] == '~'))
symbols = true;
else
return false;
}
// Validate password flags requirements
if (!lower && ((flags() & PasswordFlags::lower) != 0))
return false;
if (!upper && ((flags() & PasswordFlags::upper) != 0))
return false;
if (!digits && ((flags() & PasswordFlags::digits) != 0))
return false;
if (!symbols && ((flags() & PasswordFlags::symbols) != 0))
return false;
return true;
}
} // namespace CppSecurity