add passphrase, password generator profiles, password strength estimation, closes https://github.com/PhilippC/keepass2android/issues/81
This commit is contained in:
@@ -16,15 +16,22 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Android.App;
|
||||
using Android.App.Admin;
|
||||
using Android.Content;
|
||||
using Android.Content.PM;
|
||||
using Android.Graphics;
|
||||
using Android.OS;
|
||||
using Android.Preferences;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Java.Util;
|
||||
using KeePassLib.Cryptography;
|
||||
using Newtonsoft.Json;
|
||||
using OtpKeyProv;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
@@ -84,6 +91,48 @@ namespace keepass2android
|
||||
act.StartActivityForResult(i, 0);
|
||||
}
|
||||
|
||||
private PasswordProfiles _profiles;
|
||||
|
||||
private bool _updateDisabled = false;
|
||||
|
||||
class PasswordProfiles
|
||||
{
|
||||
public List<KeyValuePair<string, PasswordGenerator.CombinedKeyOptions>> Profiles { get; set; }
|
||||
|
||||
public PasswordGenerator.CombinedKeyOptions LastUsedSettings { get; set; }
|
||||
|
||||
public int? TryFindLastUsedProfileIndex()
|
||||
{
|
||||
for (int i=0;i<Profiles.Count;i++)
|
||||
{
|
||||
var kvp = Profiles[i];
|
||||
if (kvp.Value.Equals(LastUsedSettings))
|
||||
return i;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Add(string key, PasswordGenerator.CombinedKeyOptions options)
|
||||
{
|
||||
for (var index = 0; index < Profiles.Count; index++)
|
||||
{
|
||||
var kvp = Profiles[index];
|
||||
if (kvp.Key == key)
|
||||
{
|
||||
Profiles[index] = new KeyValuePair<string, PasswordGenerator.CombinedKeyOptions>(key, options);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Profiles.Add(new KeyValuePair<string, PasswordGenerator.CombinedKeyOptions>(key, options));
|
||||
}
|
||||
|
||||
public void Remove(in int profileIndex)
|
||||
{
|
||||
Profiles.RemoveAt(profileIndex);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnCreate(Bundle savedInstanceState) {
|
||||
_design.ApplyTheme();
|
||||
@@ -95,13 +144,13 @@ namespace keepass2android
|
||||
var prefs = GetPreferences(FileCreationMode.Private);
|
||||
|
||||
|
||||
PasswordGenerator.PasswordGenerationOptions options = null;
|
||||
string jsonOptions = prefs.GetString("password_generator_options", null);
|
||||
|
||||
string jsonOptions = prefs.GetString("password_generator_profiles", null);
|
||||
if (jsonOptions != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
options = JsonConvert.DeserializeObject<PasswordGenerator.PasswordGenerationOptions>(jsonOptions);
|
||||
_profiles = JsonConvert.DeserializeObject<PasswordProfiles>(jsonOptions);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -110,37 +159,57 @@ namespace keepass2android
|
||||
}
|
||||
else
|
||||
{
|
||||
options = new PasswordGenerator.PasswordGenerationOptions()
|
||||
PasswordGenerator.CombinedKeyOptions options = new PasswordGenerator.CombinedKeyOptions()
|
||||
{
|
||||
Length = prefs.GetInt("length", 12),
|
||||
UpperCase = prefs.GetBoolean("cb_uppercase", true),
|
||||
LowerCase = prefs.GetBoolean("cb_lowercase", true),
|
||||
Digits = prefs.GetBoolean("cb_digits", true),
|
||||
Minus = prefs.GetBoolean("cb_minus", false),
|
||||
Underline = prefs.GetBoolean("cb_underline", false),
|
||||
Space = prefs.GetBoolean("cb_space", false),
|
||||
Specials = prefs.GetBoolean("cb_specials", false),
|
||||
SpecialsExtended = false,
|
||||
Brackets = prefs.GetBoolean("cb_brackets", false)
|
||||
PasswordGenerationOptions = new PasswordGenerator.PasswordGenerationOptions()
|
||||
{
|
||||
Length = prefs.GetInt("length", 12),
|
||||
UpperCase = prefs.GetBoolean("cb_uppercase", true),
|
||||
LowerCase = prefs.GetBoolean("cb_lowercase", true),
|
||||
Digits = prefs.GetBoolean("cb_digits", true),
|
||||
Minus = prefs.GetBoolean("cb_minus", false),
|
||||
Underline = prefs.GetBoolean("cb_underline", false),
|
||||
Space = prefs.GetBoolean("cb_space", false),
|
||||
Specials = prefs.GetBoolean("cb_specials", false),
|
||||
SpecialsExtended = false,
|
||||
Brackets = prefs.GetBoolean("cb_brackets", false)
|
||||
}
|
||||
};
|
||||
_profiles = new PasswordProfiles()
|
||||
{
|
||||
LastUsedSettings = options,
|
||||
Profiles = GetDefaultProfiles()
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
((CheckBox)FindViewById(Resource.Id.cb_uppercase)).Checked = options.UpperCase;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_lowercase)).Checked = options.LowerCase;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_digits)).Checked = options.Digits;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_minus)).Checked = options.Minus;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_underline)).Checked = options.Underline;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_space)).Checked = options.Space;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_specials)).Checked = options.Specials;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_specials_extended)).Checked = options.SpecialsExtended;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_brackets)).Checked = options.Brackets;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_exclude_lookalike)).Checked = options.ExcludeLookAlike;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_at_least_one_from_each_group)).Checked = options.AtLeastOneFromEachGroup;
|
||||
_profiles ??= new PasswordProfiles();
|
||||
_profiles.LastUsedSettings ??= new PasswordGenerator.CombinedKeyOptions()
|
||||
{
|
||||
PasswordGenerationOptions = new PasswordGenerator.PasswordGenerationOptions()
|
||||
{Length = 7, UpperCase = true, LowerCase = true, Digits = true}
|
||||
};
|
||||
_profiles.Profiles ??= new List<KeyValuePair<string, PasswordGenerator.CombinedKeyOptions>>();
|
||||
|
||||
((EditText)FindViewById(Resource.Id.length)).Text = options.Length.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
foreach (int id in _buttonLengthButtonIds) {
|
||||
_updateDisabled = true;
|
||||
PopulateFieldsFromOptions(_profiles.LastUsedSettings);
|
||||
_updateDisabled = false;
|
||||
|
||||
var profileSpinner = UpdateProfileSpinner();
|
||||
|
||||
profileSpinner.ItemSelected += (sender, args) =>
|
||||
{
|
||||
if (profileSpinner.SelectedItemPosition > 0)
|
||||
{
|
||||
_profiles.LastUsedSettings = _profiles.Profiles[profileSpinner.SelectedItemPosition - 1].Value;
|
||||
_updateDisabled = true;
|
||||
PopulateFieldsFromOptions(_profiles.LastUsedSettings);
|
||||
_updateDisabled = false;
|
||||
UpdatePassword();
|
||||
}
|
||||
};
|
||||
|
||||
foreach (int id in _buttonLengthButtonIds) {
|
||||
Button button = (Button) FindViewById(id);
|
||||
button.Click += (sender, e) =>
|
||||
{
|
||||
@@ -148,15 +217,33 @@ namespace keepass2android
|
||||
|
||||
EditText editText = (EditText) FindViewById(Resource.Id.length);
|
||||
editText.Text = b.Text;
|
||||
UpdatePassword();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
FindViewById<EditText>(Resource.Id.length).TextChanged += (sender, args) => UpdatePassword();
|
||||
FindViewById<EditText>(Resource.Id.wordcount).TextChanged += (sender, args) => UpdatePassword();
|
||||
FindViewById<EditText>(Resource.Id.wordseparator).TextChanged += (sender, args) => UpdatePassword();
|
||||
|
||||
foreach (int id in _checkboxIds)
|
||||
{
|
||||
FindViewById<CheckBox>(id).CheckedChange += (sender, args) => UpdatePassword();
|
||||
}
|
||||
|
||||
var mode_spinner = FindViewById<Spinner>(Resource.Id.spinner_password_generator_mode);
|
||||
mode_spinner.ItemSelected += (sender, args) =>
|
||||
{
|
||||
FindViewById(Resource.Id.passphraseOptions).Visibility =
|
||||
mode_spinner.SelectedItemPosition == 0 ? ViewStates.Gone : ViewStates.Visible;
|
||||
FindViewById(Resource.Id.passwordOptions).Visibility =
|
||||
mode_spinner.SelectedItemPosition == 1 ? ViewStates.Gone : ViewStates.Visible;
|
||||
|
||||
UpdatePassword();
|
||||
};
|
||||
|
||||
FindViewById<Spinner>(Resource.Id.spinner_password_generator_case_mode).ItemSelected += (sender, args) =>
|
||||
{
|
||||
UpdatePassword();
|
||||
};
|
||||
|
||||
Button genPassButton = (Button) FindViewById(Resource.Id.generate_password_button);
|
||||
genPassButton.Click += (sender, e) => { UpdatePassword(); };
|
||||
@@ -184,75 +271,320 @@ namespace keepass2android
|
||||
Finish();
|
||||
};
|
||||
|
||||
|
||||
EditText txtPasswordToSet = (EditText) FindViewById(Resource.Id.password_edit);
|
||||
txtPasswordToSet.Text = GeneratePassword();
|
||||
FindViewById(Resource.Id.btn_password_generator_profile_save)
|
||||
.Click += (sender, args) =>
|
||||
{
|
||||
var editText = new EditText(this);
|
||||
new AlertDialog.Builder(this)
|
||||
.SetMessage(Resource.String.save_password_generation_profile_text)
|
||||
.SetView(editText)
|
||||
.SetPositiveButton(Android.Resource.String.Ok, (o, eventArgs) =>
|
||||
{
|
||||
_profiles.Add(editText.Text, GetOptions());
|
||||
UpdateProfileSpinner();
|
||||
})
|
||||
.Show();
|
||||
};
|
||||
|
||||
FindViewById(Resource.Id.btn_password_generator_profile_delete)
|
||||
.Click += (sender, args) =>
|
||||
{
|
||||
if (profileSpinner.SelectedItemPosition > 0)
|
||||
{
|
||||
_profiles.Remove(profileSpinner.SelectedItemPosition-1);
|
||||
UpdateProfileSpinner();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
EditText txtPasswordToSet = (EditText) FindViewById(Resource.Id.password_edit);
|
||||
|
||||
_passwordFont.ApplyTo(txtPasswordToSet);
|
||||
|
||||
UpdatePassword();
|
||||
|
||||
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
|
||||
SupportActionBar.SetHomeButtonEnabled(true);
|
||||
|
||||
}
|
||||
|
||||
private Spinner UpdateProfileSpinner()
|
||||
{
|
||||
string[] profileNames = new List<string> {GetString(Resource.String.custom_settings)}
|
||||
.Concat(_profiles.Profiles.Select(p => p.Key))
|
||||
.ToArray();
|
||||
ArrayAdapter<String> profileArrayAdapter = new ArrayAdapter<String>(this,
|
||||
Android.Resource.Layout.SimpleSpinnerDropDownItem,
|
||||
profileNames);
|
||||
var profileSpinner = FindViewById<Spinner>(Resource.Id.spinner_password_generator_profile);
|
||||
profileSpinner.Adapter = profileArrayAdapter;
|
||||
|
||||
UpdateProfileSpinnerSelection();
|
||||
return profileSpinner;
|
||||
}
|
||||
|
||||
private static List<KeyValuePair<string, PasswordGenerator.CombinedKeyOptions>> GetDefaultProfiles()
|
||||
{
|
||||
return new List<KeyValuePair<string, PasswordGenerator.CombinedKeyOptions>>()
|
||||
{
|
||||
new KeyValuePair<string, PasswordGenerator.CombinedKeyOptions>(
|
||||
"Simple12", new PasswordGenerator.CombinedKeyOptions()
|
||||
{
|
||||
PasswordGenerationOptions
|
||||
= new PasswordGenerator.PasswordGenerationOptions()
|
||||
{
|
||||
Length = 12, AtLeastOneFromEachGroup = true, ExcludeLookAlike = true,
|
||||
Digits = true, LowerCase = true, UpperCase = true
|
||||
}
|
||||
|
||||
}
|
||||
),
|
||||
new KeyValuePair<string, PasswordGenerator.CombinedKeyOptions>(
|
||||
"Special12", new PasswordGenerator.CombinedKeyOptions()
|
||||
{
|
||||
PasswordGenerationOptions
|
||||
= new PasswordGenerator.PasswordGenerationOptions()
|
||||
{
|
||||
Length = 12, AtLeastOneFromEachGroup = true, ExcludeLookAlike = true,
|
||||
Digits = true, LowerCase = true, UpperCase = true,Specials = true,Brackets = true
|
||||
}
|
||||
|
||||
}
|
||||
),
|
||||
new KeyValuePair<string, PasswordGenerator.CombinedKeyOptions>(
|
||||
"Password64", new PasswordGenerator.CombinedKeyOptions()
|
||||
{
|
||||
PasswordGenerationOptions
|
||||
= new PasswordGenerator.PasswordGenerationOptions()
|
||||
{
|
||||
Length = 64, AtLeastOneFromEachGroup = true,
|
||||
Digits = true, LowerCase = true, UpperCase = true, ExcludeLookAlike = false,Specials = true,Brackets = true, Minus = true, Space = true, SpecialsExtended = true,Underline = true
|
||||
}
|
||||
|
||||
}
|
||||
),
|
||||
new KeyValuePair<string, PasswordGenerator.CombinedKeyOptions>(
|
||||
|
||||
"Passphrase7", new PasswordGenerator.CombinedKeyOptions()
|
||||
{
|
||||
PassphraseGenerationOptions
|
||||
= new PasswordGenerator.PassphraseGenerationOptions()
|
||||
{
|
||||
WordCount = 7,
|
||||
CaseMode = PasswordGenerator.PassphraseGenerationOptions.PassphraseCaseMode.Lowercase,
|
||||
Separator = " "
|
||||
}
|
||||
}
|
||||
),
|
||||
new KeyValuePair<string, PasswordGenerator.CombinedKeyOptions>(
|
||||
"Passphrase5Plus", new PasswordGenerator.CombinedKeyOptions()
|
||||
{
|
||||
PassphraseGenerationOptions
|
||||
= new PasswordGenerator.PassphraseGenerationOptions()
|
||||
{
|
||||
WordCount = 5,
|
||||
CaseMode = PasswordGenerator.PassphraseGenerationOptions.PassphraseCaseMode.PascalCase,
|
||||
Separator = " "
|
||||
},
|
||||
PasswordGenerationOptions = new PasswordGenerator.PasswordGenerationOptions()
|
||||
{
|
||||
Length = 2,
|
||||
AtLeastOneFromEachGroup = true,
|
||||
ExcludeLookAlike = true,
|
||||
Digits = true,
|
||||
Specials = true
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private void PopulateFieldsFromOptions(PasswordGenerator.CombinedKeyOptions combinedOptions)
|
||||
{
|
||||
PasswordGenerator.PasswordGenerationOptions passwordOptions = combinedOptions.PasswordGenerationOptions;
|
||||
if (passwordOptions != null)
|
||||
{
|
||||
((CheckBox)FindViewById(Resource.Id.cb_uppercase)).Checked = passwordOptions.UpperCase;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_lowercase)).Checked = passwordOptions.LowerCase;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_digits)).Checked = passwordOptions.Digits;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_minus)).Checked = passwordOptions.Minus;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_underline)).Checked = passwordOptions.Underline;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_space)).Checked = passwordOptions.Space;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_specials)).Checked = passwordOptions.Specials;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_specials_extended)).Checked = passwordOptions.SpecialsExtended;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_brackets)).Checked = passwordOptions.Brackets;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_exclude_lookalike)).Checked = passwordOptions.ExcludeLookAlike;
|
||||
((CheckBox)FindViewById(Resource.Id.cb_at_least_one_from_each_group)).Checked = passwordOptions.AtLeastOneFromEachGroup;
|
||||
|
||||
((EditText)FindViewById(Resource.Id.length)).Text = passwordOptions.Length.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
FindViewById(Resource.Id.passwordOptions).Visibility = ViewStates.Visible;
|
||||
}
|
||||
else
|
||||
{
|
||||
FindViewById(Resource.Id.passwordOptions).Visibility = ViewStates.Gone;
|
||||
}
|
||||
|
||||
var passphraseOptions = combinedOptions.PassphraseGenerationOptions;
|
||||
|
||||
if (passphraseOptions != null)
|
||||
{
|
||||
FindViewById<EditText>(Resource.Id.wordcount).Text = passphraseOptions.WordCount.ToString(CultureInfo.InvariantCulture);
|
||||
FindViewById<EditText>(Resource.Id.wordseparator).Text = passphraseOptions.Separator;
|
||||
FindViewById<Spinner>(Resource.Id.spinner_password_generator_case_mode)
|
||||
.SetSelection((int)passphraseOptions.CaseMode);
|
||||
|
||||
FindViewById(Resource.Id.passphraseOptions).Visibility = ViewStates.Visible;
|
||||
}
|
||||
else
|
||||
{
|
||||
FindViewById(Resource.Id.passphraseOptions).Visibility = ViewStates.Gone;
|
||||
}
|
||||
|
||||
|
||||
int mode;
|
||||
if (combinedOptions.PasswordGenerationOptions != null &&
|
||||
combinedOptions.PassphraseGenerationOptions != null)
|
||||
mode = 2;
|
||||
else if (combinedOptions.PasswordGenerationOptions == null &&
|
||||
combinedOptions.PassphraseGenerationOptions != null)
|
||||
mode = 1;
|
||||
else mode = 0;
|
||||
|
||||
FindViewById<Spinner>(Resource.Id.spinner_password_generator_mode)
|
||||
.SetSelection(mode);
|
||||
|
||||
}
|
||||
|
||||
private void UpdatePassword()
|
||||
{
|
||||
if (_updateDisabled)
|
||||
return;
|
||||
String password = GeneratePassword();
|
||||
|
||||
EditText txtPassword = (EditText) FindViewById(Resource.Id.password_edit);
|
||||
txtPassword.Text = password;
|
||||
|
||||
var progressBar = FindViewById<ProgressBar>(Resource.Id.pb_password_strength);
|
||||
var passwordBits = QualityEstimation.EstimatePasswordBits(password.ToCharArray());
|
||||
progressBar.Progress = (int)passwordBits;
|
||||
progressBar.Max = 128;
|
||||
|
||||
Color color = new Color(196, 63, 49);
|
||||
if (passwordBits > 40)
|
||||
{
|
||||
color = new Color(219, 152, 55);
|
||||
}
|
||||
if (passwordBits > 64)
|
||||
{
|
||||
color = new Color(96, 138, 38);
|
||||
}
|
||||
if (passwordBits > 100)
|
||||
{
|
||||
color = new Color(31, 128, 31);
|
||||
}
|
||||
progressBar.ProgressDrawable.SetColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SrcIn));
|
||||
|
||||
FindViewById<TextView>(Resource.Id.tv_password_strength).Text = " " + passwordBits + " bits";
|
||||
|
||||
|
||||
|
||||
UpdateProfileSpinnerSelection();
|
||||
}
|
||||
|
||||
private void UpdateProfileSpinnerSelection()
|
||||
{
|
||||
int? lastUsedIndex = _profiles.TryFindLastUsedProfileIndex();
|
||||
FindViewById<Spinner>(Resource.Id.spinner_password_generator_profile)
|
||||
.SetSelection(lastUsedIndex != null ? lastUsedIndex.Value + 1 : 0);
|
||||
}
|
||||
|
||||
public String GeneratePassword() {
|
||||
String password = "";
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
PasswordGenerator generator = new PasswordGenerator(this);
|
||||
|
||||
int length;
|
||||
if (!int.TryParse(((EditText) FindViewById(Resource.Id.length)).Text, out length))
|
||||
{
|
||||
Toast.MakeText(this, Resource.String.error_wrong_length, ToastLength.Long).Show();
|
||||
return password;
|
||||
}
|
||||
var options = GetOptions();
|
||||
|
||||
try
|
||||
{
|
||||
password = generator.GeneratePassword(options);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ArgumentException(GetString(Resource.String.error_pass_gen_type));
|
||||
}
|
||||
|
||||
PasswordGenerator generator = new PasswordGenerator(this);
|
||||
_profiles.LastUsedSettings = options;
|
||||
|
||||
var options = GetOptions(length);
|
||||
|
||||
password = generator.GeneratePassword(options);
|
||||
|
||||
var prefs = GetPreferences(FileCreationMode.Private);
|
||||
prefs.Edit()
|
||||
.PutString("password_generator_options", JsonConvert.SerializeObject(options))
|
||||
.Commit();
|
||||
|
||||
|
||||
|
||||
} catch (ArgumentException e) {
|
||||
SaveProfiles();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Toast.MakeText(this, e.Message, ToastLength.Long).Show();
|
||||
}
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
private PasswordGenerator.PasswordGenerationOptions GetOptions(int length)
|
||||
private void SaveProfiles()
|
||||
{
|
||||
PasswordGenerator.PasswordGenerationOptions options = new PasswordGenerator.PasswordGenerationOptions()
|
||||
var prefs = GetPreferences(FileCreationMode.Private);
|
||||
prefs.Edit()
|
||||
.PutString("password_generator_profiles", JsonConvert.SerializeObject(_profiles))
|
||||
.Commit();
|
||||
}
|
||||
|
||||
private PasswordGenerator.CombinedKeyOptions GetOptions()
|
||||
{
|
||||
PasswordGenerator.CombinedKeyOptions options = new PasswordGenerator.CombinedKeyOptions();
|
||||
if (FindViewById(Resource.Id.passphraseOptions).Visibility == ViewStates.Visible)
|
||||
{
|
||||
Length = length,
|
||||
UpperCase = ((CheckBox) FindViewById(Resource.Id.cb_uppercase)).Checked,
|
||||
LowerCase = ((CheckBox) FindViewById(Resource.Id.cb_lowercase)).Checked,
|
||||
Digits = ((CheckBox) FindViewById(Resource.Id.cb_digits)).Checked,
|
||||
Minus = ((CheckBox) FindViewById(Resource.Id.cb_minus)).Checked,
|
||||
Underline = ((CheckBox) FindViewById(Resource.Id.cb_underline)).Checked,
|
||||
Space = ((CheckBox) FindViewById(Resource.Id.cb_space)).Checked,
|
||||
Specials = ((CheckBox) FindViewById(Resource.Id.cb_specials)).Checked,
|
||||
SpecialsExtended = ((CheckBox) FindViewById(Resource.Id.cb_specials_extended)).Checked,
|
||||
Brackets = ((CheckBox) FindViewById(Resource.Id.cb_brackets)).Checked,
|
||||
ExcludeLookAlike = ((CheckBox) FindViewById(Resource.Id.cb_exclude_lookalike)).Checked,
|
||||
AtLeastOneFromEachGroup = ((CheckBox) FindViewById(Resource.Id.cb_at_least_one_from_each_group)).Checked
|
||||
};
|
||||
int wordCount;
|
||||
if (!int.TryParse(((EditText)FindViewById(Resource.Id.wordcount)).Text, out wordCount))
|
||||
{
|
||||
throw new Exception(GetString(Resource.String.error_wrong_length));
|
||||
}
|
||||
|
||||
options.PassphraseGenerationOptions =
|
||||
new PasswordGenerator.PassphraseGenerationOptions()
|
||||
{
|
||||
WordCount = wordCount,
|
||||
Separator = FindViewById<EditText>(Resource.Id.wordseparator).Text,
|
||||
CaseMode = (PasswordGenerator.PassphraseGenerationOptions.PassphraseCaseMode)FindViewById<Spinner>(Resource.Id.spinner_password_generator_case_mode).SelectedItemPosition
|
||||
};
|
||||
}
|
||||
|
||||
if (FindViewById(Resource.Id.passwordOptions).Visibility == ViewStates.Visible)
|
||||
{
|
||||
int length;
|
||||
if (!int.TryParse(((EditText) FindViewById(Resource.Id.length)).Text, out length))
|
||||
{
|
||||
throw new Exception(GetString(Resource.String.error_wrong_length));
|
||||
}
|
||||
|
||||
options.PasswordGenerationOptions =
|
||||
new PasswordGenerator.PasswordGenerationOptions()
|
||||
{
|
||||
Length = length,
|
||||
UpperCase = ((CheckBox) FindViewById(Resource.Id.cb_uppercase)).Checked,
|
||||
LowerCase = ((CheckBox) FindViewById(Resource.Id.cb_lowercase)).Checked,
|
||||
Digits = ((CheckBox) FindViewById(Resource.Id.cb_digits)).Checked,
|
||||
Minus = ((CheckBox) FindViewById(Resource.Id.cb_minus)).Checked,
|
||||
Underline = ((CheckBox) FindViewById(Resource.Id.cb_underline)).Checked,
|
||||
Space = ((CheckBox) FindViewById(Resource.Id.cb_space)).Checked,
|
||||
Specials = ((CheckBox) FindViewById(Resource.Id.cb_specials)).Checked,
|
||||
SpecialsExtended = ((CheckBox) FindViewById(Resource.Id.cb_specials_extended)).Checked,
|
||||
Brackets = ((CheckBox) FindViewById(Resource.Id.cb_brackets)).Checked,
|
||||
ExcludeLookAlike = ((CheckBox) FindViewById(Resource.Id.cb_exclude_lookalike)).Checked,
|
||||
AtLeastOneFromEachGroup = ((CheckBox) FindViewById(Resource.Id.cb_at_least_one_from_each_group))
|
||||
.Checked
|
||||
};
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:background="?activityBackgroundColor"
|
||||
android:layout_height="fill_parent">
|
||||
android:layout_width="fill_parent"
|
||||
android:background="?activityBackgroundColor"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<RelativeLayout
|
||||
|
||||
@@ -32,7 +32,7 @@ android:background="?activityBackgroundColor"
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/ScrollView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_above="@id/bottom_bar"
|
||||
android:layout_marginBottom="12dip"
|
||||
@@ -40,95 +40,220 @@ android:background="?activityBackgroundColor"
|
||||
android:layout_marginRight="12dip"
|
||||
android:layout_marginTop="12dip"
|
||||
android:layout_alignParentTop="false">
|
||||
<RelativeLayout
|
||||
android:id="@+id/RelativeLayout"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
<EditText
|
||||
android:id="@+id/password_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10"
|
||||
android:singleLine="true"
|
||||
android:typeface="monospace"
|
||||
android:hint="@string/hint_generated_password" />
|
||||
<Button
|
||||
android:id="@+id/generate_password_button"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/generate_password" />
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp"
|
||||
android:layout_height="wrap_content">
|
||||
<ProgressBar
|
||||
|
||||
android:id="@+id/pb_password_strength"
|
||||
android:layout_width="50dp"
|
||||
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||
android:indeterminate="false"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"/>
|
||||
<TextView
|
||||
android:id="@+id/tv_password_strength"
|
||||
android:paddingLeft="4dp"
|
||||
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingBottom="1dp"
|
||||
android:paddingTop="8dp"
|
||||
android:text="@string/password_generation_profile"/>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content">
|
||||
<EditText
|
||||
android:id="@+id/password_edit"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10"
|
||||
android:singleLine="true"
|
||||
android:typeface="monospace"
|
||||
android:hint="@string/hint_generated_password" />
|
||||
<Button
|
||||
android:id="@+id/generate_password_button"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/password_edit"
|
||||
android:text="@string/generate_password" />
|
||||
<TextView
|
||||
android:id="@+id/length_label"
|
||||
android:text="@string/length"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_below="@id/generate_password_button" />
|
||||
<Button
|
||||
android:id="@+id/btn_length32"
|
||||
android:text="32"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_width="50sp"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<Spinner
|
||||
|
||||
android:id="@+id/spinner_password_generator_profile"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
<ImageButton
|
||||
android:id="@+id/btn_password_generator_profile_save"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/ic_menu_save"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentTop="true" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btn_password_generator_profile_delete"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/ic_menu_close"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentTop="true" />
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_password_generator_mode"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10"
|
||||
android:layout_marginBottom="64dip"
|
||||
android:entries="@array/PasswordGeneratorModes"
|
||||
/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/passphraseOptions"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/wordcountlayout">
|
||||
<EditText
|
||||
android:id="@+id/wordcount"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:singleLine="true"
|
||||
android:text="7"
|
||||
android:hint="@string/hint_wordcount" />
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/wordseparatorlayout">
|
||||
<EditText
|
||||
android:id="@+id/wordseparator"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:singleLine="true"
|
||||
android:text=" "
|
||||
android:hint="@string/hint_wordseparator" />
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:text="@string/passphrase_capitalization"/>
|
||||
<Spinner
|
||||
|
||||
android:id="@+id/spinner_password_generator_case_mode"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:entries="@array/PasswordGeneratorCaseModes"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/passwordOptions"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent">
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:id="@+id/pwd_buttons"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/length_label" />
|
||||
<Button
|
||||
android:id="@+id/btn_length24"
|
||||
android:text="24"
|
||||
android:layout_toLeftOf="@id/btn_length32"
|
||||
android:layout_width="match_parent">
|
||||
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="50sp"
|
||||
android:layout_alignTop="@id/btn_length32" />
|
||||
<Button
|
||||
android:id="@+id/btn_length16"
|
||||
android:text="16"
|
||||
android:layout_toLeftOf="@id/btn_length24"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="50sp"
|
||||
android:layout_alignTop="@id/btn_length32" />
|
||||
<Button
|
||||
android:id="@+id/btn_length12"
|
||||
android:text="12"
|
||||
android:layout_toLeftOf="@id/btn_length16"
|
||||
android:layout_width="50dp"
|
||||
android:layout_weight="1"
|
||||
android:id="@+id/lengthlayout">
|
||||
<EditText
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="50sp"
|
||||
android:layout_alignTop="@id/btn_length32" />
|
||||
<Button
|
||||
android:id="@+id/btn_length8"
|
||||
android:text="8"
|
||||
android:layout_toLeftOf="@id/btn_length12"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="50sp"
|
||||
android:layout_alignTop="@id/btn_length32" />
|
||||
<Button
|
||||
android:id="@+id/btn_length6"
|
||||
android:text="6"
|
||||
android:layout_toLeftOf="@id/btn_length8"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="50sp"
|
||||
android:layout_alignTop="@id/btn_length32" />
|
||||
<EditText
|
||||
android:id="@+id/length"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_toLeftOf="@id/btn_length6"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@id/btn_length32"
|
||||
|
||||
android:singleLine="true"
|
||||
android:text="12"
|
||||
android:hint="@string/hint_length" />
|
||||
<CheckBox
|
||||
android:id="@+id/cb_uppercase"
|
||||
android:layout_width="wrap_content"
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_length6"
|
||||
android:text="6"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/uppercase"
|
||||
android:checked="true"
|
||||
android:layout_below="@id/length" />
|
||||
android:layout_width="50sp"
|
||||
/>
|
||||
<Button
|
||||
android:id="@+id/btn_length8"
|
||||
android:text="8"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="50sp"
|
||||
/>
|
||||
<Button
|
||||
android:id="@+id/btn_length12"
|
||||
android:text="12"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="50sp"
|
||||
/>
|
||||
<Button
|
||||
android:id="@+id/btn_length16"
|
||||
android:text="16"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="50sp"
|
||||
/>
|
||||
<Button
|
||||
android:id="@+id/btn_length24"
|
||||
android:text="24"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="50sp"
|
||||
/>
|
||||
<Button
|
||||
android:id="@+id/btn_length32"
|
||||
android:text="32"
|
||||
android:layout_width="50sp"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<CheckBox
|
||||
android:id="@+id/cb_uppercase"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/uppercase"
|
||||
android:checked="true" />
|
||||
<CheckBox
|
||||
android:id="@+id/cb_lowercase"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/lowercase"
|
||||
android:checked="true"
|
||||
android:layout_below="@id/cb_uppercase" />
|
||||
android:checked="true" />
|
||||
<CheckBox
|
||||
android:id="@+id/cb_digits"
|
||||
android:layout_width="wrap_content"
|
||||
@@ -185,6 +310,10 @@ android:background="?activityBackgroundColor"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/at_least_one_from_each_group"
|
||||
android:layout_below="@id/cb_exclude_lookalike" />
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
</RelativeLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
@@ -266,7 +266,26 @@
|
||||
<string name="special_extended">Extended Special</string>
|
||||
<string name="at_least_one_from_each_group">At least one from each group</string>
|
||||
<string name="exclude_lookalike">Exclude look-alike characters</string>
|
||||
<string name="search_hint">Find what</string>
|
||||
<string name="password_generation_profile">Profile</string>
|
||||
<string name="save_password_generation_profile_text">Enter the name of the profile to save. Enter an existing name to overwrite.</string>
|
||||
|
||||
<string name="hint_wordcount">Passphrase word count</string>
|
||||
<string name="hint_wordseparator">Word separator</string>
|
||||
<string-array name="PasswordGeneratorModes">
|
||||
<item>Password</item>
|
||||
<item>Passphrase</item>
|
||||
<item>Passphrase + Password</item>
|
||||
</string-array>
|
||||
<string-array name="PasswordGeneratorCaseModes">
|
||||
<item>lowercase</item>
|
||||
<item>UPPERCASE</item>
|
||||
<item>First Character Uppercase</item>
|
||||
</string-array>
|
||||
<string name="custom_settings">Custom settings</string>
|
||||
<string name="passphrase_capitalization">Passphrase capitalization</string>
|
||||
|
||||
|
||||
<string name="search_hint">Find what</string>
|
||||
<string name="search_results">Search results</string>
|
||||
<string name="search_in">Search in</string>
|
||||
<string name="select_other_entry">Select another entry</string>
|
||||
|
||||
7793
src/keepass2android/Wordlist.cs
Normal file
7793
src/keepass2android/Wordlist.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -283,6 +283,7 @@
|
||||
<Compile Include="AttachmentContentProvider.cs" />
|
||||
<Compile Include="app\AppTask.cs" />
|
||||
<Compile Include="views\TextWithHelp.cs" />
|
||||
<Compile Include="Wordlist.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\xml\searchable.xml">
|
||||
|
||||
@@ -20,10 +20,26 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
public static class StringExtension
|
||||
{
|
||||
public static string ToUpperFirstLetter(this string source)
|
||||
{
|
||||
if (string.IsNullOrEmpty(source))
|
||||
return string.Empty;
|
||||
// convert to char array of the string
|
||||
char[] letters = source.ToCharArray();
|
||||
// upper case the first char
|
||||
letters[0] = char.ToUpper(letters[0]);
|
||||
// return the array made of the new char array
|
||||
return new string(letters);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Password generator
|
||||
/// </summary>
|
||||
@@ -85,9 +101,64 @@ namespace keepass2android
|
||||
_cxt = cxt;
|
||||
}
|
||||
|
||||
public class CombinedKeyOptions
|
||||
{
|
||||
protected bool Equals(CombinedKeyOptions other)
|
||||
{
|
||||
return Equals(PassphraseGenerationOptions, other.PassphraseGenerationOptions) && Equals(PasswordGenerationOptions, other.PasswordGenerationOptions);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((CombinedKeyOptions) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(PassphraseGenerationOptions, PasswordGenerationOptions);
|
||||
}
|
||||
|
||||
public PassphraseGenerationOptions PassphraseGenerationOptions { get; set; }
|
||||
public PasswordGenerationOptions PasswordGenerationOptions { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class PasswordGenerationOptions
|
||||
{
|
||||
protected bool Equals(PasswordGenerationOptions other)
|
||||
{
|
||||
return Length == other.Length && UpperCase == other.UpperCase && LowerCase == other.LowerCase && Digits == other.Digits && Minus == other.Minus && Underline == other.Underline && Space == other.Space && Specials == other.Specials && SpecialsExtended == other.SpecialsExtended && Brackets == other.Brackets && ExcludeLookAlike == other.ExcludeLookAlike && AtLeastOneFromEachGroup == other.AtLeastOneFromEachGroup;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((PasswordGenerationOptions) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var hashCode = new HashCode();
|
||||
hashCode.Add(Length);
|
||||
hashCode.Add(UpperCase);
|
||||
hashCode.Add(LowerCase);
|
||||
hashCode.Add(Digits);
|
||||
hashCode.Add(Minus);
|
||||
hashCode.Add(Underline);
|
||||
hashCode.Add(Space);
|
||||
hashCode.Add(Specials);
|
||||
hashCode.Add(SpecialsExtended);
|
||||
hashCode.Add(Brackets);
|
||||
hashCode.Add(ExcludeLookAlike);
|
||||
hashCode.Add(AtLeastOneFromEachGroup);
|
||||
return hashCode.ToHashCode();
|
||||
}
|
||||
|
||||
public int Length { get; set; }
|
||||
public bool UpperCase { get; set; }
|
||||
public bool LowerCase { get; set; }
|
||||
@@ -104,63 +175,141 @@ namespace keepass2android
|
||||
|
||||
}
|
||||
|
||||
|
||||
public String GeneratePassword(PasswordGenerationOptions options) {
|
||||
if (options.Length <= 0)
|
||||
throw new ArgumentException(_cxt.GetString(Resource.String.error_wrong_length));
|
||||
|
||||
|
||||
var groups = GetCharacterGroups(options);
|
||||
String characterSet = GetCharacterSet(options, groups);
|
||||
|
||||
if (characterSet.Length == 0)
|
||||
throw new ArgumentException(_cxt.GetString(Resource.String.error_pass_gen_type));
|
||||
|
||||
int size = characterSet.Length;
|
||||
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
|
||||
Random random = new SecureRandom();
|
||||
|
||||
if (options.AtLeastOneFromEachGroup)
|
||||
public class PassphraseGenerationOptions
|
||||
{
|
||||
protected bool Equals(PassphraseGenerationOptions other)
|
||||
{
|
||||
foreach (var g in groups)
|
||||
{
|
||||
if (g.Length > 0)
|
||||
{
|
||||
buffer.Append(g[random.Next(g.Length)]);
|
||||
}
|
||||
}
|
||||
return CaseMode == other.CaseMode && Separator == other.Separator && WordCount == other.WordCount;
|
||||
}
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
while (buffer.Length < options.Length)
|
||||
{
|
||||
buffer.Append(characterSet[random.Next(size)]);
|
||||
}
|
||||
}
|
||||
|
||||
var password = buffer.ToString();
|
||||
|
||||
if (options.AtLeastOneFromEachGroup)
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
//shuffle
|
||||
StringBuilder sb = new StringBuilder(password);
|
||||
for (int i = (password.Length - 1); i >= 1; i--)
|
||||
{
|
||||
int j = random.Next(i + 1);
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((PassphraseGenerationOptions) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine((int) CaseMode, Separator, WordCount);
|
||||
}
|
||||
|
||||
public enum PassphraseCaseMode
|
||||
{
|
||||
Lowercase,
|
||||
Uppercase,
|
||||
PascalCase
|
||||
};
|
||||
public PassphraseCaseMode CaseMode { get; set; }
|
||||
public string Separator { get; set; }
|
||||
public int WordCount { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String GeneratePassword(CombinedKeyOptions options)
|
||||
{
|
||||
if ((options.PassphraseGenerationOptions== null || options.PassphraseGenerationOptions.WordCount == 0)
|
||||
&& (options.PasswordGenerationOptions == null || options.PasswordGenerationOptions.Length == 0))
|
||||
{
|
||||
throw new Exception("Bad options");
|
||||
}
|
||||
|
||||
string key = "";
|
||||
|
||||
Random random = new SecureRandom();
|
||||
|
||||
var passwordOptions = options.PasswordGenerationOptions;
|
||||
var passphraseOptions = options.PassphraseGenerationOptions;
|
||||
if (passphraseOptions != null && passphraseOptions.WordCount > 0)
|
||||
{
|
||||
var wl = new Wordlist();
|
||||
string passphrase = "";
|
||||
for (int i = 0; i < passphraseOptions.WordCount; i++)
|
||||
{
|
||||
|
||||
string word = wl.GetWord(random);
|
||||
|
||||
if (passphraseOptions.CaseMode == PassphraseGenerationOptions.PassphraseCaseMode.Uppercase)
|
||||
{
|
||||
word = word.ToUpper();
|
||||
}
|
||||
else if (passphraseOptions.CaseMode == PassphraseGenerationOptions.PassphraseCaseMode.Lowercase)
|
||||
{
|
||||
word = word.ToLower();
|
||||
}
|
||||
else if (passphraseOptions.CaseMode == PassphraseGenerationOptions.PassphraseCaseMode.PascalCase)
|
||||
{
|
||||
word = word.ToUpperFirstLetter();
|
||||
}
|
||||
|
||||
passphrase += word;
|
||||
|
||||
if (i < passphraseOptions.WordCount - 1 || passwordOptions != null)
|
||||
passphrase += passphraseOptions.Separator;
|
||||
|
||||
var tmp = sb[i];
|
||||
sb[i] = sb[j];
|
||||
sb[j] = tmp;
|
||||
}
|
||||
|
||||
password = sb.ToString();
|
||||
key += passphrase;
|
||||
}
|
||||
|
||||
|
||||
return password;
|
||||
if (passwordOptions != null)
|
||||
{
|
||||
var groups = GetCharacterGroups(passwordOptions);
|
||||
String characterSet = GetCharacterSet(passwordOptions, groups);
|
||||
|
||||
if (characterSet.Length == 0)
|
||||
throw new Exception("Bad options");
|
||||
|
||||
int size = characterSet.Length;
|
||||
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
|
||||
if (passwordOptions.AtLeastOneFromEachGroup)
|
||||
{
|
||||
foreach (var g in groups)
|
||||
{
|
||||
if (g.Length > 0)
|
||||
{
|
||||
buffer.Append(g[random.Next(g.Length)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
while (buffer.Length < passwordOptions.Length)
|
||||
{
|
||||
buffer.Append(characterSet[random.Next(size)]);
|
||||
}
|
||||
}
|
||||
|
||||
var password = buffer.ToString();
|
||||
|
||||
if (passwordOptions.AtLeastOneFromEachGroup)
|
||||
{
|
||||
//shuffle
|
||||
StringBuilder sb = new StringBuilder(password);
|
||||
for (int i = (password.Length - 1); i >= 1; i--)
|
||||
{
|
||||
int j = random.Next(i + 1);
|
||||
|
||||
var tmp = sb[i];
|
||||
sb[i] = sb[j];
|
||||
sb[j] = tmp;
|
||||
}
|
||||
|
||||
password = sb.ToString();
|
||||
}
|
||||
|
||||
key += password;
|
||||
}
|
||||
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
public string GetCharacterSet(PasswordGenerationOptions options, List<string> groups)
|
||||
|
||||
Reference in New Issue
Block a user