/* * CreateKeyStoreDialog.java * * * ==================================================== Professional Data Security (PDS) http://crypto.brettlee.com ==================================================== Copyright (c) 2009-2011, Brett Lee All rights reserved. Portions Copyright (C) 1995-2008, Sun Microsystems, Inc. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the ORGANIZATION nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ============================================================================= */ package com.brettlee.crypto; import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.io.File; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.ButtonGroup; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JRadioButton; import javax.swing.JTextField; import javax.swing.border.TitledBorder; import javax.swing.filechooser.FileNameExtensionFilter; /** * CreateKeyStoreDialog - File-> New-> KeyStore "Dialog" * */ class CreateKeyStoreDialog { /** * */ private Gui mGui; JDialog createKeyStoreDialog; final JTextField keyStoreNameField = new JTextField("", 20); final JRadioButton jksButton = new JRadioButton("JKS", false); final JRadioButton jceksButton = new JRadioButton("JCEKS" , true); final ButtonGroup keyStoreType = new ButtonGroup(); final JPasswordField pw1 = new JPasswordField(15); final JPasswordField pw2 = new JPasswordField(15); String newline = System.getProperty("line.separator"); public CreateKeyStoreDialog (Gui theGui) { ///////////////////////////////////////////////////////////// // Build the Dialog mGui = theGui; createKeyStoreDialog = new JDialog(mGui.mainFrame, "Create a New KeyStore", true); JPanel contentPane = new JPanel(); GroupLayout layout = new GroupLayout(contentPane); contentPane.setLayout(layout); layout.setAutoCreateGaps(true); layout.setAutoCreateContainerGaps(true); createKeyStoreDialog.add(contentPane); FlowLayout flowLayoutLeft = new FlowLayout(); flowLayoutLeft.setAlignment(FlowLayout.LEFT); JPanel p1 = new JPanel(); JPanel p2 = new JPanel( flowLayoutLeft ); JPanel p3 = new JPanel( flowLayoutLeft ); JPanel p4 = new JPanel( new GridLayout(0,1) ); JPanel p5 = new JPanel(); layout.setHorizontalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(p1) .addComponent(p2) .addComponent(p3) .addComponent(p4) .addComponent(p5) ) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(p1) .addComponent(p2) .addComponent(p3) .addComponent(p4) .addComponent(p5) ); ///////////////////////////////////////////////////////////// // p1 - Title JLabel jlabel = new JLabel("Create a New KeyStore"); p1.add(jlabel); // p2 - KeyStore name JPanel p2SubPanel = new JPanel(new FlowLayout()); p2.add(p2SubPanel); p2.setBorder(new TitledBorder("KeyStore Name")); JLabel p2Label = new JLabel("What should we name this KeyStore: "); p2SubPanel.add(p2Label); p2SubPanel.add(keyStoreNameField); keyStoreNameField.setEnabled(true); JButton iconOpen = new JButton(Gui.createImageIcon("images/folder.gif", 28)); iconOpen.setFocusable(false); Gui.enterPressesWhenFocused(iconOpen); iconOpen.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { openMenuItemActionPerformed(evt); } }); iconOpen.setToolTipText("Open"); p2SubPanel.add(iconOpen); // p3 - KeyStore type p3.setBorder(new TitledBorder("KeyStore Type")); JLabel p3Label = new JLabel("Select the type of KeyStore to create: "); p3.add(p3Label, BorderLayout.WEST ); jksButton.setEnabled(false); keyStoreType.add(jceksButton); keyStoreType.add(jksButton); p3.add( jksButton, BorderLayout.WEST); p3.add( jceksButton, BorderLayout.WEST); // p4 - KeyStore passphrase JPanel p4SubPanel2a = new JPanel(flowLayoutLeft); p4.add(p4SubPanel2a); JPanel p4SubPanel2b = new JPanel(new GridLayout(2,2)); p4SubPanel2a.add(p4SubPanel2b); p4.setBorder(new TitledBorder("KeyStore Passphrase")); p4SubPanel2b.add(new JLabel("Passphrase: "), BorderLayout.WEST); p4SubPanel2b.add(pw1, BorderLayout.WEST); p4SubPanel2b.add(new JLabel("Passphrase (again): "), BorderLayout.WEST); pw2.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent evt) { if ( pw2.getPassword().length > 0 ) { createKeyStoreActionPerformed(evt); } } } ); p4SubPanel2b.add(pw2, BorderLayout.WEST); // p5 - Create & Cancel Buttons JButton jButtonCreate = new JButton("Create"); jButtonCreate.setMnemonic(KeyEvent.VK_R); Gui.enterPressesWhenFocused(jButtonCreate); jButtonCreate.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { createKeyStoreActionPerformed(evt); } }); p5.add(jButtonCreate); JButton jButtonCancel = new JButton("Cancel"); jButtonCancel.setMnemonic(KeyEvent.VK_C); Gui.enterPressesWhenFocused(jButtonCancel); jButtonCancel.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // System.out.println("Canceling..."); createKeyStoreDialog.setVisible(false); createKeyStoreDialog.dispose(); } }); p5.add(jButtonCancel); ///////////////////////////////////////////////////////////// // Finish up createKeyStoreDialog.setTitle("Professional Data Security (PDS) - Create New KeyStore"); createKeyStoreDialog.pack(); createKeyStoreDialog.setLocationRelativeTo(null); createKeyStoreDialog.setVisible(true); } /////////////////////////////////////////////////////////////////////// /** * Listeners for the CreateKeyStore inner class * */ /////////////////////////////////////////////////////////////////////// JFrame chooserFrame = new JFrame(); JFrame frame = new JFrame(); String ksName; // Listener Action Item for Browse to KeyStore private void openMenuItemActionPerformed(ActionEvent evt) { JFileChooser fileChooser; if ( mGui.stateObject.getDefaultKeyStoreDir() != null ) { fileChooser = new JFileChooser ( mGui.stateObject.getDefaultKeyStoreDir() ); } else { fileChooser = new JFileChooser ( mGui.runTimePath ); } fileChooser.setDialogTitle( "KeyStore Location" ); fileChooser.setApproveButtonText("OK"); FileNameExtensionFilter filterPDS = new FileNameExtensionFilter("Professional Data Security Files (PDS)", "PDS"); FileNameExtensionFilter filterJCEKS = new FileNameExtensionFilter("Java Cryptographic Extension (JCE) KeyStores (JCEKS)", "JCEKS"); FileNameExtensionFilter filterJKS = new FileNameExtensionFilter("Java KeyStores (JKS)", "JKS"); FileNameExtensionFilter filterKeyStores = new FileNameExtensionFilter("Java KeyStores (JCEKS, JKS)", "JCEKS", "JKS"); fileChooser.addChoosableFileFilter( filterJKS ); fileChooser.addChoosableFileFilter( filterJCEKS ); fileChooser.addChoosableFileFilter( filterPDS ); fileChooser.addChoosableFileFilter( filterKeyStores ); int returnVal = fileChooser.showOpenDialog(chooserFrame); if ( returnVal == 0 ) { // Get Absolute Path: ksName = fileChooser.getSelectedFile().getPath(); // System.out.print("KeyStore: " + ksName + newline); keyStoreNameField.setText( ksName ); keyStoreNameField.setEnabled(true); keyStoreNameField.repaint(); } else if ( returnVal == 1 ) { // System.out.print("Canceling..." + newline); } else { System.out.print("Error: " + returnVal + newline); } } private void createKeyStoreActionPerformed(ActionEvent evt) { // System.out.println("Begin create new KeyStore.."); String keyStoreName = keyStoreNameField.getText(); // System.out.println("KeyStore Name: " + keyStoreName); // See if KeyStore field was empty // if ( keyStoreName.length() == 0 ) { // notify if failure JOptionPane.showMessageDialog( frame, "KeyStore name cannot be empty.", "KeyStore Name", JOptionPane.WARNING_MESSAGE); return; } // Determine what type of keystore is to be created. String keyStoreType; if ( jceksButton.isSelected() ) { keyStoreType = "JCEKS"; } else { keyStoreType = "JKS"; } // System.out.println("KeyStore Type : " + keyStoreType); // If provided, strip off file extensions of JCEKS / JKS. // // Strip off JCEKS extension from files Pattern pattern = Pattern.compile("(.+)\\.JCEKS", Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(keyStoreName); if( matcher.matches() ) { // System.out.println("Contains extension: " + keyStoreName); keyStoreName = matcher.group(1); // System.out.println("Truncated name : " + keyStoreName); } // Strip off JKS extension from files pattern = Pattern.compile("(.+)\\.JKS", Pattern.CASE_INSENSITIVE); matcher = pattern.matcher(keyStoreName); if( matcher.matches() ) { // System.out.println("Contains extension: " + keyStoreName); keyStoreName = matcher.group(1); // System.out.println("Truncated name : " + keyStoreName); } // Options // 1. User provided just a file name - create in default directory. // 2. User provided a relative path (does not begin with C: or /). // - create path/file within the default directory. // 3. User provided absolute path to file - create in provided path. String keyStorePath = null; String keyStoreFileName = null; // First, see if the keyStoreName contains path info // pattern = Pattern.compile("(.*)[/\\\\](.*)"); matcher = pattern.matcher( keyStoreName ); if ( matcher.matches() ) { // KeyStore name has path info. // // System.out.println("KeyStore info provided: " + keyStoreName ); // System.out.println("Dir: " + matcher.group(1) ); // System.out.println("File: " + matcher.group(2) ); keyStorePath = matcher.group(1); keyStoreFileName = matcher.group(2); // Find the *full* directory part of the path. // Yes, matcher.group(1) contains the path, but in the corner // case of providing /myks.jceks, the first slash is lost in // the previous regex. So we recompile the pattern differently // and don't fall for that one: pattern = Pattern.compile("(.*)" + keyStoreFileName ); matcher = pattern.matcher( keyStoreName ); if( matcher.matches() ) { // System.out.println("Full directory: " + matcher.group(1) ); keyStorePath = matcher.group(1); } else { System.out.println("Unknown error in CreateKeyStoreDialog."); System.out.println("Should have a match on path. Returning..."); return; } } else { keyStoreFileName = keyStoreName; } // Determine if path is empty, absolute or relative. Boolean absolutePath = false; Boolean pathMightWork = false; if ( keyStorePath != null ) { // Have ~something~ for path info. pattern = Pattern.compile("[A-Z]:\\\\(.*)", Pattern.CASE_INSENSITIVE); matcher = pattern.matcher( keyStorePath ); if ( matcher.matches() ) { // System.out.println("Have a DOS world."); absolutePath = true; pathMightWork = true; } // Not DOS, how bout Nix? if ( ! pathMightWork ) { pattern = Pattern.compile("/(.*)", Pattern.CASE_INSENSITIVE); matcher = pattern.matcher( keyStorePath ); if ( matcher.matches() ) { // System.out.println("Unix'd."); absolutePath = true; pathMightWork = true; } } // Finally if ( ! absolutePath ) { // Prepend default path to provided path // System.out.println( "Setting keystore path relative to the default." ); keyStorePath = ( mGui.stateObject.getDefaultKeyStoreDir() + keyStorePath ); } } else { // Prepend default path to the file // System.out.println( "Prepending default keystore path." ); keyStorePath = ( mGui.stateObject.getDefaultKeyStoreDir() ); } // Have the final keystore path...but does it exist // System.out.println ( "Final keystore path is: " + keyStorePath ); try { if ( ! new java.io.File( keyStorePath ).exists() ) { JFrame frame = new JFrame(); int n = JOptionPane.showOptionDialog( frame, "The KeyStore directory does not exist." + newline + newline + keyStorePath + newline + newline + "Would you like to create it?" + newline + newline, "Directory does not exist", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, new String[] {"Yes", "No"}, "No"); if ( n != 0 ) { // System.out.println("Canceling..."); // createKeyStoreDialog.setVisible(false); // createKeyStoreDialog.dispose(); return; } else { // System.out.println("Creating the directory..."); boolean success = (new File( keyStorePath )).mkdirs(); if (success) { // System.out.println("Directory: " + keyStorePath + " created"); } else { JOptionPane.showMessageDialog( frame, "Unable to Create the Directory:" + newline + keyStorePath + newline + newline + "Please check the permissions or the path" + newline + "and try again.", "Unable to Create the Directory", JOptionPane.ERROR_MESSAGE); createKeyStoreDialog.setVisible(false); createKeyStoreDialog.dispose(); return; } } } } catch (Exception e) { System.out.println("Unable to get fully pathed filename: " + e); return; } // Should now have a keystore path that exists. Reset keyStoreName. keyStoreName = keyStorePath + keyStoreFileName + "." + keyStoreType ; // Does the KeyStore file currently exist? // System.out.println( "Does the file already exist: " + keyStoreName ); if ( new java.io.File( keyStoreName ).exists() ) { int n = JOptionPane.showOptionDialog( frame, "A KeyStore with this name currently exists:" + newline + keyStoreName + newline + newline + "If you continue, this KeyStore and all the keys in it will be destroyed." + newline + "Any data files that have been encrypted by these keys will be lost." + newline + newline + "Continue?", "KeyStore exists", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, new String[] {"Yes", "No"}, "No"); if ( n != 0 ) { // System.out.println("Canceling..."); return; } } // // Done with the KeyStore path. Time to authenticate. // char[] ksPass1 = pw1.getPassword(); char[] ksPass2 = pw2.getPassword(); // System.out.print("First Passphrase : "); // for ( int i = 0; i < ksPass1.length; i++ ) { // System.out.print( ksPass1[i] ); // } // System.out.println(); // System.out.print("Next Passphrase : "); // for ( int i = 0; i < ksPass2.length; i++ ) { // System.out.print( ksPass2[i] ); // } // System.out.println(); // Was the first key pass provided and correct if ( ! (ksPass1.length >= 8) ) { // notify if failure JOptionPane.showMessageDialog( frame, "The KeyStore passphrase must be at least 8 characters, " + newline + "containing both upper and lower case A-Z characters " + newline + "as well as one other character.", "Passphrase empty", JOptionPane.WARNING_MESSAGE); return; } // Check for correct syntax boolean upper = false; // set to true if test passes boolean lower = false; // set to true if test passes boolean other = false; // set to true if test passes // Check for upper case first for ( int i = 0; i < ksPass1.length; i++ ) { for ( int n = 65; n <= 90; n++ ) { if ( ( (int) ksPass1[i] ) == n ) { upper = true; n = 91; i = ksPass1.length; } } } // System.out.println("Contained upper: " + upper); // Check for lower case next for ( int i=0; i < ksPass1.length; i++ ) { for ( int n = 97; n <= 122; n++ ) { if ( ( (int) ksPass1[i] ) == n ) { lower = true; n = 123; i = ksPass1.length; } } } // System.out.println("Contained lower: " + lower); // Check for existence of another char last for ( int i = 0; i < ksPass1.length; i++ ) { boolean otherUpper = false; boolean otherLower = false; // Is it an upper case char ? for ( int n = 65; n <= 90; n++ ) { if ( ( (int) ksPass1[i] ) == n ) { otherUpper = true; n = 91; } } // If not upper, then is it lower case char? if ( ! otherUpper ) { for ( int j = 97; j <= 122; j++ ) { if ( ( (int) ksPass1[i] ) == j ) { otherLower = true; j = 123; } } } if ( ( ! otherUpper ) && ( ! otherLower ) ) { other = true; i = ksPass1.length; } } // System.out.println("Contained other: " + other); if( ! ( upper && lower && other ) ) { // notify if failure JOptionPane.showMessageDialog( frame, "KeyStore passphrase must be at least 8 characters, " + newline + "containing both upper case and lower case characters " + newline + "as well as some other character.", "Passphrase empty", JOptionPane.WARNING_MESSAGE); return; } // Did the passwords match if ( ! java.util.Arrays.equals(ksPass1,ksPass2) ) { // notify if failure JOptionPane.showMessageDialog( frame, "Passphrases did not match.", "Passphrase mismatch", JOptionPane.WARNING_MESSAGE); return; } // System.out.println("Creating KeyStore..."); // System.out.println("KeyStore Name: "); // System.out.println(keyStoreName + "." + keyStoreType); try { if ( new CryptoKeyStore().createKeyStore( keyStoreType, ksPass1, keyStoreName ) ) { JOptionPane.showMessageDialog( frame, "KeyStore successfully created:" + newline + keyStoreName + newline , "Success", JOptionPane.INFORMATION_MESSAGE, Gui.createImageIcon("images/PDS_Logo-32.png")); }; } catch (Exception createKeyStoreException) { // notify if failure System.out.println("Error Creating KeyStore: " + createKeyStoreException); JOptionPane.showMessageDialog( frame, "Error Creating KeyStore: " + createKeyStoreException, "Error Creating KeyStore" , JOptionPane.ERROR_MESSAGE); } finally { // Scrub the passphrases // System.out.println("Scrubbing passphrases in Gui.createKeyStoreDialog()..."); for ( int i = 0; i < ksPass1.length; i++ ) { ksPass1[i] = '0'; } for ( int i = 0; i < ksPass2.length; i++ ) { ksPass2[i] = '0'; } // System.out.println("Closing Create Key Dialog"); createKeyStoreDialog.setVisible(false); createKeyStoreDialog.dispose(); } } }