aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/pwgen/pw_phonemes.java206
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/pwgen/pw_rand.java69
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/pwgen/pwgen.java138
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/pwgen/randnum.java26
4 files changed, 439 insertions, 0 deletions
diff --git a/app/src/main/java/com/zeapo/pwdstore/pwgen/pw_phonemes.java b/app/src/main/java/com/zeapo/pwdstore/pwgen/pw_phonemes.java
new file mode 100644
index 00000000..1b312232
--- /dev/null
+++ b/app/src/main/java/com/zeapo/pwdstore/pwgen/pw_phonemes.java
@@ -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;
+ }
+}
diff --git a/app/src/main/java/com/zeapo/pwdstore/pwgen/pw_rand.java b/app/src/main/java/com/zeapo/pwdstore/pwgen/pw_rand.java
new file mode 100644
index 00000000..1f4acdec
--- /dev/null
+++ b/app/src/main/java/com/zeapo/pwdstore/pwgen/pw_rand.java
@@ -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;
+ }
+}
diff --git a/app/src/main/java/com/zeapo/pwdstore/pwgen/pwgen.java b/app/src/main/java/com/zeapo/pwdstore/pwgen/pwgen.java
new file mode 100644
index 00000000..e08573f0
--- /dev/null
+++ b/app/src/main/java/com/zeapo/pwdstore/pwgen/pwgen.java
@@ -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;
+ }
+
+}
+
diff --git a/app/src/main/java/com/zeapo/pwdstore/pwgen/randnum.java b/app/src/main/java/com/zeapo/pwdstore/pwgen/randnum.java
new file mode 100644
index 00000000..83cf4b03
--- /dev/null
+++ b/app/src/main/java/com/zeapo/pwdstore/pwgen/randnum.java
@@ -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);
+ }
+}