Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(152)

Side by Side Diff: components/autofill/core/browser/password_generator.cc

Issue 308503002: [Password Generation] Start using pronouncable passwords (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: unnecessary includes Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/autofill/core/browser/password_generator.h" 5 #include "components/autofill/core/browser/password_generator.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/basictypes.h" 10 #include "base/basictypes.h"
11 #include "base/logging.h"
12 #include "base/rand_util.h" 11 #include "base/rand_util.h"
12 #include "base/strings/string_util.h"
13 #include "third_party/fips181/fips181.h"
13 14
14 const int kMinUpper = 65; // First upper case letter 'A' 15 const int kMinUpper = 65; // First upper case letter 'A'
15 const int kMaxUpper = 90; // Last upper case letter 'Z' 16 const int kMaxUpper = 90; // Last upper case letter 'Z'
16 const int kMinLower = 97; // First lower case letter 'a' 17 const int kMinLower = 97; // First lower case letter 'a'
17 const int kMaxLower = 122; // Last lower case letter 'z' 18 const int kMaxLower = 122; // Last lower case letter 'z'
18 const int kMinDigit = 48; // First digit '0' 19 const int kMinDigit = 48; // First digit '0'
19 const int kMaxDigit = 57; // Last digit '9' 20 const int kMaxDigit = 57; // Last digit '9'
20 // Copy of the other printable symbols from the ASCII table since they are
21 // disjointed.
22 const char kOtherSymbols[] =
23 {'!', '\"', '#', '$', '%', '&', '\'', '(',
24 ')', '*', '+', ',', '-', '.', '/', ':',
25 ';', '<', '=', '>', '?', '@', '[', '\\',
26 ']', '^', '_', '`', '{', '|', '}', '~'};
27 const int kMinPasswordLength = 4; 21 const int kMinPasswordLength = 4;
28 const int kMaxPasswordLength = 15; 22 const int kMaxPasswordLength = 15;
29 23
30 namespace { 24 namespace {
31 25
32 // A helper function to get the length of the generated password from 26 // A helper function to get the length of the generated password from
33 // |max_length| retrieved from input password field. 27 // |max_length| retrieved from input password field.
34 int GetLengthFromHint(int max_length, int default_length) { 28 int GetLengthFromHint(int max_length, int default_length) {
35 if (max_length >= kMinPasswordLength && max_length <= kMaxPasswordLength) 29 if (max_length >= kMinPasswordLength && max_length <= kMaxPasswordLength)
36 return max_length; 30 return max_length;
37 else 31 else
38 return default_length; 32 return default_length;
39 } 33 }
40 34
41 void InitializeAlphaNumericCharacters(std::vector<char>* characters) { 35 // We want the password to have uppercase, lowercase, and at least one number.
42 for (int i = kMinDigit; i <= kMaxDigit; ++i) 36 bool VerifyPassword(const std::string& password) {
43 characters->push_back(static_cast<char>(i)); 37 int num_lower_case = 0;
44 for (int i = kMinUpper; i <= kMaxUpper; ++i) 38 int num_upper_case = 0;
45 characters->push_back(static_cast<char>(i)); 39 int num_digits = 0;
46 for (int i = kMinLower; i <= kMaxLower; ++i) 40
47 characters->push_back(static_cast<char>(i)); 41 for (size_t i = 0; i < password.size(); ++i) {
42 if (password[i] >= kMinUpper && password[i] <= kMaxUpper)
43 ++num_upper_case;
44 if (password[i] >= kMinLower && password[i] <= kMaxLower)
45 ++num_lower_case;
46 if (password[i] >= kMinDigit && password[i] <= kMaxDigit)
47 ++num_digits;
48 }
49
50 return num_lower_case && num_upper_case && num_digits;
48 } 51 }
49 52
50 // Classic algorithm to randomly select |num_select| elements out of 53 // Make sure that there is at least one upper case and one number in the
51 // |num_total| elements. One description can be found at: 54 // password. Assume that there already exists a lower case letter as it's the
52 // "http://stackoverflow.com/questions/48087/select-a-random-n-elements-from-lis tt-in-c-sharp/48089#48089" 55 // default from gen_pron_pass.
53 void GetRandomSelection(int num_to_select, 56 void ForceFixPassword(std::string* password) {
54 int num_total, 57 for (std::string::iterator iter = password->begin();
55 std::vector<int>* selections) { 58 iter != password->end(); ++iter) {
56 DCHECK_GE(num_total, num_to_select); 59 if (islower(*iter)) {
57 int num_left = num_total; 60 *iter = base::ToUpperASCII(*iter);
58 int num_needed = num_to_select; 61 break;
59 for (int i = 0; i < num_total && num_needed > 0; ++i) {
60 // we have probability = |num_needed| / |num_left| to select
61 // this position.
62 int probability = base::RandInt(0, num_left - 1);
63 if (probability < num_needed) {
64 selections->push_back(i);
65 --num_needed;
66 } 62 }
67 --num_left;
68 } 63 }
69 DCHECK_EQ(num_to_select, static_cast<int>(selections->size())); 64 for (std::string::reverse_iterator iter = password->rbegin();
65 iter != password->rend(); ++iter) {
66 if (islower(*iter)) {
67 *iter = base::RandInt(kMinDigit, kMaxDigit);
68 break;
69 }
70 }
70 } 71 }
71 72
72 } // namespace 73 } // namespace
73 74
74 namespace autofill { 75 namespace autofill {
75 76
76 const int PasswordGenerator::kDefaultPasswordLength = 12; 77 const int PasswordGenerator::kDefaultPasswordLength = 12;
77 78
78 PasswordGenerator::PasswordGenerator(int max_length) 79 PasswordGenerator::PasswordGenerator(int max_length)
79 : password_length_(GetLengthFromHint(max_length, kDefaultPasswordLength)) {} 80 : password_length_(GetLengthFromHint(max_length, kDefaultPasswordLength)) {}
80 PasswordGenerator::~PasswordGenerator() {} 81 PasswordGenerator::~PasswordGenerator() {}
81 82
82 std::string PasswordGenerator::Generate() const { 83 std::string PasswordGenerator::Generate() const {
83 std::string ret; 84 char password[255];
84 CR_DEFINE_STATIC_LOCAL(std::vector<char>, alphanumeric_characters, ()); 85 char unused_hypenated_password[255];
85 if (alphanumeric_characters.empty()) 86 // Generate passwords that have numbers and upper and lower case letters.
86 InitializeAlphaNumericCharacters(&alphanumeric_characters); 87 // No special characters included for now.
88 unsigned int mode = S_NB | S_CL | S_SL;
87 89
88 // First, randomly select 4 positions to hold one upper case letter, 90 // gen_pron_pass() doesn't guarantee that it includes all of the type given
89 // one lower case letter, one digit, and one other symbol respectively, 91 // in mode, so regenerate a few times if neccessary.
90 // to make sure at least one of each category of characters will be 92 // TODO(gcasto): Is it worth regenerating at all?
91 // included in the password. 93 for (int i = 0; i < 10; ++i) {
92 std::vector<int> positions; 94 gen_pron_pass(password, unused_hypenated_password,
93 GetRandomSelection(4, password_length_, &positions); 95 password_length_, password_length_, mode);
96 if (VerifyPassword(password))
97 break;
98 }
94 99
95 // To enhance the strengh of the password, we random suffle the positions so 100 // If the password still isn't conforming after a few iterations, force it
96 // that the 4 catagories can be put at a random position in it. 101 // to be so. This may change a syllable in the password.
97 std::random_shuffle(positions.begin(), positions.end()); 102 std::string str_password(password);
98 103 if (!VerifyPassword(str_password)) {
99 // Next, generate each character of the password. 104 ForceFixPassword(&str_password);
100 for (int i = 0; i < password_length_; ++i) {
101 if (i == positions[0]) {
102 // Generate random upper case letter.
103 ret.push_back(static_cast<char>(base::RandInt(kMinUpper, kMaxUpper)));
104 } else if (i == positions[1]) {
105 // Generate random lower case letter.
106 ret.push_back(static_cast<char>(base::RandInt(kMinLower, kMaxLower)));
107 } else if (i == positions[2]) {
108 // Generate random digit.
109 ret.push_back(static_cast<char>(base::RandInt(kMinDigit, kMaxDigit)));
110 } else if (i == positions[3]) {
111 // Generate random other symbol.
112 ret.push_back(
113 kOtherSymbols[base::RandInt(0, arraysize(kOtherSymbols) - 1)]);
114 } else {
115 // Generate random alphanumeric character. We don't use other symbols
116 // here as most sites don't allow a lot of non-alphanumeric characters.
117 ret.push_back(
118 alphanumeric_characters.at(
119 base::RandInt(0, alphanumeric_characters.size() - 1)));
120 }
121 } 105 }
122 return ret; 106 return str_password;
123 } 107 }
124 108
125 } // namespace autofill 109 } // namespace autofill
OLDNEW
« no previous file with comments | « components/autofill/core/browser/password_generator.h ('k') | components/autofill/core/browser/password_generator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698