Import pwgen classes
This commit is contained in:
parent
8c885882dc
commit
d2a252a06b
4 changed files with 439 additions and 0 deletions
206
app/src/main/java/com/zeapo/pwdstore/pwgen/pw_phonemes.java
Normal file
206
app/src/main/java/com/zeapo/pwdstore/pwgen/pw_phonemes.java
Normal file
|
@ -0,0 +1,206 @@
|
|||
package com.zeapo.pwdstore.pwgen;
|
||||
|
||||
public class pw_phonemes {
|
||||
private static final int CONSONANT = 0x0001;
|
||||
private static final int VOWEL = 0x0002;
|
||||
private static final int DIPTHONG = 0x0004;
|
||||
private static final int NOT_FIRST = 0x0008;
|
||||
|
||||
private static final element elements[] = {
|
||||
new element("a", VOWEL),
|
||||
new element("ae", VOWEL | DIPTHONG),
|
||||
new element("ah", VOWEL | DIPTHONG),
|
||||
new element("ai", VOWEL | DIPTHONG),
|
||||
new element("b", CONSONANT),
|
||||
new element("c", CONSONANT),
|
||||
new element("ch", CONSONANT | DIPTHONG),
|
||||
new element("d", CONSONANT),
|
||||
new element("e", VOWEL),
|
||||
new element("ee", VOWEL | DIPTHONG),
|
||||
new element("ei", VOWEL | DIPTHONG),
|
||||
new element("f", CONSONANT),
|
||||
new element("g", CONSONANT),
|
||||
new element("gh", CONSONANT | DIPTHONG | NOT_FIRST),
|
||||
new element("h", CONSONANT),
|
||||
new element("i", VOWEL),
|
||||
new element("ie", VOWEL | DIPTHONG),
|
||||
new element("j", CONSONANT),
|
||||
new element("k", CONSONANT),
|
||||
new element("l", CONSONANT),
|
||||
new element("m", CONSONANT),
|
||||
new element("n", CONSONANT),
|
||||
new element("ng", CONSONANT | DIPTHONG | NOT_FIRST),
|
||||
new element("o", VOWEL),
|
||||
new element("oh", VOWEL | DIPTHONG),
|
||||
new element("oo", VOWEL | DIPTHONG),
|
||||
new element("p", CONSONANT),
|
||||
new element("ph", CONSONANT | DIPTHONG),
|
||||
new element("qu", CONSONANT | DIPTHONG),
|
||||
new element("r", CONSONANT),
|
||||
new element("s", CONSONANT),
|
||||
new element("sh", CONSONANT | DIPTHONG),
|
||||
new element("t", CONSONANT),
|
||||
new element("th", CONSONANT | DIPTHONG),
|
||||
new element("u", VOWEL),
|
||||
new element("v", CONSONANT),
|
||||
new element("w", CONSONANT),
|
||||
new element("x", CONSONANT),
|
||||
new element("y", CONSONANT),
|
||||
new element("z", CONSONANT)
|
||||
};
|
||||
|
||||
private static class element {
|
||||
String str;
|
||||
int flags;
|
||||
element(String str, int flags) {
|
||||
this.str = str;
|
||||
this.flags = flags;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int NUM_ELEMENTS = elements.length;
|
||||
|
||||
/**
|
||||
* Generates a human-readable password.
|
||||
*
|
||||
* @param size length of password to generate
|
||||
* @param pwFlags flag field where set bits indicate conditions the
|
||||
* generated password must meet
|
||||
* <table summary="bits of flag field">
|
||||
* <tr><td>Bit</td><td>Condition</td></tr>
|
||||
* <tr><td>0</td><td>include at least one number</td></tr>
|
||||
* <tr><td>1</td><td>include at least one uppercase letter</td></tr>
|
||||
* <tr><td>2</td><td>include at least one symbol</td></tr>
|
||||
* <tr><td>3</td><td>don't include ambiguous characters</td></tr>
|
||||
* </table>
|
||||
* @return the generated password
|
||||
*/
|
||||
public static String phonemes(int size, int pwFlags) {
|
||||
String password;
|
||||
int curSize, i, length, flags, featureFlags, prev, shouldBe;
|
||||
boolean first;
|
||||
String str;
|
||||
char cha;
|
||||
|
||||
do {
|
||||
password = "";
|
||||
featureFlags = pwFlags;
|
||||
curSize = 0;
|
||||
prev = 0;
|
||||
first = true;
|
||||
|
||||
shouldBe = randnum.number(2) == 1 ? VOWEL : CONSONANT;
|
||||
|
||||
while (curSize < size) {
|
||||
i = randnum.number(NUM_ELEMENTS);
|
||||
str = elements[i].str;
|
||||
length = str.length();
|
||||
flags = elements[i].flags;
|
||||
// Filter on the basic type of the next element
|
||||
if ((flags & shouldBe) == 0) {
|
||||
continue;
|
||||
}
|
||||
// Handle the NOT_FIRST flag
|
||||
if (first && (flags & NOT_FIRST) > 0) {
|
||||
continue;
|
||||
}
|
||||
// Don't allow VOWEL followed a Vowel/Dipthong pair
|
||||
if ((prev & VOWEL) > 0 && (flags & VOWEL) > 0
|
||||
&& (flags & DIPTHONG) > 0) {
|
||||
continue;
|
||||
}
|
||||
// Don't allow us to overflow the buffer
|
||||
if (length > size - curSize) {
|
||||
continue;
|
||||
}
|
||||
// OK, we found an element which matches our criteria, let's do
|
||||
// it
|
||||
password += str;
|
||||
|
||||
// Handle UPPERS
|
||||
if ((pwFlags & pwgen.UPPERS) > 0) {
|
||||
if ((first || (flags & CONSONANT) > 0)
|
||||
&& (randnum.number(10) < 2)) {
|
||||
int index = password.length() - length;
|
||||
password = password.substring(0, index)
|
||||
+ str.toUpperCase();
|
||||
featureFlags &= ~pwgen.UPPERS;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the AMBIGUOUS flag
|
||||
if ((pwFlags & pwgen.AMBIGUOUS) > 0) {
|
||||
for (char ambiguous : pwgen.AMBIGUOUS_STR.toCharArray()) {
|
||||
if (password.contains(String.valueOf(ambiguous))) {
|
||||
password = password.substring(0, curSize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (password.length() == curSize)
|
||||
continue;
|
||||
}
|
||||
|
||||
curSize += length;
|
||||
|
||||
// Time to stop?
|
||||
if (curSize >= size)
|
||||
break;
|
||||
|
||||
// Handle DIGITS
|
||||
if ((pwFlags & pwgen.DIGITS) > 0) {
|
||||
if (!first && (randnum.number(10) < 3)) {
|
||||
String val;
|
||||
do {
|
||||
cha = Character.forDigit(randnum.number(10), 10);
|
||||
val = String.valueOf(cha);
|
||||
} while ((pwFlags & pwgen.AMBIGUOUS) > 0
|
||||
&& pwgen.AMBIGUOUS_STR.contains(val));
|
||||
password += val;
|
||||
curSize++;
|
||||
|
||||
featureFlags &= ~pwgen.DIGITS;
|
||||
|
||||
first = true;
|
||||
prev = 0;
|
||||
shouldBe = randnum.number(2) == 1 ? VOWEL : CONSONANT;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle SYMBOLS
|
||||
if ((pwFlags & pwgen.SYMBOLS) > 0) {
|
||||
if (!first && (randnum.number(10) < 2)) {
|
||||
String val;
|
||||
int num;
|
||||
do {
|
||||
num = randnum.number(pwgen.SYMBOLS_STR.length());
|
||||
cha = pwgen.SYMBOLS_STR.toCharArray()[num];
|
||||
val = String.valueOf(cha);
|
||||
} while ((pwFlags & pwgen.AMBIGUOUS) > 0
|
||||
&& pwgen.AMBIGUOUS_STR.contains(val));
|
||||
password += val;
|
||||
curSize++;
|
||||
|
||||
featureFlags &= ~pwgen.SYMBOLS;
|
||||
}
|
||||
}
|
||||
|
||||
// OK, figure out what the next element should be
|
||||
if (shouldBe == CONSONANT) {
|
||||
shouldBe = VOWEL;
|
||||
} else {
|
||||
if ((prev & VOWEL) > 0 || (flags & DIPTHONG) > 0
|
||||
|| (randnum.number(10) > 3)) {
|
||||
shouldBe = CONSONANT;
|
||||
} else {
|
||||
shouldBe = VOWEL;
|
||||
}
|
||||
}
|
||||
prev = flags;
|
||||
first = false;
|
||||
}
|
||||
} while ((featureFlags & (pwgen.UPPERS | pwgen.DIGITS | pwgen.SYMBOLS))
|
||||
> 0);
|
||||
return password;
|
||||
}
|
||||
}
|
69
app/src/main/java/com/zeapo/pwdstore/pwgen/pw_rand.java
Normal file
69
app/src/main/java/com/zeapo/pwdstore/pwgen/pw_rand.java
Normal file
|
@ -0,0 +1,69 @@
|
|||
package com.zeapo.pwdstore.pwgen;
|
||||
|
||||
public class pw_rand {
|
||||
|
||||
/**
|
||||
* Generates a completely random password.
|
||||
*
|
||||
* @param size length of password to generate
|
||||
* @param pwFlags flag field where set bits indicate conditions the
|
||||
* generated password must meet
|
||||
* <table summary ="bits of flag field">
|
||||
* <tr><td>Bit</td><td>Condition</td></tr>
|
||||
* <tr><td>0</td><td>include at least one number</td></tr>
|
||||
* <tr><td>1</td><td>include at least one uppercase letter</td></tr>
|
||||
* <tr><td>2</td><td>include at least one symbol</td></tr>
|
||||
* <tr><td>3</td><td>don't include ambiguous characters</td></tr>
|
||||
* <tr><td>4</td><td>don't include vowels</td></tr>
|
||||
* </table>
|
||||
* @return the generated password
|
||||
*/
|
||||
public static String rand(int size, int pwFlags) {
|
||||
String password = "";
|
||||
char cha;
|
||||
int i, featureFlags, num;
|
||||
String val;
|
||||
|
||||
String bank = "";
|
||||
if ((pwFlags & pwgen.DIGITS) > 0) {
|
||||
bank += pwgen.DIGITS_STR;
|
||||
}
|
||||
if ((pwFlags & pwgen.UPPERS) > 0) {
|
||||
bank += pwgen.UPPERS_STR;
|
||||
}
|
||||
bank += pwgen.LOWERS_STR;
|
||||
if ((pwFlags & pwgen.SYMBOLS) > 0) {
|
||||
bank += pwgen.SYMBOLS_STR;
|
||||
}
|
||||
do {
|
||||
featureFlags = pwFlags;
|
||||
i = 0;
|
||||
while (i < size) {
|
||||
num = randnum.number(bank.length());
|
||||
cha = bank.toCharArray()[num];
|
||||
val = String.valueOf(cha);
|
||||
if ((pwFlags & pwgen.AMBIGUOUS) > 0
|
||||
&& pwgen.AMBIGUOUS_STR.contains(val)) {
|
||||
continue;
|
||||
}
|
||||
if ((pwFlags & pwgen.NO_VOWELS) > 0
|
||||
&& pwgen.VOWELS_STR.contains(val)) {
|
||||
continue;
|
||||
}
|
||||
password += val;
|
||||
i++;
|
||||
if (pwgen.DIGITS_STR.contains(val)) {
|
||||
featureFlags &= ~pwgen.DIGITS;
|
||||
}
|
||||
if (pwgen.UPPERS_STR.contains(val)) {
|
||||
featureFlags &= ~pwgen.UPPERS;
|
||||
}
|
||||
if (pwgen.SYMBOLS_STR.contains(val)) {
|
||||
featureFlags &= ~pwgen.SYMBOLS;
|
||||
}
|
||||
}
|
||||
} while ((featureFlags & (pwgen.UPPERS | pwgen.DIGITS | pwgen.SYMBOLS))
|
||||
> 0);
|
||||
return password;
|
||||
}
|
||||
}
|
138
app/src/main/java/com/zeapo/pwdstore/pwgen/pwgen.java
Normal file
138
app/src/main/java/com/zeapo/pwdstore/pwgen/pwgen.java
Normal file
|
@ -0,0 +1,138 @@
|
|||
package com.zeapo.pwdstore.pwgen;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class pwgen {
|
||||
static final int DIGITS = 0x0001;
|
||||
static final int UPPERS = 0x0002;
|
||||
static final int SYMBOLS = 0x0004;
|
||||
static final int AMBIGUOUS = 0x0008;
|
||||
static final int NO_VOWELS = 0x0010;
|
||||
|
||||
static final String DIGITS_STR = "0123456789";
|
||||
static final String UPPERS_STR = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
static final String LOWERS_STR = "abcdefghijklmnopqrstuvwxyz";
|
||||
static final String SYMBOLS_STR = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
|
||||
static final String AMBIGUOUS_STR = "B8G6I1l0OQDS5Z2";
|
||||
static final String VOWELS_STR = "01aeiouyAEIOUY";
|
||||
|
||||
// No a, c, n, h, H, C, 1, N
|
||||
private static final String pwOptions = "0ABsvy";
|
||||
|
||||
/**
|
||||
* Sets password generation preferences.
|
||||
*
|
||||
* @param ctx context from which to retrieve SharedPreferences from
|
||||
* preferences file 'pwgen'
|
||||
* @param argv options for password generation
|
||||
* <table summary="options for password generation">
|
||||
* <tr><td>Option</td><td>Description</td></tr>
|
||||
* <tr><td>0</td><td>don't include numbers</td></tr>
|
||||
* <tr><td>A</td><td>don't include uppercase letters</td></tr>
|
||||
* <tr><td>B</td><td>don't include ambiguous charactersl</td></tr>
|
||||
* <tr><td>s</td><td>generate completely random passwords</td></tr>
|
||||
* <tr><td>v</td><td>don't include vowels</td></tr>
|
||||
* <tr><td>y</td><td>include at least one symbol</td></tr>
|
||||
* </table>
|
||||
* @param numArgv numerical options for password generation: length of
|
||||
* generated passwords followed by number of passwords to
|
||||
* generate
|
||||
* @return <code>false</code> if a numerical options is invalid,
|
||||
* <code>true</code> otherwise
|
||||
*/
|
||||
public static boolean setPrefs(Context ctx, ArrayList<String> argv
|
||||
, int... numArgv) {
|
||||
SharedPreferences prefs
|
||||
= ctx.getSharedPreferences("pwgen", Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
|
||||
for (char option : pwOptions.toCharArray()) {
|
||||
if (argv.contains(String.valueOf(option))) {
|
||||
editor.putBoolean(String.valueOf(option), true);
|
||||
argv.remove(String.valueOf(option));
|
||||
} else {
|
||||
editor.putBoolean(String.valueOf(option), false);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < numArgv.length && i < 2; i++) {
|
||||
if (numArgv[i] <= 0) {
|
||||
// Invalid password length or number of passwords
|
||||
return false;
|
||||
}
|
||||
String name = i == 0 ? "length" : "num";
|
||||
editor.putInt(name, numArgv[i]);
|
||||
}
|
||||
editor.apply();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates passwords using the preferences set by
|
||||
* {@link #setPrefs(Context, ArrayList, int...)}.
|
||||
*
|
||||
* @param ctx context from which to retrieve SharedPreferences from
|
||||
* preferences file 'pwgen'
|
||||
* @return list of generated passwords
|
||||
*/
|
||||
public static ArrayList<String> generate(Context ctx) {
|
||||
SharedPreferences prefs
|
||||
= ctx.getSharedPreferences("pwgen", Context.MODE_PRIVATE);
|
||||
|
||||
boolean phonemes = true;
|
||||
int pwgenFlags = DIGITS | UPPERS;
|
||||
|
||||
for (char option : pwOptions.toCharArray()) {
|
||||
if (prefs.getBoolean(String.valueOf(option), false)) {
|
||||
switch(option) {
|
||||
case '0':
|
||||
pwgenFlags &= ~DIGITS;
|
||||
break;
|
||||
case 'A':
|
||||
pwgenFlags &= ~UPPERS;
|
||||
break;
|
||||
case 'B':
|
||||
pwgenFlags |= AMBIGUOUS;
|
||||
break;
|
||||
case 's':
|
||||
phonemes = false;
|
||||
// pwgenFlags = DIGITS | UPPERS;
|
||||
break;
|
||||
case 'y':
|
||||
pwgenFlags |= SYMBOLS;
|
||||
break;
|
||||
case 'v':
|
||||
phonemes = false;
|
||||
pwgenFlags |= NO_VOWELS; // | DIGITS | UPPERS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int length = prefs.getInt("length", 8);
|
||||
if (length < 5) {
|
||||
phonemes = false;
|
||||
}
|
||||
if (length <= 2) {
|
||||
pwgenFlags &= ~UPPERS;
|
||||
}
|
||||
if (length <= 1) {
|
||||
pwgenFlags &= ~DIGITS;
|
||||
}
|
||||
|
||||
ArrayList<String> passwords = new ArrayList<>();
|
||||
int num = prefs.getInt("num", 1);
|
||||
for (int i = 0; i < num; i++) {
|
||||
if (phonemes) {
|
||||
passwords.add(pw_phonemes.phonemes(length, pwgenFlags));
|
||||
} else {
|
||||
passwords.add(pw_rand.rand(length, pwgenFlags));
|
||||
}
|
||||
}
|
||||
return passwords;
|
||||
}
|
||||
|
||||
}
|
||||
|
26
app/src/main/java/com/zeapo/pwdstore/pwgen/randnum.java
Normal file
26
app/src/main/java/com/zeapo/pwdstore/pwgen/randnum.java
Normal file
|
@ -0,0 +1,26 @@
|
|||
package com.zeapo.pwdstore.pwgen;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class randnum {
|
||||
private static SecureRandom random;
|
||||
|
||||
static {
|
||||
try {
|
||||
random = SecureRandom.getInstance("SHA1PRNG");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new SecurityException("SHA1PRNG not available", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random number n, where 0 <= n < maxNum.
|
||||
*
|
||||
* @param maxNum the bound on the random number to be returned
|
||||
* @return the generated random number
|
||||
*/
|
||||
public static int number(int maxNum) {
|
||||
return random.nextInt(maxNum);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue