/trunk/LockCrypt.Java/src/com/lime49/lockcrypt/FrmPWGen.java
Java | 507 lines | 483 code | 12 blank | 12 comment | 55 complexity | 8fcd24faa8fc972e68a5080f541c6ae2 MD5 | raw file
- package com.lime49.lockcrypt;
- import com.lime49.lockcrypt.ui.AbstractDialog;
- import com.lime49.lockcrypt.ui.GradientJPanel;
- import java.util.*;
- import javax.swing.*;
- import javax.swing.border.*;
- import java.awt.*;
- import java.awt.event.*;
- import java.awt.datatransfer.Clipboard;
- import java.awt.datatransfer.StringSelection;
- import java.security.NoSuchAlgorithmException;
- import java.net.URL;
- import java.security.SecureRandom;
- import java.text.MessageFormat;
- import javax.swing.event.ChangeEvent;
- import javax.swing.event.ChangeListener;
- import javax.swing.event.ListSelectionEvent;
- import javax.swing.event.ListSelectionListener;
-
- public class FrmPWGen extends AbstractDialog {
- private JButton btnGen, btnCopy, btnClose;
- private JList log;
- private DefaultListModel logModel;
- private JSpinner spnLength;
- private JCheckBox chkUppercase, chkLowercase, chkDigits, chkSpecial, chkBrackets, chkExtended, chkSpecialFormat;
- private JTextField txtSpecialFormat;
- private ResourceBundle lang;
- private Font boldFont;
- private String selectedPassword = "";
- private GradientJPanel pnlMaxEntropy, pnlSelectedEntropy;
- private JLabel lblMaxEntropyPWMeter, lblMaxEntropyBitStrength, lblSelectedEntropyPWMeter, lblSelectedEntropyBitStrength;
-
- private String DIGITS = "0123456789",
- LOWERCASE = "abcdefghijklmnopqrstuvwxyz",
- UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
- SPECIAL = "!\"£$€%^&*-_=+@#~?`/\\",
- BRACKETS = "()[]{}<>",
- EXTENDED;
-
- /**
- * Creates a Password Generator window, using the specified ResourceBundle for language strings
- * @param owner The parent dialog on which this dialog should be centered.
- * @param lang The ResourceBundle to use for languages
- */
- public FrmPWGen(JDialog owner, ResourceBundle lang) {
- super(owner, lang.getString("PWGEN"), true);
- this.init(lang);
- }
-
- /**
- * Creates a Password Generator window, using the specified ResourceBundle for language strings
- * @param owner The parent dialog on which this dialog should be centered.
- * @param lang The ResourceBundle to use for languages
- */
- public FrmPWGen(JFrame owner, ResourceBundle lang) {
- super(owner, lang.getString("PWGEN"), true);
- this.init(lang);
- }
-
-
- private void init(final ResourceBundle lang) {
- //TODO: move buttons to the bottom and add 'enable secure clipboard' checkbox
- this.lang = lang;
- StringBuffer buff = new StringBuffer(); // populate the extended characters list (mostly unprintable)
- for(int i=161;i<256;i++) {
- buff.append((char)i);
- }
- EXTENDED = buff.toString();
- KeyStroke escapeKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
- Action escapeAction = new AbstractAction() {
- // close the frame when the user presses escape
- public void actionPerformed(ActionEvent e) {
- thisDialog.dispose();
- }
- };
- this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(escapeKeyStroke, "ESCAPE");
- this.getRootPane().getActionMap().put("ESCAPE", escapeAction);
- this.setLayout(new BorderLayout());
- this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
- JPanel content = new JPanel();
- content.setLayout(new BoxLayout(content, BoxLayout.PAGE_AXIS));
- content.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
- this.setContentPane(content);
-
- GridBagConstraints c = new GridBagConstraints();
- c.insets = Constants.GLOBALINSETS;
- c.weighty = 1;
- int curY = 0;
-
- JPanel boxLength = new JPanel();
- content.add(boxLength);
- boxLength.setLayout(new BoxLayout(boxLength, BoxLayout.LINE_AXIS));
- JLabel lblLength = new JLabel(lang.getString("LENGTH"));
- boldFont = lblLength.getFont().deriveFont(Font.BOLD);
- lblLength.setFont(boldFont);
- lblLength.setLabelFor(spnLength);
- lblLength.setDisplayedMnemonic('e');
- boxLength.add(Box.createHorizontalStrut(100));
- boxLength.add(lblLength);
- boxLength.add(Box.createHorizontalStrut(10));
- SpinnerModel spnModel = new SpinnerNumberModel(8,1,511,1);
- spnLength = new JSpinner(spnModel);
- spnLength.setPreferredSize(new Dimension(50,20));
- spnLength.setMaximumSize(new Dimension(80,20));
- spnLength.addChangeListener(new ChangeListener() {
- public void stateChanged(ChangeEvent e) {
- calculateMaxEntropy();
- }
- });
- boxLength.add(spnLength);
- boxLength.add(Box.createHorizontalGlue());
-
- JPanel pnlInclude = new JPanel(new GridLayout(0,2,3,3));
- pnlInclude.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), lang.getString("PWGEN_POSSIBLECHARS")));
- pnlInclude.setFont(boldFont);
- content.add(pnlInclude);
- EntropyChangeListener entropyChangeListener = new EntropyChangeListener();
- MessageFormat fmtUppercase = new MessageFormat(lang.getString("PWGEN_UPPERCASE"));
- chkUppercase = new JCheckBox(fmtUppercase.format(new Object [] {"A-Z"}));
- chkUppercase.setMnemonic('U');
- chkUppercase.setSelected(true);
- chkUppercase.addItemListener(entropyChangeListener);
- pnlInclude.add(chkUppercase);
- MessageFormat fmtDigits = new MessageFormat(lang.getString("PWGEN_DIGITS"));
- chkDigits = new JCheckBox(fmtDigits.format(new Object [] {"0-9"}));
- chkDigits.setMnemonic('D');
- chkDigits.setSelected(true);
- chkDigits.addItemListener(entropyChangeListener);
- pnlInclude.add(chkDigits);
- MessageFormat fmtLowercase = new MessageFormat(lang.getString("PWGEN_LOWERCASE"));
- chkLowercase = new JCheckBox(fmtLowercase.format(new Object [] {"a-z"}));
- chkLowercase.setMnemonic('L');
- chkLowercase.setSelected(true);
- chkLowercase.addItemListener(entropyChangeListener);
- pnlInclude.add(chkLowercase);
- MessageFormat fmtBrackets = new MessageFormat(lang.getString("PWGEN_BRACKETS"));
- chkBrackets = new JCheckBox(fmtBrackets.format(new Object [] {" {},[],(), <> "}));
- chkBrackets.setMnemonic('B');
- chkBrackets.addItemListener(entropyChangeListener);
- pnlInclude.add(chkBrackets);
- chkExtended = new JCheckBox(lang.getString("PWGEN_EXTENDED"));
- chkExtended.setMnemonic('H');
- chkExtended.addItemListener(entropyChangeListener);
- pnlInclude.add(chkExtended);
- MessageFormat fmtSpecial = new MessageFormat(lang.getString("PWGEN_SPECIAL"));
- chkSpecial = new JCheckBox(fmtSpecial.format(new Object [] {"!,\",£,$,%,^", lang.getString("ETC")}));
- chkSpecial.setMnemonic('S');
- chkSpecial.addItemListener(entropyChangeListener);
- pnlInclude.add(chkSpecial);
-
- JPanel pnlFormat = new JPanel(new GridBagLayout());
- curY = 0;
- pnlFormat.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), lang.getString("PWGEN_SPECIALFORMAT")));
- content.add(pnlFormat);
- chkSpecialFormat = new JCheckBox(lang.getString("PWGEN_SPECIALFORMAT"));
- chkSpecialFormat.setBorder(BorderFactory.createLineBorder(Color.black));
- chkSpecialFormat.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- if(chkSpecialFormat.isSelected()) {
- txtSpecialFormat.setEnabled(true);
- txtSpecialFormat.setBackground(Color.white);
- } else {
- txtSpecialFormat.setEnabled(false);
- txtSpecialFormat.setBackground(Color.getHSBColor(0f, 0f, 0.87f));
- }
- }
- });
- Utils.setgrid(c,curY,0,1,1,GridBagConstraints.NONE,GridBagConstraints.NORTHWEST,0.8);
- pnlFormat.add(chkSpecialFormat,c);
- JButton btnSpecialFormatInfo = new JButton("");
- final ResourceBundle bundle = lang;
- btnSpecialFormatInfo.setToolTipText(lang.getString("INFORMATION"));
- btnSpecialFormatInfo.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- FrmPWGenSpecialFormat frm = new FrmPWGenSpecialFormat(thisDialog, bundle);
- frm.setLocation(thisDialog.getX() + ((thisDialog.getWidth() - frm.getWidth())/2), thisDialog.getY() + ((thisDialog.getHeight() - frm.getHeight())/2));
- frm.setVisible(true);
- }
- });
- btnSpecialFormatInfo.setHorizontalAlignment(SwingConstants.LEFT);
- try {
- ImageIcon icoName = new ImageIcon();
- URL URLicon = this.getClass().getResource("images/bulb_16.png");
- icoName.setImage(Toolkit.getDefaultToolkit().getImage(URLicon));
- btnSpecialFormatInfo.setIcon(icoName);
- } catch(Exception e) { }
- Utils.setgrid(c,curY,1,1,1,GridBagConstraints.NONE,GridBagConstraints.NORTHEAST,0.2);
- pnlFormat.add(btnSpecialFormatInfo,c);
- curY++;
- txtSpecialFormat = new JTextField(30);
- txtSpecialFormat.setEnabled(false);
- txtSpecialFormat.setBackground(Color.getHSBColor(0f, 0f, 0.87f));
- Utils.setgrid(c,curY,0,2,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.NORTHWEST,1);
- pnlFormat.add(txtSpecialFormat,c);
- curY++;
-
- Box pnlGeneratedPasswords = Box.createVerticalBox();
- pnlGeneratedPasswords.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), lang.getString("GENERATEDPASSWORDS")));
- content.add(pnlGeneratedPasswords);
- logModel = new DefaultListModel();
- log = new JList(logModel);
- log.addListSelectionListener(new ListSelectionListener() {
- public void valueChanged(ListSelectionEvent e) {
- if(!logModel.isEmpty()) {
- String selectedPassword = log.getSelectedValue().toString();
- int pwStrength = PWStrengthChecker.checkStrength(selectedPassword);
- lblSelectedEntropyPWMeter.setText(pwStrength+"% - "+PWStrengthChecker.getStrengthDescription(pwStrength, lang));
- PWStrengthChecker.setPanelGradient(pnlSelectedEntropy, pwStrength);
- lblSelectedEntropyBitStrength.setText(PWStrengthChecker.calculateBitStrength(selectedPassword)+" bits");
- }
- }
- });
- JScrollPane logScroll = new JScrollPane(log);
- log.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
- logScroll.setViewportBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
- logScroll.setBorder(BorderFactory.createEmptyBorder(3,3,3,3));
- pnlGeneratedPasswords.add(logScroll);
-
- JPanel pnlAnalysis = new JPanel(new GridBagLayout());
- pnlAnalysis.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), lang.getString("PWGEN_ANALYSIS")));
- JButton btnAnalysisInfo = new JButton("");
- btnAnalysisInfo.setToolTipText(lang.getString("INFORMATION"));
- btnAnalysisInfo.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- Utils.openURL("http://wiki.lime49.com/index.php?title=Password_Generator#Password_Analysis");
- }
- });
- btnAnalysisInfo.setHorizontalAlignment(SwingConstants.LEFT);
- try {
- ImageIcon icoName = new ImageIcon();
- URL URLicon = this.getClass().getResource("images/bulb_16.png");
- icoName.setImage(Toolkit.getDefaultToolkit().getImage(URLicon));
- btnAnalysisInfo.setIcon(icoName);
- } catch(Exception e) { }
- JLabel lblMaxEntropy = new JLabel(lang.getString("PWGEN_MAXENTROPY"));
- pnlMaxEntropy = new GradientJPanel(new BorderLayout());
- lblMaxEntropyPWMeter = new JLabel("");
- lblMaxEntropyBitStrength = new JLabel("");
- pnlMaxEntropy.setBorder(BorderFactory.createLineBorder(Color.black));
- JLabel lblSelectedEntropy = new JLabel(lang.getString("PWGEN_ENTROPYSELECTED"));
- pnlSelectedEntropy = new GradientJPanel(new BorderLayout());
- curY++;
- lblSelectedEntropyPWMeter = new JLabel(lang.getString("NONESELECTED"));
- lblSelectedEntropyBitStrength = new JLabel("");
- pnlSelectedEntropy.setBorder(BorderFactory.createLineBorder(Color.black));
- calculateMaxEntropy();
-
- content.add(pnlAnalysis);
- curY = 0;
- Utils.setgrid(c,curY,1,1,1,GridBagConstraints.NONE,GridBagConstraints.NORTHEAST,1);
- pnlAnalysis.add(btnAnalysisInfo,c);
- curY++;
- Utils.setgrid(c,curY,0,1,1,GridBagConstraints.NONE,GridBagConstraints.NORTHWEST,0.5);
- pnlAnalysis.add(lblMaxEntropy,c);
- Utils.setgrid(c,curY,1,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.NORTHEAST,1);
- pnlAnalysis.add(pnlMaxEntropy,c);
- pnlMaxEntropy.add(lblMaxEntropyPWMeter, BorderLayout.LINE_START);
- pnlMaxEntropy.add(lblMaxEntropyBitStrength, BorderLayout.LINE_END);
- curY++;
- Utils.setgrid(c,curY,0,1,1,GridBagConstraints.NONE,GridBagConstraints.NORTHWEST,0.5);
- pnlAnalysis.add(lblSelectedEntropy,c);
- Utils.setgrid(c,curY,1,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.NORTHEAST,1);
- pnlAnalysis.add(pnlSelectedEntropy,c);
- pnlSelectedEntropy.add(lblSelectedEntropyPWMeter, BorderLayout.LINE_START);
- pnlSelectedEntropy.add(lblSelectedEntropyBitStrength, BorderLayout.LINE_END);
-
- JPanel pnlButtons = new JPanel(new FlowLayout(FlowLayout.TRAILING));
- content.add(pnlButtons);
- pnlButtons.add(Box.createHorizontalGlue());
- btnGen = new JButton(lang.getString("PWGEN_GENERATE"));
- btnGen.setMnemonic('G');
- btnGen.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) { genPass(); }
- });
- btnGen.setMinimumSize(Constants.MINSIZE);
- btnGen.setMaximumSize(Constants.MAXSIZE);
- pnlButtons.add(btnGen);
- pnlButtons.add(Box.createHorizontalStrut(10));
- btnCopy = new JButton(lang.getString("COPY"));
- btnCopy.setMnemonic('C');
- btnCopy.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) { copyToClip(); }
- });
- btnCopy.setMinimumSize(Constants.MINSIZE);
- btnCopy.setMaximumSize(Constants.MAXSIZE);
- pnlButtons.add(btnCopy);
- pnlButtons.add(Box.createHorizontalStrut(10));
- btnClose = new JButton(lang.getString("OK"));
- btnClose.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- selectedPassword = log.getSelectedValue() == null ? "" : log.getSelectedValue().toString();
- thisDialog.dispose();
- }
- });
- btnClose.setMinimumSize(Constants.MINSIZE);
- btnClose.setMaximumSize(Constants.MAXSIZE);
- pnlButtons.add(btnClose);
-
- this.setMinimumSize(new Dimension(500,400));
- this.pack();
- }
-
- /**
- * Generates a password according to the selected checkboxes and length spinner
- */
- private void genPass() {
- if(ValidateInput()) {
- int passLength = (Integer)spnLength.getValue();
- StringBuffer chars = new StringBuffer();
- if(chkUppercase.isSelected()) {
- chars.append(UPPERCASE);
- }
- if(chkLowercase.isSelected()) {
- chars.append(LOWERCASE);
- }
- if(chkDigits.isSelected()) {
- chars.append(DIGITS);
- }
- if(chkSpecial.isSelected()) {
- chars.append(SPECIAL);
- }
- if(chkBrackets.isSelected()) {
- chars.append(BRACKETS);
- }
- if(chkExtended.isSelected()) { // 161-255
- chars.append(EXTENDED);
- }
- char[] possChars = chars.toString().toCharArray();
- int numPossChars = possChars.length;
- Random seed = null;
- try {
- seed = SecureRandom.getInstance("SHA1PRNG");
- } catch(NoSuchAlgorithmException e) {
- System.out.println("SHA1PRNG algorithm not found, using standard random generator");
- seed = new Random();
- }
- // Fisher-Yates shuffle
- for(int i=numPossChars-1;i>0;i--) {
- int pos = seed.nextInt(i);
- char temp = possChars[i];
- possChars[i] = possChars[pos];
- possChars[pos] = temp;
- }
- if(Constants.DEBUG) {
- System.out.println(possChars);
- }
- char[] pass = new char[passLength];
- if(chkSpecialFormat.isSelected()) {
- String format = txtSpecialFormat.getText();
- int i=0;
- while(i<passLength) {
- char proposed = possChars[seed.nextInt(numPossChars)];
- if(format.length() > i) {
- switch(format.charAt(i)) {
- case 'd':
- if(DIGITS.indexOf(proposed) >=0) {
- pass[i] = proposed;
- i++;
- }
- break;
- case 'c':
- if(LOWERCASE.indexOf(proposed) >=0) {
- pass[i] = proposed;
- i++;
- }
- break;
- case 'C':
- if(UPPERCASE.indexOf(proposed) >=0) {
- pass[i] = proposed;
- i++;
- }
- break;
- case 'b':
- if(BRACKETS.indexOf(proposed) >=0) {
- pass[i] = proposed;
- i++;
- }
- break;
- case 's':
- if(SPECIAL.indexOf(proposed) >=0) {
- pass[i] = proposed;
- i++;
- }
- break;
- case 'e':
- if(EXTENDED.indexOf(proposed) >=0) {
- pass[i] = proposed;
- i++;
- }
- default:
- pass[i] = proposed;
- i++;
- break;
- }
- } else {
- pass[i] = proposed;
- i++;
- }
- }
- } else {
- for(int i=0;i<passLength;i++) {
- pass[i] = possChars[seed.nextInt(numPossChars)];
- }
- }
-
- logModel.addElement(new String(pass));
- log.setSelectedIndex(logModel.getSize()-1);
- log.ensureIndexIsVisible(logModel.getSize()-1);
- }
- }
-
- private void calculateMaxEntropy() {
- int poolsize = 0;
- if(chkUppercase.isSelected()) {
- poolsize += 26;
- }
- if(chkLowercase.isSelected()) {
- poolsize += 26;
- }
- if(chkDigits.isSelected()) {
- poolsize += 10;
- }
- if(chkSpecial.isSelected()) {
- poolsize += 20;
- }
- if(chkBrackets.isSelected()) {
- poolsize += 8;
- }
- if(chkExtended.isSelected()) { // 161-255
- poolsize += 94;
- }
- double bitStrength = Math.log(Math.pow(poolsize, (Integer)spnLength.getValue())) / Math.log(2);
- int score = (int)((double)poolsize/184*100);
- lblMaxEntropyPWMeter.setText(score+"% - "+PWStrengthChecker.getStrengthDescription(score, lang));
- lblMaxEntropyBitStrength.setText((int)Math.round(bitStrength)+" bits");
- PWStrengthChecker.setPanelGradient(pnlMaxEntropy, score);
- lblMaxEntropyPWMeter.invalidate();
- lblMaxEntropyPWMeter.repaint();
- lblMaxEntropyPWMeter.revalidate();
- }
-
- private boolean ValidateInput() {
- boolean havePossible = false;
- if(chkSpecialFormat.isSelected()) {
- String format = txtSpecialFormat.getText();
- boolean haveDigits = (format.indexOf('d') >= 0),
- haveLowercase = (format.indexOf('c') >= 0),
- haveUppercase = (format.indexOf('C') >= 0),
- haveBrackets = (format.indexOf('b') >= 0),
- haveSpecial = (format.indexOf('s') >= 0),
- haveExtended = (format.indexOf('e') >= 0),
- haveAny = (format.indexOf('*') >= 0);
- if(format.length() > 0) {
- if(haveAny) {
- havePossible = true;
- } else {
- if(chkDigits.isSelected() && haveDigits) {
- havePossible = true;
- } else if(chkLowercase.isSelected() && haveLowercase) {
- havePossible = true;
- } else if(chkUppercase.isSelected() && haveUppercase) {
- havePossible = true;
- } else if(chkBrackets.isSelected() && haveBrackets) {
- havePossible = true;
- } else if(chkSpecial.isSelected() && haveSpecial) {
- havePossible = true;
- } else if(chkExtended.isSelected() && haveExtended) {
- havePossible = true;
- }
- }
- }
- if(!havePossible) {
- JOptionPane.showMessageDialog(this, lang.getString("ERR_PWGEN_NOELIGIBLEFORMAT"), lang.getString("ERROR"), JOptionPane.ERROR_MESSAGE);
- }
- } else {
- if(chkDigits.isSelected() || chkLowercase.isSelected()|| chkUppercase.isSelected()|| chkBrackets.isSelected() || chkSpecial.isSelected() || chkExtended.isSelected()) {
- havePossible = true;
- } else {
- JOptionPane.showMessageDialog(this, lang.getString("ERR_PWGEN_NOELIGIBLE"), lang.getString("ERROR"), JOptionPane.ERROR_MESSAGE);
- }
- }
- return havePossible;
- }
-
- /**
- * Returns the selected password, or an empty string if none is selected
- * @return The selected password, or an empty string if none is selected
- */
- public String getSelectedPassword() {
- return selectedPassword;
- }
-
- /**
- * Copys the selected password to the clipboard
- */
- private void copyToClip() {
- //TODO: add secure clipboard, disable button when list empty
- Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
- clipboard.setContents(new StringSelection((String)log.getSelectedValue()), null);
- }
-
- private class EntropyChangeListener implements ItemListener {
- public void itemStateChanged(ItemEvent e) {
- calculateMaxEntropy();
- }
- }
- }