Import pwgen classes

This commit is contained in:
Matthew Wong 2015-07-10 19:44:22 -04:00
parent 8c885882dc
commit d2a252a06b
4 changed files with 439 additions and 0 deletions

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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 &lt;= n &lt; 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);
}
}