keepassxc

Форк
0
/
PasswordGenerator.cpp 
338 строк · 8.4 Кб
1
/*
2
 *  Copyright (C) 2013 Felix Geyer <debfx@fobos.de>
3
 *  Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
4
 *
5
 *  This program is free software: you can redistribute it and/or modify
6
 *  it under the terms of the GNU General Public License as published by
7
 *  the Free Software Foundation, either version 2 or (at your option)
8
 *  version 3 of the License.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU General Public License
16
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18

19
#include "PasswordGenerator.h"
20

21
#include "crypto/Random.h"
22

23
const int PasswordGenerator::DefaultLength = 32;
24
const char* PasswordGenerator::DefaultCustomCharacterSet = "";
25
const char* PasswordGenerator::DefaultExcludedChars = "";
26

27
PasswordGenerator::PasswordGenerator()
28
    : m_length(PasswordGenerator::DefaultLength)
29
    , m_classes(PasswordGenerator::CharClass::DefaultCharset)
30
    , m_flags(PasswordGenerator::GeneratorFlag::DefaultFlags)
31
    , m_custom(PasswordGenerator::DefaultCustomCharacterSet)
32
    , m_excluded(PasswordGenerator::DefaultExcludedChars)
33
{
34
}
35

36
void PasswordGenerator::setLength(int length)
37
{
38
    m_length = length;
39
}
40

41
void PasswordGenerator::setCharClasses(const PasswordGenerator::CharClasses& classes)
42
{
43
    m_classes = classes;
44
}
45

46
void PasswordGenerator::setCustomCharacterSet(const QString& customCharacterSet)
47
{
48
    m_custom = customCharacterSet;
49
}
50
void PasswordGenerator::setExcludedCharacterSet(const QString& excludedCharacterSet)
51
{
52
    m_excluded = excludedCharacterSet;
53
}
54

55
void PasswordGenerator::setFlags(const GeneratorFlags& flags)
56
{
57
    m_flags = flags;
58
}
59

60
QString PasswordGenerator::generatePassword() const
61
{
62
    Q_ASSERT(isValid());
63

64
    const QVector<PasswordGroup> groups = passwordGroups();
65

66
    QVector<QChar> passwordChars;
67
    for (const PasswordGroup& group : groups) {
68
        for (QChar ch : group) {
69
            passwordChars.append(ch);
70
        }
71
    }
72

73
    QString password;
74

75
    if (m_flags & CharFromEveryGroup) {
76
        for (const auto& group : groups) {
77
            int pos = randomGen()->randomUInt(static_cast<quint32>(group.size()));
78

79
            password.append(group[pos]);
80
        }
81

82
        for (int i = groups.size(); i < m_length; i++) {
83
            int pos = randomGen()->randomUInt(static_cast<quint32>(passwordChars.size()));
84

85
            password.append(passwordChars[pos]);
86
        }
87

88
        // shuffle chars
89
        for (int i = (password.size() - 1); i >= 1; i--) {
90
            int j = randomGen()->randomUInt(static_cast<quint32>(i + 1));
91

92
            QChar tmp = password[i];
93
            password[i] = password[j];
94
            password[j] = tmp;
95
        }
96
    } else {
97
        for (int i = 0; i < m_length; i++) {
98
            int pos = randomGen()->randomUInt(static_cast<quint32>(passwordChars.size()));
99

100
            password.append(passwordChars[pos]);
101
        }
102
    }
103

104
    return password;
105
}
106

107
bool PasswordGenerator::isValid() const
108
{
109
    if (m_classes == CharClass::NoClass && m_custom.isEmpty()) {
110
        return false;
111
    } else if (m_length <= 0) {
112
        return false;
113
    }
114

115
    if ((m_flags & CharFromEveryGroup) && (m_length < numCharClasses())) {
116
        return false;
117
    }
118

119
    return !passwordGroups().isEmpty();
120
}
121

122
QVector<PasswordGroup> PasswordGenerator::passwordGroups() const
123
{
124
    QVector<PasswordGroup> passwordGroups;
125

126
    if (m_classes & LowerLetters) {
127
        PasswordGroup group;
128

129
        for (int i = 97; i <= (97 + 25); i++) {
130

131
            if ((m_flags & ExcludeLookAlike) && (i == 108)) { // "l"
132
                continue;
133
            }
134

135
            group.append(i);
136
        }
137

138
        passwordGroups.append(group);
139
    }
140
    if (m_classes & UpperLetters) {
141
        PasswordGroup group;
142

143
        for (int i = 65; i <= (65 + 25); i++) {
144

145
            if ((m_flags & ExcludeLookAlike) && (i == 66 || i == 71 || i == 73 || i == 79)) { //"B", "G", "I" and "O"
146
                continue;
147
            }
148

149
            group.append(i);
150
        }
151

152
        passwordGroups.append(group);
153
    }
154
    if (m_classes & Numbers) {
155
        PasswordGroup group;
156

157
        for (int i = 48; i < (48 + 10); i++) {
158
            if ((m_flags & ExcludeLookAlike) && (i == 48 || i == 49 || i == 54 || i == 56)) { // "0", "1", "6", and "8"
159
                continue;
160
            }
161

162
            group.append(i);
163
        }
164

165
        passwordGroups.append(group);
166
    }
167
    if (m_classes & Braces) {
168
        PasswordGroup group;
169

170
        // ()[]{}
171
        group.append(40);
172
        group.append(41);
173
        group.append(91);
174
        group.append(93);
175
        group.append(123);
176
        group.append(125);
177

178
        passwordGroups.append(group);
179
    }
180
    if (m_classes & Punctuation) {
181
        PasswordGroup group;
182

183
        // .,:;
184
        group.append(44);
185
        group.append(46);
186
        group.append(58);
187
        group.append(59);
188

189
        passwordGroups.append(group);
190
    }
191
    if (m_classes & Quotes) {
192
        PasswordGroup group;
193

194
        // "'
195
        group.append(34);
196
        group.append(39);
197

198
        passwordGroups.append(group);
199
    }
200
    if (m_classes & Dashes) {
201
        PasswordGroup group;
202

203
        // -/\_|
204
        group.append(45);
205
        group.append(47);
206
        group.append(92);
207
        group.append(95);
208
        if (!(m_flags & ExcludeLookAlike)) {
209
            group.append(124); // "|"
210
        }
211

212
        passwordGroups.append(group);
213
    }
214
    if (m_classes & Math) {
215
        PasswordGroup group;
216

217
        // !*+<=>?
218
        group.append(33);
219
        group.append(42);
220
        group.append(43);
221
        group.append(60);
222
        group.append(61);
223
        group.append(62);
224
        group.append(63);
225

226
        passwordGroups.append(group);
227
    }
228
    if (m_classes & Logograms) {
229
        PasswordGroup group;
230

231
        // #$%&
232
        for (int i = 35; i <= 38; i++) {
233
            group.append(i);
234
        }
235
        // @^`~
236
        group.append(64);
237
        group.append(94);
238
        group.append(96);
239
        group.append(126);
240

241
        passwordGroups.append(group);
242
    }
243
    if (m_classes & EASCII) {
244
        PasswordGroup group;
245

246
        // [U+0080, U+009F] are C1 control characters,
247
        // U+00A0 is non-breaking space
248
        for (int i = 161; i <= 172; i++) {
249
            group.append(i);
250
        }
251
        // U+00AD is soft hyphen (format character)
252
        for (int i = 174; i <= 255; i++) {
253
            if ((m_flags & ExcludeLookAlike) && (i == 249)) { // "﹒"
254
                continue;
255
            }
256
            group.append(i);
257
        }
258

259
        passwordGroups.append(group);
260
    }
261
    if (!m_custom.isEmpty()) {
262
        PasswordGroup group;
263

264
        for (const auto& ch : m_custom) {
265
            if (!group.contains(ch)) {
266
                group.append(ch);
267
            }
268
        }
269

270
        passwordGroups.append(group);
271
    }
272

273
    // Loop over character groups and remove excluded characters from them;
274
    // remove empty groups
275
    int i = 0;
276
    while (i != passwordGroups.size()) {
277
        PasswordGroup group = passwordGroups[i];
278

279
        for (QChar ch : m_excluded) {
280
            int j = group.indexOf(ch);
281
            while (j != -1) {
282
                group.remove(j);
283
                j = group.indexOf(ch);
284
            }
285
        }
286
        if (!group.isEmpty()) {
287
            passwordGroups.replace(i, group);
288
            ++i;
289
        } else {
290
            passwordGroups.remove(i);
291
        }
292
    }
293

294
    return passwordGroups;
295
}
296

297
int PasswordGenerator::numCharClasses() const
298
{
299
    // Actually compute the non empty password groups
300
    auto non_empty_groups = passwordGroups();
301
    return non_empty_groups.size();
302
}
303

304
int PasswordGenerator::getMinLength() const
305
{
306
    if ((m_flags & CharFromEveryGroup)) {
307
        return numCharClasses();
308
    }
309
    return 1;
310
}
311
void PasswordGenerator::reset()
312
{
313
    m_classes = CharClass::DefaultCharset;
314
    m_flags = GeneratorFlag::DefaultFlags;
315
    m_custom = DefaultCustomCharacterSet;
316
    m_excluded = DefaultExcludedChars;
317
    m_length = DefaultLength;
318
}
319
int PasswordGenerator::getLength() const
320
{
321
    return m_length;
322
}
323
const PasswordGenerator::GeneratorFlags& PasswordGenerator::getFlags() const
324
{
325
    return m_flags;
326
}
327
const PasswordGenerator::CharClasses& PasswordGenerator::getActiveClasses() const
328
{
329
    return m_classes;
330
}
331
const QString& PasswordGenerator::getCustomCharacterSet() const
332
{
333
    return m_custom;
334
}
335
const QString& PasswordGenerator::getExcludedCharacterSet() const
336
{
337
    return m_excluded;
338
}
339

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.