diff --git a/pom.xml b/pom.xml
index 587dfec..c9abe07 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,25 +40,6 @@
-
- maven-antrun-plugin
- 1.8
-
-
- install
-
-
-
-
-
-
-
-
- run
-
-
-
-
diff --git a/src/pwgen/BitsPasswordJPanel.java b/src/pwgen/BitsPasswordJPanel.java
index 570ccf6..88b6adb 100644
--- a/src/pwgen/BitsPasswordJPanel.java
+++ b/src/pwgen/BitsPasswordJPanel.java
@@ -5,6 +5,8 @@
import javax.swing.*;
+import static pwgen.PwUtil.*;
+
public class BitsPasswordJPanel extends PasswordJPanel {
private final JSpinner bitsSpinner = new JSpinner(new SpinnerNumberModel(8, 8, 4096, 8));
@@ -20,25 +22,25 @@ public BitsPasswordJPanel () {
protected void loadPrefs () throws Exception {
System.out.println("load prefs");
Preferences prefs = Preferences.userNodeForPackage(getClass());
- bitsSpinner.setValue(Integer.valueOf(prefs.getInt("bits", 64)));
- b64CheckBox.setSelected(prefs.getBoolean("b64", true));
+ bitsSpinner.setValue(Integer.valueOf(prefs.getInt("btbits", 64)));
+ b64CheckBox.setSelected(prefs.getBoolean("btb64", true));
}
@Override
protected void savePrefs () throws Exception {
System.out.println("save prefs");
Preferences prefs = Preferences.userNodeForPackage(getClass());
- prefs.putInt("bits", ((Number) bitsSpinner.getValue()).intValue());
- prefs.putBoolean("any", b64CheckBox.isSelected());
+ prefs.putInt("btbits", ((Number) bitsSpinner.getValue()).intValue());
+ prefs.putBoolean("btb64", b64CheckBox.isSelected());
prefs.flush();
}
@Override
- public String generate () {
+ public void generate () {
StringBuilder sb = new StringBuilder();
- int bits = ((Number) bitsSpinner.getValue()).intValue();
- sb.append(bits(bits, b64CheckBox.isSelected()));
+ int b = intValue(bitsSpinner);
+ sb.append(bits(b, b64CheckBox.isSelected()));
Collections.shuffle(new StringBuilderList(sb), RANDOM);
- return sb.toString();
+ setValue(sb.toString(), Math.pow(2, b));
}
}
diff --git a/src/pwgen/CharPasswordJPanel.java b/src/pwgen/CharPasswordJPanel.java
index 896cbf8..e0b2651 100644
--- a/src/pwgen/CharPasswordJPanel.java
+++ b/src/pwgen/CharPasswordJPanel.java
@@ -5,6 +5,8 @@
import javax.swing.*;
+import static pwgen.PwUtil.*;
+
public class CharPasswordJPanel extends PasswordJPanel {
private final JSpinner lowerSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 99, 1));
@@ -12,6 +14,8 @@ public class CharPasswordJPanel extends PasswordJPanel {
private final JSpinner digitSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 99, 1));
private final JSpinner punctSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 99, 1));
private final JSpinner anySpinner = new JSpinner(new SpinnerNumberModel(0, 0, 99, 1));
+ private final JCheckBox shuffleBox = new JCheckBox("Shuffle");
+
public CharPasswordJPanel () {
optionPanel.add(new JLabel("Upper"));
@@ -24,40 +28,54 @@ public CharPasswordJPanel () {
optionPanel.add(punctSpinner);
optionPanel.add(new JLabel("Any"));
optionPanel.add(anySpinner);
+ optionPanel.add(shuffleBox);
}
@Override
protected void loadPrefs () throws Exception {
System.out.println("load prefs");
Preferences prefs = Preferences.userNodeForPackage(getClass());
- lowerSpinner.setValue(prefs.getInt("lower", 6));
- upperSpinner.setValue(prefs.getInt("upper", 1));
- digitSpinner.setValue(prefs.getInt("digitx", 1));
- punctSpinner.setValue(prefs.getInt("punct", 0));
- anySpinner.setValue(prefs.getInt("any", 0));
+ lowerSpinner.setValue(prefs.getInt("chlower", 5));
+ upperSpinner.setValue(prefs.getInt("chupper", 1));
+ digitSpinner.setValue(prefs.getInt("chdigit", 1));
+ punctSpinner.setValue(prefs.getInt("chpunct", 1));
+ anySpinner.setValue(prefs.getInt("chany", 0));
+ shuffleBox.setSelected(prefs.getBoolean("chshuf", true));
}
@Override
protected void savePrefs () throws Exception {
System.out.println("save prefs");
Preferences prefs = Preferences.userNodeForPackage(getClass());
- prefs.putInt("upper", (Integer) upperSpinner.getValue());
- prefs.putInt("lower", (Integer) lowerSpinner.getValue());
- prefs.putInt("digitx", (Integer) digitSpinner.getValue());
- prefs.putInt("punct", (Integer) punctSpinner.getValue());
- prefs.putInt("any", (Integer) anySpinner.getValue());
+ prefs.putInt("chupper", (Integer) upperSpinner.getValue());
+ prefs.putInt("chlower", (Integer) lowerSpinner.getValue());
+ prefs.putInt("chdigit", (Integer) digitSpinner.getValue());
+ prefs.putInt("chpunct", (Integer) punctSpinner.getValue());
+ prefs.putInt("chany", (Integer) anySpinner.getValue());
+ prefs.putBoolean("chshuf", shuffleBox.isSelected());
prefs.flush();
}
@Override
- public String generate () {
+ public void generate () {
StringBuilder sb = new StringBuilder();
- sb.append(upper((Integer) upperSpinner.getValue()));
- sb.append(lower((Integer) lowerSpinner.getValue()));
- sb.append(digit((Integer) digitSpinner.getValue()));
- sb.append(punct((Integer) punctSpinner.getValue()));
- sb.append(any((Integer) anySpinner.getValue()));
- Collections.shuffle(new StringBuilderList(sb), RANDOM);
- return sb.toString();
+ int u = intValue(upperSpinner);
+ int l = intValue(lowerSpinner);
+ int d = intValue(digitSpinner);
+ int p = intValue(punctSpinner);
+ int a = intValue(anySpinner);
+ sb.append(upper(u));
+ sb.append(lower(l));
+ sb.append(digit(d));
+ sb.append(punct(p));
+ sb.append(any(a));
+ double v = pow(26, u + l) + pow(10, d) + pow(PUNCT, p) + pow(ANY, a);
+ System.out.println("v=" + v);
+ if (shuffleBox.isSelected()) {
+ Collections.shuffle(new StringBuilderList(sb), RANDOM);
+ double f = fac(sb.length()) / (fac(u)*fac(l)*fac(d)*fac(p)*fac(a));
+ v = v * f;
+ }
+ setValue(sb.toString(), v);
}
}
diff --git a/src/pwgen/DictPasswordJPanel.java b/src/pwgen/DictPasswordJPanel.java
index 86a62cf..9d7ecd5 100644
--- a/src/pwgen/DictPasswordJPanel.java
+++ b/src/pwgen/DictPasswordJPanel.java
@@ -8,18 +8,32 @@
import javax.swing.*;
+import static pwgen.PwUtil.*;
+
public class DictPasswordJPanel extends PasswordJPanel {
-
- private static final int MAX = 8;
- private static final int MIN = 4;
+
+ private static final int MIN = 3;
+ private static final int MAX = 13;
+ private static Comparator> LI_CMP = new Comparator>() {
+ @Override
+ public int compare(List l1, List l2) {
+ int c = l1.size() - l2.size();
+ for (int n = 0; c == 0 && n < l1.size(); n++) {
+ c = l1.get(Integer.valueOf(n)) - l2.get(Integer.valueOf(n));
+ }
+ return c;
+ }
+ };
private final JLabel fileLabel = new JLabel();
private final JButton fileButton = new JButton("File...");
private final JSpinner wordSpinner = new JSpinner(new SpinnerNumberModel(8, 0, 99, 1));
private final JSpinner digitSpinner = new JSpinner(new SpinnerNumberModel(1, 0, 99, 1));
private final JSpinner punctSpinner = new JSpinner(new SpinnerNumberModel(1, 0, 99, 1));
- private final SortedMap> dict = new TreeMap<>();
+ /** map of word length to list of words */
+ private final SortedMap> dict = new TreeMap<>();
private final JCheckBox titleBox = new JCheckBox("Title");
+ private final JCheckBox shuffleBox = new JCheckBox("Shuffle");
private File file;
@@ -36,6 +50,7 @@ public DictPasswordJPanel () {
optionPanel.add(new JLabel("Punct"));
optionPanel.add(punctSpinner);
optionPanel.add(titleBox);
+ optionPanel.add(shuffleBox);
}
private void file () {
@@ -50,7 +65,7 @@ private void file () {
}
private void loadfile () {
- dict.clear();
+ Map> dictset = new TreeMap<>();
Pattern p = Pattern.compile("[a-z]+");
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) {
String l;
@@ -58,23 +73,28 @@ private void loadfile () {
// try to avoid poor quality words
l = l.trim().toLowerCase();
if (p.matcher(l).matches() && l.length() >= MIN && l.length() <= MAX) {
- dict.compute(l.length(), (k,v) -> v != null ? v : new TreeSet<>()).add(l);
+ dictset.computeIfAbsent(l.length(), k -> new TreeSet<>()).add(l);
}
}
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(this, e.toString());
}
+ dict.clear();
+ for (Map.Entry> e : dictset.entrySet()) {
+ dict.put(e.getKey(), new ArrayList<>(e.getValue()));
+ }
}
@Override
protected void loadPrefs () {
Preferences prefs = Preferences.userNodeForPackage(getClass());
- wordSpinner.setValue(prefs.getInt("len", 7));
- digitSpinner.setValue(prefs.getInt("digit", 1));
- punctSpinner.setValue(prefs.getInt("punct", 1));
- titleBox.setSelected(prefs.getBoolean("title", false));
- String f = prefs.get("file", "");
+ wordSpinner.setValue(prefs.getInt("dclen", 6));
+ digitSpinner.setValue(prefs.getInt("dcdigit", 1));
+ punctSpinner.setValue(prefs.getInt("dcpunct", 1));
+ titleBox.setSelected(prefs.getBoolean("dctitle", true));
+ shuffleBox.setSelected(prefs.getBoolean("dcshuf", true));
+ String f = prefs.get("dcfile", "");
System.out.println("loaded file pref " + f);
if (f.length() > 0) {
file = new File(f);
@@ -85,113 +105,127 @@ protected void loadPrefs () {
@Override
protected void savePrefs () throws Exception {
Preferences prefs = Preferences.userNodeForPackage(getClass());
- prefs.putInt("len", (Integer) wordSpinner.getValue());
- prefs.putInt("digit", (Integer) digitSpinner.getValue());
- prefs.putInt("punct", (Integer) punctSpinner.getValue());
- prefs.putBoolean("title", titleBox.isSelected());
+ prefs.putInt("dclen", (Integer) wordSpinner.getValue());
+ prefs.putInt("dcdigit", (Integer) digitSpinner.getValue());
+ prefs.putInt("dcpunct", (Integer) punctSpinner.getValue());
+ prefs.putBoolean("dctitle", titleBox.isSelected());
+ prefs.putBoolean("dcshuf", shuffleBox.isSelected());
if (file != null) {
System.out.println("save file pref " + file.getAbsolutePath());
- prefs.put("file", file.getAbsolutePath());
+ prefs.put("dcfile", file.getAbsolutePath());
}
prefs.sync();
}
+
+ private Set> partitions(int n, int s) {
+ Set> out = new TreeSet<>(LI_CMP);
+ if (n == 1 && s >= MIN && s <= MAX) {
+ out.add(Arrays.asList(Integer.valueOf(s)));
+ } else if (n > 1 && s >= MIN) {
+ for (int i = MIN; i < MAX; i++) {
+ for (List j : partitions(n - 1, s - i)) {
+ out.add(join(j, i));
+ }
+ }
+ }
+ return out.size() > 0 ? out : Collections.emptySet();
+ }
+
+ private List join (List l, int i) {
+ List l2 = new ArrayList<>();
+ l2.addAll(l);
+ l2.add(i);
+ Collections.sort(l2);
+ return l2;
+ }
+
+ private Long dictproduct(List x) {
+ long v = 1;
+ for (Integer i : x) {
+ List s = dict.get(i);
+ v = v * (s != null ? s.size() : 0);
+ }
+ return Long.valueOf(v);
+ }
+
+ private long sum (List l) {
+ long v = 0;
+ for (Long x : l) {
+ v = v + x;
+ }
+ return v;
+ }
@Override
- public String generate () {
+ public void generate () {
if (dict.size() == 0) {
loadfile();
}
-
+
if (dict.size() == 0) {
JOptionPane.showMessageDialog(this, "No words in dictionary");
- return "";
- }
-
- List parts = new ArrayList<>();
-
- {
- int len = ((Integer)wordSpinner.getValue()).intValue();
-
- List seq = seq(len);
- if (seq == null) {
- JOptionPane.showMessageDialog(this, "Could not sequence");
- return "";
- }
-
- for (int x : seq) {
- Set s = dict.get(x);
- if (s != null && s.size() > 0) {
- String[] a = s.toArray(new String[s.size()]);
- String word = a[RANDOM.nextInt(a.length)];
- if (titleBox.isSelected()) {
- word = word.substring(0, 1).toUpperCase() + word.substring(1);
- }
- parts.add(word);
- }
- }
+ return;
}
-
- {
- int dig = ((Integer)digitSpinner.getValue()).intValue();
- if (dig > 0) {
- parts.add(digit(dig));
+
+ List list = new ArrayList<>();
+
+ int wordlen = intValue(wordSpinner);
+ List> plist = new ArrayList<>();
+ List pcounts = new ArrayList<>();
+ for (int n = 1; n < (wordlen / MIN); n++) {
+ Set> pset = partitions(n, wordlen);
+ //System.out.println("parts(" + n + ")=" + pset);
+ for (List p : pset) {
+ plist.add(p);
+ pcounts.add(dictproduct(p));
+ //System.out.println("part=" + p + " prod(p)=" + dictproduct(p));
}
}
-
+
+ long ptotal = sum(pcounts);
+ int words = 0;
+ System.out.println("ptotal=" + ptotal);
+
{
- int pun = ((Integer)punctSpinner.getValue()).intValue();
- if (pun > 0) {
- parts.add(punct(pun));
+ long index = (RANDOM.nextLong() >>> 1) % ptotal;
+ long sum = 0;
+ for (int n = 0; n < pcounts.size(); n++) {
+ sum = sum + pcounts.get(n);
+ if (sum >= index) {
+ List p = plist.get(n);
+ words = p.size();
+ Collections.shuffle(p, RANDOM);
+ for (Integer i : p) {
+ String word = randomItem(dict.get(i));
+ if (titleBox.isSelected()) {
+ word = word.substring(0, 1).toUpperCase() + word.substring(1);
+ }
+ list.add(word);
+ }
+ break;
+ }
}
}
-
- Collections.shuffle(parts, RANDOM);
- return String.join("", parts);
- }
-
- private List seq (int len) {
-
- List> seqs = new ArrayList<>();
-
- if (dict.keySet().contains(len)) {
- seqs.add(Arrays.asList(len));
- }
-
- if (seqs.size() == 0 || len >= MAX) {
- List seq = sumseq(len);
- if (seq != null) {
- seqs.add(seq);
- }
+
+ int dig = intValue(digitSpinner);
+ if (dig > 0) {
+ list.add(digit(dig));
}
-
- return seqs.size() > 0 ? seqs.get(RANDOM.nextInt(seqs.size())) : null;
- }
-
- private List sumseq (int len) {
- // add sizes to list
- // shuffle list
- // pick a subset...
- Integer[] keys = dict.keySet().toArray(new Integer[dict.size()]);
- List seq = new ArrayList<>();
- for (int n = 0; n < keys.length; n++) {
- if (keys[n] <= len - MIN) {
- for (int m = 0; m < len - MIN; m++) {
- seq.add(keys[n]);
- }
- }
+
+ int pun = intValue(punctSpinner);
+ if (pun > 0) {
+ list.add(punct(pun));
}
-// System.out.println("seq=" + seq);
- for (int n = 0; n < 100; n++) {
- Collections.shuffle(seq, RANDOM);
- int sum = 0;
- for (int m = 0; m < seq.size() && sum < len; m++) {
- sum += seq.get(m);
- if (sum == len) {
-// System.out.println("n=" + n);
- return new ArrayList<>(seq.subList(0, m + 1));
- }
- }
+
+ double space = ptotal + pow(10, dig) + pow(PUNCT, pun);
+
+ if (shuffleBox.isSelected()) {
+ Collections.shuffle(list, RANDOM);
+ double f = fac(list.size()) / (fac(words)*fac(dig)*fac(pun));
+ space = space * f;
}
- return null;
+
+ setValue(String.join("", list), space);
}
+
}
diff --git a/src/pwgen/PasswordJPanel.java b/src/pwgen/PasswordJPanel.java
index e8aff03..caf5125 100644
--- a/src/pwgen/PasswordJPanel.java
+++ b/src/pwgen/PasswordJPanel.java
@@ -1,22 +1,20 @@
package pwgen;
-import java.awt.Font;
-import java.awt.GridLayout;
-import java.awt.Toolkit;
+import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
-import java.security.SecureRandom;
-import java.util.Base64;
import javax.swing.*;
public abstract class PasswordJPanel extends JPanel {
-
- protected static final SecureRandom RANDOM = new SecureRandom();
-
+
+ private static final Font FONT = new Font("monospaced", Font.PLAIN, 16);
+
protected final JPanel optionPanel = new JPanel();
private final JTextField textField = new JTextField();
+ private final JLabel bitsLabel = new JLabel("Bits");
+ private final JTextField bitsField = new JTextField();
private final JButton generateButton = new JButton("Generate");
private final JButton copyButton = new JButton("Copy");
@@ -24,18 +22,44 @@ public PasswordJPanel () {
super(new GridLayout(2, 1));
setBorder(BorderFactory.createEmptyBorder());
- textField.setColumns(32);
- textField.setFont(new Font("monospaced", Font.PLAIN, 16));
- textField.setBorder(BorderFactory.createEtchedBorder());
-
- generateButton.addActionListener(e -> textField.setText(generate()));
+ textField.setFont(FONT);
+
+ bitsField.setFont(FONT);
+ bitsField.setEditable(false);
+ bitsField.setColumns(4);
+
+ generateButton.addActionListener(e -> generate());
copyButton.addActionListener(e -> copy());
- JPanel buttonPanel = new JPanel();
- buttonPanel.add(textField);
- buttonPanel.add(generateButton);
- buttonPanel.add(copyButton);
+ JPanel buttonPanel = new JPanel(new GridBagLayout());
+
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = 0;
+ c.insets = new Insets(5,5,5,5);
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 4;
+ c.weighty = 1;
+ buttonPanel.add(textField, c);
+
+ c.gridx++;
+ c.fill = GridBagConstraints.NONE;
+ c.weightx = 0;
+ buttonPanel.add(bitsLabel, c);
+
+ c.gridx++;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 0;
+ buttonPanel.add(bitsField, c);
+
+ c.gridx++;
+ c.fill = GridBagConstraints.NONE;
+ c.weightx = 0;
+ buttonPanel.add(generateButton, c);
+
+ c.gridx++;
+ buttonPanel.add(copyButton, c);
add(optionPanel);
add(buttonPanel);
@@ -46,88 +70,15 @@ private void copy () {
clip.setContents(new StringSelection(textField.getText()), null);
}
- protected abstract String generate();
+ protected abstract void generate();
+
+ protected void setValue (String pass, double size) {
+ textField.setText(pass);
+ bitsField.setText(size > 0 ? Integer.toString(PwUtil.log2(size)) : "");
+ }
protected abstract void loadPrefs () throws Exception;
protected abstract void savePrefs () throws Exception;
-
- /**
- * return a printable ascii character
- */
- protected String any (int max) {
- StringBuilder sb = new StringBuilder();
- for (int n = 0; n < max; n++) {
- // don't include 0x7f (delete)
- // but do include space
- char c = (char) (RANDOM.nextInt(95) + 32);
- sb.append(c);
- }
- return sb.toString();
- }
-
- protected String lower (int max) {
- StringBuilder sb = new StringBuilder();
- for (int n = 0; n < max; n++) {
- char c = (char) ('a' + RANDOM.nextInt(26));
- sb.append(c);
- }
- return sb.toString();
- }
-
- protected String upper (int max) {
- StringBuilder sb = new StringBuilder();
- for (int n = 0; n < max; n++) {
- char c = (char) ('A' + RANDOM.nextInt(26));
- sb.append(c);
- }
- return sb.toString();
- }
-
- protected String digit (int max) {
- StringBuilder sb = new StringBuilder();
- for (int n = 0; n < max; n++) {
- char c = (char) ('0' + RANDOM.nextInt(10));
- sb.append(c);
- }
- return sb.toString();
- }
-
- protected String punct (int max) {
- StringBuilder sb = new StringBuilder();
- for (int n = 0; n < max; n++) {
- while (true) {
- char c = (char) (RANDOM.nextInt(95) + 32);
- if (!Character.isLetterOrDigit(c) && !Character.isWhitespace(c)) {
- sb.append(c);
- break;
- }
- }
- }
- return sb.toString();
- }
-
- protected String hex (int max) {
- StringBuilder sb = new StringBuilder();
- for (int n = 0; n < max; n++) {
- sb.append(Integer.toHexString(RANDOM.nextInt(16)));
- }
- return sb.toString();
- }
-
- protected String bits (int bits, boolean b64) {
- byte[] a = new byte[bits/8];
- RANDOM.nextBytes(a);
- if (b64) {
- return Base64.getEncoder().encodeToString(a);
- } else {
- StringBuilder sb = new StringBuilder();
- for (int n = 0; n < a.length; n++) {
- byte b = a[n];
- sb.append(Integer.toHexString(b&0xf)).append(Integer.toHexString((b>>4)&0xf));
- }
- return sb.toString();
- }
- }
-
+
}
diff --git a/src/pwgen/PwUtil.java b/src/pwgen/PwUtil.java
new file mode 100644
index 0000000..3892c77
--- /dev/null
+++ b/src/pwgen/PwUtil.java
@@ -0,0 +1,150 @@
+package pwgen;
+
+import javax.swing.*;
+import java.security.SecureRandom;
+import java.util.Base64;
+
+public class PwUtil {
+
+ protected static final SecureRandom RANDOM = new SecureRandom();
+ protected static final int PUNCT = punctCount();
+ protected static final int ANY = 126 - 33;
+
+ public static int intValue(JSpinner s) {
+ return ((Number) s.getValue()).intValue();
+ }
+
+ /** generate random integer in range */
+ public static int randomInt (int greaterThanOrEqual, int lessThan) {
+ return RANDOM.nextInt(lessThan - greaterThanOrEqual) + greaterThanOrEqual;
+ }
+
+ /** return x to the power of y */
+ public static double pow (int x, int y) {
+ return Math.pow(x, y);
+ }
+
+ /** return log2 of v */
+ public static int log2 (double v) {
+ return (int) (Math.log(v) / Math.log(2));
+ }
+
+ /** return factorial of i */
+ public static double fac (int i) {
+ double v = 1;
+ for (int n = 1; n <= i; n++) {
+ v = v * n;
+ }
+ return v;
+ }
+
+ private static int punctCount() {
+ int c = 0;
+ for (int n = 32; n < 127; n++) {
+ char ch = (char) n;
+ if (!Character.isWhitespace(ch) && !Character.isLetterOrDigit(ch)) {
+ c++;
+ }
+ }
+ return c;
+ }
+
+ /** pick random item from list */
+ public static T randomItem(java.util.List l) {
+ return l.get(RANDOM.nextInt(l.size()));
+ }
+
+ /**
+ * return a sequence of any ascii characters
+ */
+ public static String any (int count) {
+ StringBuilder sb = new StringBuilder();
+ for (int n = 0; n < count; n++) {
+ // don't include 0x7f (delete) or space
+ char c = (char) randomInt(33, 127);
+ sb.append(c);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * return string of lowercase ascii characters
+ */
+ public static String lower (int count) {
+ StringBuilder sb = new StringBuilder();
+ for (int n = 0; n < count; n++) {
+ char c = (char) ('a' + RANDOM.nextInt(26));
+ sb.append(c);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * return string of uppercase ascii characters
+ */
+ public static String upper (int count) {
+ StringBuilder sb = new StringBuilder();
+ for (int n = 0; n < count; n++) {
+ char c = (char) ('A' + RANDOM.nextInt(26));
+ sb.append(c);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * return string of decimal ascii characters
+ */
+ public static String digit (int count) {
+ StringBuilder sb = new StringBuilder();
+ for (int n = 0; n < count; n++) {
+ char c = (char) ('0' + RANDOM.nextInt(10));
+ sb.append(c);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * return string of punctuation ascii characters
+ */
+ public static String punct (int count) {
+ StringBuilder sb = new StringBuilder();
+ for (int n = 0; n < count; n++) {
+ while (true) {
+ char c = (char) randomInt(33, 127);
+ if (!Character.isLetterOrDigit(c) && !Character.isWhitespace(c)) {
+ sb.append(c);
+ break;
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+ public static String hex (int max) {
+ StringBuilder sb = new StringBuilder();
+ for (int n = 0; n < max; n++) {
+ sb.append(Integer.toHexString(RANDOM.nextInt(16)));
+ }
+ return sb.toString();
+ }
+
+ /** generate random bits as hex or base64 string */
+ public static String bits (int bits, boolean b64) {
+ byte[] a = new byte[bits/8];
+ RANDOM.nextBytes(a);
+ if (b64) {
+ return Base64.getEncoder().encodeToString(a);
+ } else {
+ StringBuilder sb = new StringBuilder();
+ for (int n = 0; n < a.length; n++) {
+ byte b = a[n];
+ sb.append(Integer.toHexString(b&0xf)).append(Integer.toHexString((b>>4)&0xf));
+ }
+ return sb.toString();
+ }
+ }
+
+ private PwUtil() {
+
+ }
+}
diff --git a/src/pwgen/WordPasswordJPanel.java b/src/pwgen/WordPasswordJPanel.java
index f70499c..532524b 100644
--- a/src/pwgen/WordPasswordJPanel.java
+++ b/src/pwgen/WordPasswordJPanel.java
@@ -7,11 +7,14 @@
import javax.swing.*;
+import static pwgen.PwUtil.*;
+
public class WordPasswordJPanel extends PasswordJPanel {
private final JSpinner wordSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 99, 1));
private final JSpinner digitSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 99, 1));
private final JCheckBox titleBox = new JCheckBox("Title");
+ private final JCheckBox shuffleBox = new JCheckBox("Shuffle");
public WordPasswordJPanel () {
optionPanel.add(new JLabel("Word"));
@@ -19,39 +22,44 @@ public WordPasswordJPanel () {
optionPanel.add(new JLabel("Digit"));
optionPanel.add(digitSpinner);
optionPanel.add(titleBox);
+ optionPanel.add(shuffleBox);
}
@Override
protected void loadPrefs () {
Preferences prefs = Preferences.userNodeForPackage(getClass());
- wordSpinner.setValue(prefs.getInt("words", 7));
- digitSpinner.setValue(prefs.getInt("digit", 1));
- titleBox.setSelected(prefs.getBoolean("title", false));
+ wordSpinner.setValue(prefs.getInt("wdwords", 7));
+ digitSpinner.setValue(prefs.getInt("wddigit", 1));
+ titleBox.setSelected(prefs.getBoolean("wdtitle", true));
+ shuffleBox.setSelected(prefs.getBoolean("wdshuf", false));
}
@Override
protected void savePrefs () throws Exception {
Preferences prefs = Preferences.userNodeForPackage(getClass());
- prefs.putInt("words", (Integer) wordSpinner.getValue());
- prefs.putInt("digit", (Integer) digitSpinner.getValue());
- prefs.putBoolean("title", titleBox.isSelected());
+ prefs.putInt("wdwords", (Integer) wordSpinner.getValue());
+ prefs.putInt("wddigit", (Integer) digitSpinner.getValue());
+ prefs.putBoolean("wdtitle", titleBox.isSelected());
+ prefs.putBoolean("wdshuf", shuffleBox.isSelected());
prefs.sync();
}
@Override
- public String generate () {
+ public void generate () {
List list = new ArrayList<>();
int word = ((Integer) wordSpinner.getValue()).intValue();
int digit = ((Integer) digitSpinner.getValue()).intValue();
list.add(word(word, titleBox.isSelected()));
list.add(digit(digit));
- Collections.shuffle(list, RANDOM);
+ if (shuffleBox.isSelected()) {
+ Collections.shuffle(list, RANDOM);
+ }
StringBuilder sb = new StringBuilder();
for (String s : list) {
sb.append(s);
}
- return sb.toString();
+ setValue(sb.toString(), 0);
}
protected String word (int len, boolean title) {