Projects >> cismet-commons >>aa9e5aa616f0736034b024a5973446bb308ca3ea

Chunk
Conflicting content
     *
            });
        return ret;
    }

     *
    /**
     * DOCUMENT ME!
     *
            }

        }
<<<<<<< HEAD

/***************************************************
*
* cismet GmbH, Saarbruecken, Germany
*
*              ... and it just works.
*
****************************************************/
package de.cismet.tools;

import net.sourceforge.blowfishj.BlowfishEasy;

import org.apache.log4j.Logger;

import java.io.IOException;
import java.io.InputStream;

import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

import javax.swing.JOptionPane;
import javax.swing.UIManager;

/**
 * DOCUMENT ME!
 *
 * @author   thorsten.hell@cismet.de
 * @author   martin.scholl@cismet.de
 * @version  $Revision$, $Date$
 */
public class PasswordEncrypter extends javax.swing.JFrame {

    //~ Static fields/initializers ---------------------------------------------

    private static final transient Logger LOG = Logger.getLogger(PasswordEncrypter.class);

    private static final byte LF = 0xA;

    @Deprecated
    public static String CRYPT_PREFIX = "crypt::";                       // NOI18N
    @Deprecated
    private static final char[] MASTER_PASS = "fourtytwo".toCharArray(); // NOI18N

    private static final String CIPHER = "PBEWithMD5AndDES/CBC/PKCS5Padding";
    private static final String FACTORY = "PBEWithMD5AndDES";
    private static final int ITERATIONS = 20;
    private static final byte[] DEFAULT_SALT = new byte[] { 124, 10, 10, 54, 23, 43, 72, 78 };

    private static final char[] PE_MASTERKEY_PROP = "PasswordEncrypter.masterKey".toCharArray(); // NOI18N
    private static final char[] PE_SALT_PROP = "PasswordEncrypter.salt".toCharArray();           // NOI18N

    private static final SecureRandom RANDOM = new SecureRandom();

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton cmdGo;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JPasswordField pwfPassword1;
    private javax.swing.JPasswordField pwfPassword2;
    private javax.swing.JTextArea txtCode;
    // End of variables declaration//GEN-END:variables

    //~ Constructors -----------------------------------------------------------

    /**
     * Creates new form PasswordEncrypter.
     */
    public PasswordEncrypter() {
        initComponents();
        getRootPane().setDefaultButton(cmdGo);
    }

    //~ Methods ----------------------------------------------------------------

    /**
     * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The
     * content of this method is always regenerated by the Form Editor.
     */
    // //GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        jLabel1 = new javax.swing.JLabel();
        cmdGo = new javax.swing.JButton();
        txtCode = new javax.swing.JTextArea();
        jLabel2 = new javax.swing.JLabel();
        jLabel3 = new javax.swing.JLabel();
        jLabel4 = new javax.swing.JLabel();
        pwfPassword1 = new javax.swing.JPasswordField();
        pwfPassword2 = new javax.swing.JPasswordField();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle(org.openide.util.NbBundle.getMessage(PasswordEncrypter.class, "PasswordEncrypter.title")); // NOI18N
        getContentPane().setLayout(new java.awt.GridBagLayout());

        jLabel1.setFont(new java.awt.Font("MS Sans Serif", 1, 12)); // NOI18N
        jLabel1.setText(org.openide.util.NbBundle.getMessage(
                PasswordEncrypter.class,
                "PasswordEncrypter.jLabel1.text"));                 // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = 3;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 11, 3);
        getContentPane().add(jLabel1, gridBagConstraints);

        cmdGo.setText(org.openide.util.NbBundle.getMessage(PasswordEncrypter.class, "PasswordEncrypter.cmdGo.text")); // NOI18N
        cmdGo.addActionListener(new java.awt.event.ActionListener() {

                @Override
                public void actionPerformed(final java.awt.event.ActionEvent evt) {
                    cmdGoActionPerformed(evt);
                }
            });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
        getContentPane().add(cmdGo, gridBagConstraints);

        txtCode.setLineWrap(true);
        txtCode.setRows(3);
        txtCode.setOpaque(false);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
        getContentPane().add(txtCode, gridBagConstraints);

        jLabel2.setText(org.openide.util.NbBundle.getMessage(
                PasswordEncrypter.class,
                "PasswordEncrypter.jLabel2.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0);
        getContentPane().add(jLabel2, gridBagConstraints);

        jLabel3.setText(org.openide.util.NbBundle.getMessage(
                PasswordEncrypter.class,
                "PasswordEncrypter.jLabel3.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0);
        getContentPane().add(jLabel3, gridBagConstraints);

        jLabel4.setText(org.openide.util.NbBundle.getMessage(
                PasswordEncrypter.class,
                "PasswordEncrypter.jLabel4.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0);
        getContentPane().add(jLabel4, gridBagConstraints);

        pwfPassword1.addFocusListener(new java.awt.event.FocusAdapter() {

                @Override
                public void focusGained(final java.awt.event.FocusEvent evt) {
                    pwfPassword1FocusGained(evt);
                }
            });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
        getContentPane().add(pwfPassword1, gridBagConstraints);

        pwfPassword2.addFocusListener(new java.awt.event.FocusAdapter() {

                @Override
                public void focusGained(final java.awt.event.FocusEvent evt) {
                    pwfPassword2FocusGained(evt);
                }
            });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
        getContentPane().add(pwfPassword2, gridBagConstraints);

        final java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        setBounds((screenSize.width - 398) / 2, (screenSize.height - 183) / 2, 398, 183);
    } // //GEN-END:initComponents

    /**
     * DOCUMENT ME!
     *
     * @param  evt  DOCUMENT ME!
     */
    private void pwfPassword2FocusGained(final java.awt.event.FocusEvent evt) { //GEN-FIRST:event_pwfPassword2FocusGained
        pwfPassword2.setSelectionStart(0);
        pwfPassword2.setSelectionEnd(pwfPassword1.getPassword().length);
    }                                                                           //GEN-LAST:event_pwfPassword2FocusGained

    /**
     * DOCUMENT ME!
     *
     * @param  evt  DOCUMENT ME!
     */
    private void pwfPassword1FocusGained(final java.awt.event.FocusEvent evt) { //GEN-FIRST:event_pwfPassword1FocusGained
        pwfPassword1.setSelectionStart(0);
        pwfPassword1.setSelectionEnd(pwfPassword1.getPassword().length);
    }                                                                           //GEN-LAST:event_pwfPassword1FocusGained

    /**
     * DOCUMENT ME!
     * @param  evt  DOCUMENT ME!
     */
    private void cmdGoActionPerformed(final java.awt.event.ActionEvent evt) {                        //GEN-FIRST:event_cmdGoActionPerformed
        final String p1 = new String(pwfPassword1.getPassword());
        final String p2 = new String(pwfPassword2.getPassword());
        if (p1.equals(p2)) {
            try {
                txtCode.setText(encryptString(String.valueOf(pwfPassword1.getPassword())));
            } catch (final PasswordEncrypterException ex) {
                txtCode.setText("exception during encryption: " + ex);
            }
        } else {
            JOptionPane.showMessageDialog(
                this,
                org.openide.util.NbBundle.getMessage(
                    PasswordEncrypter.class,
                    "PasswordEncrypter.cmdGoActionPerformed(ActionEvent).JOptionPane_anon.message"), // NOI18N
                org.openide.util.NbBundle.getMessage(
                    PasswordEncrypter.class,
                    "PasswordEncrypter.cmdGoActionPerformed(ActionEvent).JOptionPane_anon.title"),   // NOI18N
                JOptionPane.ERROR_MESSAGE);
            pwfPassword1.setText("");                                                                // NOI18N
            pwfPassword2.setText("");                                                                // NOI18N
        }
    }                                                                                                //GEN-LAST:event_cmdGoActionPerformed

    /**
     * DOCUMENT ME!
     *
     * @param   args  the command line arguments
     *
     * @throws  Exception  DOCUMENT ME!
     */
    public static void main(final String[] args) throws Exception {
        java.awt.EventQueue.invokeLater(new Runnable() {

                @Override
                public void run() {
                    try {

                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (final Exception e) {
                        e.printStackTrace();
                    }
                    new PasswordEncrypter().setVisible(true);
                }
            });
    }

    /**
     * DOCUMENT ME!
     *
     * @param   code  DOCUMENT ME!
     *
     * @return  DOCUMENT ME!
     *
     * @throws  PasswordEncrypterException  DOCUMENT ME!
     */
    @Deprecated
    public static String decryptString(String code) throws PasswordEncrypterException {
        if ((code != null) && code.startsWith(CRYPT_PREFIX)) {
            final BlowfishEasy blowfish = new BlowfishEasy(MASTER_PASS);
            code = code.substring(CRYPT_PREFIX.length(), code.length());
            return blowfish.decryptString(code);
        } else {
            return code;
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @param   pwd  DOCUMENT ME!
     *
     * @return  DOCUMENT ME!
     *
     * @throws  PasswordEncrypterException  DOCUMENT ME!
     */
    @Deprecated
    public static String encryptString(final String pwd) throws PasswordEncrypterException {
        final BlowfishEasy blowfish = new BlowfishEasy(MASTER_PASS);
        final String code = CRYPT_PREFIX + blowfish.encryptString(pwd);

        return code;
    }

    /**
     * DOCUMENT ME!
     *
     * @param   string     DOCUMENT ME!
     * @param   wipeInput  DOCUMENT ME!
     *
     * @return  or null if the given array is null
     *
     * @throws  PasswordEncrypterException  DOCUMENT ME!
     */
    public static char[] encrypt(final char[] string, final boolean wipeInput) throws PasswordEncrypterException {
        if (string == null) {
            LOG.warn("received null array, returning null"); // NOI18N

            return null;
        }

        final byte[] bytes = bytesFromChars(string, wipeInput);

        final byte[] enc = applyCipher(bytes, Cipher.ENCRYPT_MODE);

        wipe(bytes);

        final byte[] base64 = Base64.toBase64(enc, true);
        final char[] chars = new char[base64.length];
        for (int i = 0; i < base64.length; ++i) {
            chars[i] = (char)base64[i];
            base64[i] = getWipe();
        }

        final char[] ret = new char[chars.length + 2];

        ret[0] = '{';
        for (int i = 0; i < chars.length; ++i) {
            ret[i + 1] = chars[i];
            chars[i] = (char)getWipe();
        }
        ret[ret.length - 1] = '}';

        return ret;
    }

    /**
     * Decrypts a given string that was created by {@link #encrypt(char[])}. The caller is responsible for wiping the
     * given parameter and the returned result himself.
     *
     * @param   string     the encrypted string
     * @param   wipeInput  DOCUMENT ME!
     *
     * @return  the decrypted string in a char[] or null if the given array is 
     *          null
     *
     * @throws  PasswordEncrypterException  DOCUMENT ME!
     */
    public static char[] decrypt(final char[] string, final boolean wipeInput) throws PasswordEncrypterException {
        if (string == null) {
            LOG.warn("received null array, returning null"); // NOI18N
            return null;
        }
        // for backwards compatibility
        final char[] cryptPrefix = CRYPT_PREFIX.toCharArray();
        boolean compatibilityDecrypt = true;
        if (string.length >= cryptPrefix.length) {
            for (int i = 0; i < cryptPrefix.length; ++i) {
                if (string[i] != cryptPrefix[i]) {
                    compatibilityDecrypt = false;
                    break;
                }
            }
        }

        if (compatibilityDecrypt) {
            return decryptString(String.valueOf(string)).toCharArray();
        } else if (('{' == string[0]) && ('}' == string[string.length - 1])) {
            // strip the curly braces
            final char[] base64 = new char[string.length - 2];
            for (int i = 0; i < (string.length - 2); ++i) {
                base64[i] = string[i + 1];
                if (wipeInput) {
                    string[i] = (char)getWipe();
                }
            }

            if (wipeInput) {
                string[0] = (char)getWipe();
                string[string.length - 1] = (char)getWipe();
            }

            final byte[] b64Bytes = new byte[base64.length];
            for (int i = 0; i < base64.length; ++i) {
                b64Bytes[i] = (byte)base64[i];
                base64[i] = (char)getWipe();
            }

            final byte[] bytes = Base64.fromBase64(b64Bytes, true);

            final byte[] res = applyCipher(bytes, Cipher.DECRYPT_MODE);

            wipe(bytes);

            final char[] ret = charsFromBytes(res, true);

            return ret;
        } else {
            return string;
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @param   bytes  string DOCUMENT ME!
     * @param   mode   DOCUMENT ME!
     *
     * @return  DOCUMENT ME!
     *
     * @throws  IllegalArgumentException    DOCUMENT ME!
     * @throws  PasswordEncrypterException  DOCUMENT ME!
     */
    private static byte[] applyCipher(final byte[] bytes, final int mode) {
        if (bytes == null) {
            throw new IllegalArgumentException("given bytes must not be null"); // NOI18N
        }

        Cipher pbeCipher = null;
        SecretKey pbeKey = null;
        try {
            final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(FACTORY);
            pbeKey = keyFactory.generateSecret(new PBEKeySpec(getMasterPw()));
            pbeCipher = Cipher.getInstance(CIPHER);
            pbeCipher.init(mode, pbeKey, new PBEParameterSpec(getSalt(), ITERATIONS));

            final byte[] res = pbeCipher.doFinal(bytes);

            return res;
        } catch (final Exception ex) {
            final String message = "cannot process string: mode=" + mode; // NOI18N
            LOG.error(message, ex);
            throw new PasswordEncrypterException(message, ex);
        } finally {
            // ensure re-init for wiping the cipher, when the cipher is initialised, the key is initialised, too
            if (pbeCipher != null) {
                try {
                    pbeCipher.init(mode, pbeKey, new PBEParameterSpec(getSalt(), ITERATIONS));
                } catch (final Exception ex) {
                    LOG.warn("cannot re-init the cipher", ex); // NOI18N
                }
            }
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @return  DOCUMENT ME!
     *
    /**
     * @throws  PasswordEncrypterException  DOCUMENT ME!
     */
    private static char[] getMasterPw() throws PasswordEncrypterException {
        final InputStream peStream = PasswordEncrypter.class.getResourceAsStream("PasswordEncrypter.properties");

        if (peStream == null) {
            final String message = "PasswordEncrypter properties not present"; // NOI18N
            LOG.error(message);
            throw new PasswordEncrypterException(message);
        } else {
            // we deal with ASCII only
            final byte[] bytes = safeRead(peStream, PE_MASTERKEY_PROP);
            if (bytes == null) {
                final String message = "cannot read master password from properties, not set?"; // NOI18N
                LOG.error(message);
                throw new PasswordEncrypterException(message);
            }

            // simple cast because of ASCII only support
            final char[] chars = new char[bytes.length];
            for (int i = 0; i < bytes.length; ++i) {
                chars[i] = (char)bytes[i];
                bytes[i] = getWipe();
            }

            return chars;
        }
    }

    /**
     * Always 8 bytes.
     *
     * @return  DOCUMENT ME!
     *
     * @throws  PasswordEncrypterException  DOCUMENT ME!
     */
    private static byte[] getSalt() throws PasswordEncrypterException {
        final InputStream peStream = PasswordEncrypter.class.getResourceAsStream("PasswordEncrypter.properties");

        if (peStream == null) {
            final String message = "PasswordEncrypter properties not present"; // NOI18N
            LOG.error(message);
            throw new PasswordEncrypterException(message);
        } else {
            final byte[] salt = safeRead(peStream, PE_SALT_PROP);
            if (salt == null) {
                LOG.warn("salt not set, using default salt");                  // NOI18N

                return DEFAULT_SALT;
            } else if (salt.length < 8) {
    //J-
                LOG.warn("salt too short, filling up with default salt"); // NOI18N
                final byte[] newSalt = new byte[8];
                for (int i = 0; i < 8; ++i) {
                    if (i < salt.length) {
                        newSalt[i] = salt[i];
                        salt[i] = getWipe();
                    } else {
                        newSalt[i] = DEFAULT_SALT[i];
                    }
                }

                return newSalt;
            } else if (salt.length < 8) {
                LOG.warn("salt too long, stripping first 8 bytes"); // NOI18N
                final byte[] newSalt = new byte[8];
                for (int i = 0; i < salt.length; ++i) {
                    if (i < newSalt.length) {
                        newSalt[i] = salt[i];
                        salt[i] = getWipe();
                    } else {
                        salt[i] = getWipe();
                    }
                }

                return newSalt;
            } else {
                return salt;
            }
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @param   bytes      DOCUMENT ME!
     * @param   wipeInput  DOCUMENT ME!
     *
     * @return  DOCUMENT ME!
     *
     * @throws  IllegalArgumentException  DOCUMENT ME!
     */
    public static char[] charsFromBytes(final byte[] bytes, final boolean wipeInput) {
        if ((bytes.length % 2) != 0) {
            throw new IllegalArgumentException("cannot convert odd number of bytes");
        }

     * DOCUMENT ME!
        final char[] chars = new char[bytes.length >> 1];
        for (int i = 0; i < chars.length; ++i) {
            final int p = i << 1;
            chars[i] = (char)(((bytes[p] & 0x00FF) << 8) + (bytes[p + 1] & 0x00FF));

            if (wipeInput) {
                bytes[p] = getWipe();
                bytes[p + 1] = getWipe();
            }
        }

        return chars;
    }

    /**
     * DOCUMENT ME!
     *
     * @param  bytes  DOCUMENT ME!
     */
    public static void wipe(final byte[] bytes) {
        for (int i = 0; i < bytes.length; ++i) {
            bytes[i] = getWipe();
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @param   chars      DOCUMENT ME!
     * @param   wipeInput  DOCUMENT ME!
     *
     * @return  DOCUMENT ME!
     */
    public static byte[] bytesFromChars(final char[] chars, final boolean wipeInput) {
        final byte[] bytes = new byte[chars.length << 1];
        for (int i = 0; i < chars.length; ++i) {
            final int p = i << 1;
            bytes[p] = (byte)((chars[i] & 0xFF00) >> 8);
            bytes[p + 1] = (byte)(chars[i] & 0x00FF);

            if (wipeInput) {
                chars[i] = (char)getWipe();
            }
        }

        return bytes;
    }

    /**
     * DOCUMENT ME!
     *
     * @param  chars  DOCUMENT ME!
     */
    public static void wipe(final char[] chars) {
        for (int i = 0; i < chars.length; ++i) {
            chars[i] = (char)getWipe();
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @return  DOCUMENT ME!
     */
    public static byte getWipe() {
        RANDOM.setSeed(System.nanoTime());
        final byte[] wipe = new byte[1];
        RANDOM.nextBytes(wipe);

        return wipe[0];
    }

    /**
     * Reads a property as safe as possible. This operation is completely char[] based and won't put any property values
     * into {@link String} objects. The given stream will be used as is, it won't be closed nor reset. However, if the
     * {@link InputStream#read()} operation of this implementation will change some markers or similar they won't be
     * reset, too.
*
* *

IMPORTANT: Properties are supposed to be separated by a single '=' and terminated by a line feed or EOF.

*
* *

IMPORTANT: Only ASCII encoded properties are currently supported

* * @param propertyStream the stream to read from * @param property the property to read * * @return the value of the property in a byte[] * * @throws PasswordEncrypterException DOCUMENT ME! */ public static byte[] safeRead(final InputStream propertyStream, final char[] property) throws PasswordEncrypterException { // TODO: optimise parser try { int c; int mark = 0; boolean comment = false; boolean firstChar = true; while ((c = propertyStream.read()) > 0) { if (firstChar && (c == '#')) { comment = true; firstChar = false; } else if (c == LF) { firstChar = true; comment = false; } else if (comment) { firstChar = false; } else if ((property.length > mark) && (c == property[mark])) { firstChar = false; mark++; } else if ((c == '=') && (property.length == mark)) { // read the property value byte[] bytes = new byte[100]; int p; int index = 0; while (((p = propertyStream.read()) > 0) && (p != LF)) { bytes[index] = (byte)p; index++; final byte[] tmp = new byte[bytes.length + 100]; if (index == bytes.length) { // resize and wipe for (int i = 0; i < bytes.length; ++i) { tmp[i] = bytes[i]; bytes[i] = getWipe(); } bytes = tmp; } } // resize final byte[] tmp = new byte[index]; for (int i = 0; i < tmp.length; ++i) { // copy and wipe tmp[i] = bytes[i]; bytes[i] = getWipe(); } return tmp; } else { // mismatching property key, reset marker mark = 0; firstChar = false; } } } catch (final IOException ex) { final String message = "cannot read password from properties"; // NOI18N LOG.error(message, ex); throw new PasswordEncrypterException(message, ex); } return null; } } ======= /*************************************************** * * cismet GmbH, Saarbruecken, Germany * * ... and it just works. * ****************************************************/ package de.cismet.tools; import net.sourceforge.blowfishj.BlowfishEasy; import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; import sun.misc.BASE64Encoder; import java.io.IOException; import java.io.InputStream; import java.security.SecureRandom; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; import javax.swing.JOptionPane; /** * DOCUMENT ME! * * @author thorsten.hell@cismet.de * @version $Revision$, $Date$ */ // FIXME: encoding, random wipe bytes public class PasswordEncrypter extends javax.swing.JFrame { //~ Static fields/initializers --------------------------------------------- private static final transient Logger LOG = Logger.getLogger(PasswordEncrypter.class); @Deprecated public static String CRYPT_PREFIX = "crypt::"; // NOI18N @Deprecated private static final char[] MASTER_PASS = "fourtytwo".toCharArray(); // NOI18N private static final String CIPHER = "PBEWithMD5AndDES/CBC/PKCS5Padding"; private static final String FACTORY = "PBEWithMD5AndDES"; private static final char[] PE_MASTERKEY_PROP = "PasswordEncrypter.masterKey".toCharArray(); // NOI18N private static final char[] PE_SALT_PROP = "PasswordEncrypter.salt".toCharArray(); // NOI18N private static final int ITERATIONS = 20; private static final byte LF = 0xA; private static final byte CR = 0xD; private static final byte EQ = 0x3D; private static final byte[] DEFAULT_SALT = new byte[] { 124, 10, 10, 54, 23, 43, 72, 78 }; private static final SecureRandom RANDOM = new SecureRandom(); private static final int LINE_SPLIT = 76; // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton cmdGo; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; private javax.swing.JLabel jLabel4; private javax.swing.JPasswordField pwfPassword1; private javax.swing.JPasswordField pwfPassword2; private javax.swing.JTextArea txtCode; // End of variables declaration//GEN-END:variables //~ Constructors ----------------------------------------------------------- /** * Creates new form PasswordEncrypter. */ public PasswordEncrypter() { initComponents(); getRootPane().setDefaultButton(cmdGo); } //~ Methods ---------------------------------------------------------------- /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The * content of this method is always regenerated by the Form Editor. */ // //GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; jLabel1 = new javax.swing.JLabel(); cmdGo = new javax.swing.JButton(); txtCode = new javax.swing.JTextArea(); jLabel2 = new javax.swing.JLabel(); jLabel3 = new javax.swing.JLabel(); jLabel4 = new javax.swing.JLabel(); pwfPassword1 = new javax.swing.JPasswordField(); pwfPassword2 = new javax.swing.JPasswordField(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setTitle(org.openide.util.NbBundle.getMessage(PasswordEncrypter.class, "PasswordEncrypter.title")); // NOI18N getContentPane().setLayout(new java.awt.GridBagLayout()); jLabel1.setFont(new java.awt.Font("MS Sans Serif", 1, 12)); // NOI18N jLabel1.setText(org.openide.util.NbBundle.getMessage( PasswordEncrypter.class, "PasswordEncrypter.jLabel1.text")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(3, 3, 11, 3); getContentPane().add(jLabel1, gridBagConstraints); cmdGo.setText(org.openide.util.NbBundle.getMessage(PasswordEncrypter.class, "PasswordEncrypter.cmdGo.text")); // NOI18N cmdGo.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(final java.awt.event.ActionEvent evt) { cmdGoActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3); getContentPane().add(cmdGo, gridBagConstraints); txtCode.setLineWrap(true); txtCode.setRows(3); txtCode.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3); getContentPane().add(txtCode, gridBagConstraints); jLabel2.setText(org.openide.util.NbBundle.getMessage( PasswordEncrypter.class, "PasswordEncrypter.jLabel2.text")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST; gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0); getContentPane().add(jLabel2, gridBagConstraints); jLabel3.setText(org.openide.util.NbBundle.getMessage( PasswordEncrypter.class, "PasswordEncrypter.jLabel3.text")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST; gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0); getContentPane().add(jLabel3, gridBagConstraints); jLabel4.setText(org.openide.util.NbBundle.getMessage( PasswordEncrypter.class, "PasswordEncrypter.jLabel4.text")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST; gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0); getContentPane().add(jLabel4, gridBagConstraints); pwfPassword1.addFocusListener(new java.awt.event.FocusAdapter() { @Override public void focusGained(final java.awt.event.FocusEvent evt) { pwfPassword1FocusGained(evt); } gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3); getContentPane().add(pwfPassword1, gridBagConstraints); pwfPassword2.addFocusListener(new java.awt.event.FocusAdapter() { @Override public void focusGained(final java.awt.event.FocusEvent evt) { pwfPassword2FocusGained(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3); getContentPane().add(pwfPassword2, gridBagConstraints); final java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); setBounds((screenSize.width - 398) / 2, (screenSize.height - 183) / 2, 398, 183); } // //GEN-END:initComponents /** * DOCUMENT ME! * * @param evt DOCUMENT ME! */ private void pwfPassword2FocusGained(final java.awt.event.FocusEvent evt) {//GEN-FIRST:event_pwfPassword2FocusGained pwfPassword2.setSelectionStart(0); pwfPassword2.setSelectionEnd(pwfPassword1.getPassword().length); }//GEN-LAST:event_pwfPassword2FocusGained * @param evt DOCUMENT ME! */ private void pwfPassword1FocusGained(final java.awt.event.FocusEvent evt) {//GEN-FIRST:event_pwfPassword1FocusGained pwfPassword1.setSelectionStart(0); pwfPassword1.setSelectionEnd(pwfPassword1.getPassword().length); }//GEN-LAST:event_pwfPassword1FocusGained /** * DOCUMENT ME! * * @param evt DOCUMENT ME! */ private void cmdGoActionPerformed(final java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cmdGoActionPerformed final String p1 = new String(pwfPassword1.getPassword()); final String p2 = new String(pwfPassword2.getPassword()); if (p1.equals(p2)) { try { txtCode.setText(encryptString(String.valueOf(pwfPassword1.getPassword()))); } catch (final PasswordEncrypterException ex) { txtCode.setText("exception during encryption: " + ex); } } else { JOptionPane.showMessageDialog( this, org.openide.util.NbBundle.getMessage( PasswordEncrypter.class, "PasswordEncrypter.cmdGoActionPerformed(ActionEvent).JOptionPane_anon.message"), // NOI18N org.openide.util.NbBundle.getMessage( PasswordEncrypter.class, "PasswordEncrypter.cmdGoActionPerformed(ActionEvent).JOptionPane_anon.title"), // NOI18N JOptionPane.ERROR_MESSAGE); pwfPassword1.setText(""); // NOI18N pwfPassword2.setText(""); // NOI18N } }//GEN-LAST:event_cmdGoActionPerformed /** * DOCUMENT ME! * * @param args the command line arguments * * @throws Exception DOCUMENT ME! */ public static void main(final String[] args) throws Exception { System.out.println(); System.out.println("TEST toBase64"); // final String string = "a"; final String string = "abcdefgh"; // final String string = "12345678902093woeiaösdghö43lwreahsdgöo24iwhlrasdfwesradgbrdsfv356%$3woeiaösdghö43lwreahsdgöo24iwhlrasdfwesradgbrdsfv356%3woeiaösdghö43lwreahsdgöo24iwhlrasdfwesradgbrdsfv356%"; final byte[] expResult1 = Base64.encodeBase64(string.getBytes()); final String expResult2 = new BASE64Encoder().encode(string.getBytes()); final byte[] result = PasswordEncrypter.toBase64(string.getBytes(), true); System.out.println(new String(result)); System.out.println(new String(expResult1)); System.out.println(expResult2); System.out.println(new String(fromBase64(result, false))); // final char[] out = encrypt("def".toCharArray()); // System.out.println(Arrays.toString(out)); // final char[] in = decrypt(out); // System.out.println(Arrays.toString(in)); // final SecretKeyFactory s = SecretKeyFactory.getInstance("DESede"); // System.out.println(s); // java.awt.EventQueue.invokeLater(new Runnable() { // // @Override // public void run() { // try { // UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); // } catch (final Exception e) { // e.printStackTrace(); // } // new PasswordEncrypter().setVisible(true); // } // }); // final String s = "ürpk"; // System.out.println(s); // // final byte[] bytes = bytesFromCharAndWipe(s.toCharArray()); // Arrays.toString(bytes); // final char[] chars = charFromBytesAndWipe(bytes); // // System.out.println(String.valueOf(chars)); } * @param code DOCUMENT ME! * * @return DOCUMENT ME! * * @throws PasswordEncrypterException DOCUMENT ME! */ @Deprecated public static String decryptString(String code) throws PasswordEncrypterException { if ((code != null) && code.startsWith(CRYPT_PREFIX)) { final BlowfishEasy blowfish = new BlowfishEasy(MASTER_PASS); code = code.substring(CRYPT_PREFIX.length(), code.length()); return blowfish.decryptString(code); } else { return code; } } /** * DOCUMENT ME! * * @param pwd DOCUMENT ME! * * @return DOCUMENT ME! * * @throws PasswordEncrypterException DOCUMENT ME! */ @Deprecated public static String encryptString(final String pwd) throws PasswordEncrypterException { final BlowfishEasy blowfish = new BlowfishEasy(MASTER_PASS); final String code = CRYPT_PREFIX + blowfish.encryptString(pwd); return code; } /** * DOCUMENT ME! * * @param string DOCUMENT ME! * * @return DOCUMENT ME! * * @throws PasswordEncrypterException DOCUMENT ME! */ public static char[] encrypt(final char[] string) throws PasswordEncrypterException { final char[] chars = null; // applyCipher(string, Cipher.ENCRYPT_MODE); final char[] ret = new char[chars.length + 2]; ret[0] = '{'; for (int i = 0; i < chars.length; ++i) { ret[i + 1] = chars[i]; chars[i] = (char)getWipe(); } ret[ret.length - 1] = '}'; private static final byte[] BASE64CODE = new byte[] { // A-Z 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, // a-z 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, // 0-9 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, // + / 0x2B, 0x2F }; //J+ /** * DOCUMENT ME! * * @param byteString string DOCUMENT ME! * * @return DOCUMENT ME! */ public static byte[] toBase64(final byte[] byteString, final boolean wipeInput) { final int padding = (3 - (byteString.length % 3)) % 3; final byte[] byteStringPadded = new byte[byteString.length + padding]; for (int i = 0; i < byteString.length; ++i) { byteStringPadded[i] = byteString[i]; if(wipeInput){ byteString[i] = getWipe(); } } final byte[] base64 = new byte[(byteStringPadded.length / 3) * 4]; int k = 0; for (int i = 0; i < byteStringPadded.length; i += 3) { final int j = ((byteStringPadded[i] & 0xFF) << 16) + ((byteStringPadded[i + 1] & 0xFF) << 8) + (byteStringPadded[i + 2] & 0xFF); byteStringPadded[i] = getWipe(); byteStringPadded[i + 1] = getWipe(); byteStringPadded[i + 2] = getWipe(); base64[k++] = BASE64CODE[(j >> 18) & 0x3F]; base64[k++] = BASE64CODE[(j >> 12) & 0x3F]; base64[k++] = BASE64CODE[(j >> 6) & 0x3F]; base64[k++] = BASE64CODE[j & 0x3F]; } // integer div to get linecount final int lineCount = base64.length / LINE_SPLIT; final byte[] base64Br = new byte[base64.length + (lineCount * 2)]; for (int i = 0, j = 0; i < base64.length; ++i, ++j) { if ((i > 0) && ((i % LINE_SPLIT) == 0)) { base64Br[j++] = CR; base64Br[j++] = LF; } base64Br[j] = base64[i]; base64[i] = getWipe(); } for (int i = base64Br.length - 1; i > (base64Br.length - 1 - padding); --i) { base64Br[i] = EQ; } return base64Br; } public static byte[] fromBase64(final byte[] byteString, final boolean wipeInput) { // at least four bytes present in encoded string if(byteString.length < 4){ throw new IllegalArgumentException("incorrectly encoded string, too few bytes: " + byteString.length); } final int padding; if(byteString[byteString.length - 2] == EQ){ padding = 2; } else if (byteString[byteString.length - 1] == EQ){ padding = 1; } else { padding = 0; } final int lineCount = byteString.length / (LINE_SPLIT + 2); final byte[] strippedBr = new byte[byteString.length - (lineCount * 2)]; for(int i = 0, j = 0; i < byteString.length; ++i, ++j){ if(i < 0 && ((i % LINE_SPLIT) == 0)){ if(wipeInput){ byteString[i++] = getWipe(); byteString[i++] = getWipe(); } else { i += 2; } } else { strippedBr[j] = (byte)(byteString[i]); if(wipeInput){ byteString[i] = getWipe(); } } } final byte[] decoded = new byte[(strippedBr.length / 4) * 3]; int k = 0; for(int i = 0; i < strippedBr.length; i += 4){ final int j = ((strippedBr[i] & 0x3F) << 18) + ((strippedBr[i + 1] & 0x3F) << 12) + ((strippedBr[i + 2] & 0x3F) << 6) + (strippedBr[i + 3] & 0x3F); strippedBr[i] = getWipe(); strippedBr[i + 1] = getWipe(); strippedBr[i + 2] = getWipe(); strippedBr[i + 3] = getWipe(); decoded[k++] = (byte)((j >> 16) & 0xFF); if(i < strippedBr.length - 4 || (padding < 2)) { decoded[k++] = (byte)((j >> 8) & 0xFF); } if(i < strippedBr.length - 4 || (padding < 1)) { decoded[k++] = (byte)(j & 0xFF); } } return decoded; } /** * DOCUMENT ME! * * @param bytes string DOCUMENT ME! * @param mode DOCUMENT ME! * * @return DOCUMENT ME! * * @throws PasswordEncrypterException DOCUMENT ME! */ private static byte[] applyCipher(final byte[] bytes, final int mode) { Cipher pbeCipher = null; SecretKey pbeKey = null; try { final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(FACTORY); pbeKey = keyFactory.generateSecret(new PBEKeySpec(getMasterPw())); pbeCipher = Cipher.getInstance(CIPHER); return chars; pbeCipher.init(mode, pbeKey, new PBEParameterSpec(getSalt(), ITERATIONS)); final byte[] res = pbeCipher.doFinal(bytes); return res; } catch (final Exception ex) { final String message = "cannot process string: mode=" + mode; // NOI18N LOG.error(message, ex); ex.printStackTrace(); throw new PasswordEncrypterException(message, ex); } finally { // ensure re-init for wiping the cipher, when the cipher is initialised, the key is initialised, too if (pbeCipher != null) { try { pbeCipher.init(mode, pbeKey, new PBEParameterSpec(getSalt(), ITERATIONS)); } catch (final Exception ex) { LOG.warn("cannot re-init the cipher", ex); // NOI18N } } } } /** * Decrypts a given string that was created by {@link #encrypt(char[])}. The caller is responsible for wiping the * given parameter and the returned result himself. * * @param string the encrypted string * * @return the decrypted string in a char[] * * @throws PasswordEncrypterException DOCUMENT ME! */ public static char[] decrypt(final char[] string) throws PasswordEncrypterException { // for backwards compatibility final char[] cryptPrefix = CRYPT_PREFIX.toCharArray(); boolean compatibilityDecrypt = true; if (string.length >= cryptPrefix.length) { for (int i = 0; i < cryptPrefix.length; ++i) { if (string[i] != cryptPrefix[i]) { compatibilityDecrypt = false; break; } } } if (compatibilityDecrypt) { return decryptString(String.valueOf(string)).toCharArray(); } else if (('{' == string[0]) && ('}' == string[string.length - 1])) { // strip the curly braces final char[] chars = new char[string.length - 2]; // we don't know if System.arraycopy() creates traces in memory for (int i = 0; i < (string.length - 2); ++i) { chars[i] = string[i + 1]; } final char[] ret = null; // applyCipher(chars, Cipher.DECRYPT_MODE); // wipe tmp array wipe(chars); return ret; } else { return string; } } /** * DOCUMENT ME! * * @return DOCUMENT ME! * * @throws PasswordEncrypterException DOCUMENT ME! */ private static char[] getMasterPw() throws PasswordEncrypterException { final InputStream peStream = PasswordEncrypter.class.getResourceAsStream("PasswordEncrypter.properties"); if (peStream == null) { final String message = "PasswordEncrypter properties not present"; // NOI18N LOG.error(message); throw new PasswordEncrypterException(message); } else { // we deal with ASCII only final byte[] bytes = safeRead(peStream, PE_MASTERKEY_PROP); if (bytes == null) { final String message = "cannot read master password from properties, not set?"; // NOI18N LOG.error(message); throw new PasswordEncrypterException(message); } // simple cast because of ASCII only support final char[] chars = new char[bytes.length]; for (int i = 0; i < bytes.length; ++i) { chars[i] = (char)bytes[i]; bytes[i] = getWipe(); } /** * Always 8 bytes. * * @return DOCUMENT ME! * * @throws PasswordEncrypterException DOCUMENT ME! */ private static byte[] getSalt() throws PasswordEncrypterException { final InputStream peStream = PasswordEncrypter.class.getResourceAsStream("PasswordEncrypter.properties"); if (peStream == null) { final String message = "PasswordEncrypter properties not present"; // NOI18N LOG.error(message); throw new PasswordEncrypterException(message); } else { final byte[] salt = safeRead(peStream, PE_SALT_PROP); if (salt == null) { LOG.warn("salt not set, using default salt"); // NOI18N return DEFAULT_SALT; } else if (salt.length < 8) { LOG.warn("salt too short, filling up with default salt"); // NOI18N final byte[] newSalt = new byte[8]; for (int i = 0; i < 8; ++i) { if (i < salt.length) { newSalt[i] = salt[i]; salt[i] = getWipe(); } else { newSalt[i] = DEFAULT_SALT[i]; } } return newSalt; } else if (salt.length < 8) { LOG.warn("salt too long, stripping first 8 bytes"); // NOI18N final byte[] newSalt = new byte[8]; for (int i = 0; i < salt.length; ++i) { if (i < newSalt.length) { newSalt[i] = salt[i]; salt[i] = getWipe(); } else { salt[i] = getWipe(); } } return newSalt; } else { return salt; } } } /** * DOCUMENT ME! * * @param bytes DOCUMENT ME! * * @return DOCUMENT ME! * * @throws IllegalArgumentException DOCUMENT ME! */ public static char[] charFromBytesAndWipe(final byte[] bytes) { if ((bytes.length % 2) != 0) { throw new IllegalArgumentException("cannot convert odd number of bytes"); } final char[] chars = new char[bytes.length >> 1]; for (int i = 0; i < chars.length; ++i) { final int p = i << 1; chars[i] = (char)(((bytes[p] & 0x00FF) << 8) + (bytes[p + 1] & 0x00FF)); bytes[p] = getWipe(); bytes[p + 1] = getWipe(); } return chars; } /** * DOCUMENT ME! * * @param bytes DOCUMENT ME! * * @return DOCUMENT ME! * * @throws IllegalArgumentException DOCUMENT ME! */ public static char[] charFromBytes(final byte[] bytes) { if ((bytes.length % 2) != 0) { throw new IllegalArgumentException("cannot convert odd number of bytes"); } final char[] chars = new char[bytes.length >> 1]; for (int i = 0; i < chars.length; ++i) { final int p = i << 1; chars[i] = (char)(((bytes[p] & 0x00FF) << 8) + (bytes[p + 1] & 0x00FF)); } return chars; } /** * DOCUMENT ME! * * @param bytes DOCUMENT ME! */ public static void wipe(final byte[] bytes) { for (int i = 0; i < bytes.length; ++i) { bytes[i] = getWipe(); } } /** * DOCUMENT ME! * * @param chars DOCUMENT ME! * * @return DOCUMENT ME! */ public static byte[] bytesFromCharAndWipe(final char[] chars) { final byte[] bytes = new byte[chars.length << 1]; for (int i = 0; i < chars.length; ++i) { final int p = i << 1; bytes[p] = (byte)((chars[i] & 0xFF00) >> 8); bytes[p + 1] = (byte)(chars[i] & 0x00FF); chars[i] = (char)getWipe(); } return bytes; } /** * DOCUMENT ME! * * @param chars DOCUMENT ME! * * @return DOCUMENT ME! */ public static byte[] bytesFromChar(final char[] chars) { final byte[] bytes = new byte[chars.length << 1]; for (int i = 0; i < chars.length; ++i) { final int p = i << 1; bytes[p] = (byte)((chars[i] & 0xFF00) >> 8); bytes[p + 1] = (byte)(chars[i] & 0x00FF); } return bytes; } /** * DOCUMENT ME! * * @param chars DOCUMENT ME! */ public static void wipe(final char[] chars) { for (int i = 0; i < chars.length; ++i) { chars[i] = (char)getWipe(); } } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public static byte getWipe() { RANDOM.setSeed(System.nanoTime()); final byte[] wipe = new byte[1]; RANDOM.nextBytes(wipe); return wipe[0]; } /** * Reads a property as safe as possible. This operation is completely char[] based and won't put any property values * into {@link String} objects. The given stream will be used as is, it won't be closed nor reset. However, if the * {@link InputStream#read()} operation of this implementation will change some markers or similar they won't be * reset, too.
*
* *

IMPORTANT: Properties are supposed to be separated by a single '=' and terminated by a line feed or EOF.

*
* *

IMPORTANT: Only ASCII encoded properties are currently supported

* * @param propertyStream the stream to read from * @param property the property to read * * @return the value of the property in a byte[] * * @throws PasswordEncrypterException DOCUMENT ME! */ public static byte[] safeRead(final InputStream propertyStream, final char[] property) throws PasswordEncrypterException { // TODO: optimise parser try { int c; int mark = 0; boolean comment = false; boolean firstChar = true; while ((c = propertyStream.read()) > 0) { if (firstChar && (c == '#')) { comment = true; firstChar = false; } else if (c == LF) { firstChar = true; comment = false; } else if (comment) { firstChar = false; } else if ((property.length > mark) && (c == property[mark])) { firstChar = false; mark++; } else if ((c == '=') && (property.length == mark)) { // read the property value byte[] bytes = new byte[100]; int p; int index = 0; while (((p = propertyStream.read()) > 0) && (p != LF)) { bytes[index] = (byte)p; index++; final byte[] tmp = new byte[bytes.length + 100]; if (index == bytes.length) { // resize and wipe for (int i = 0; i < bytes.length; ++i) { tmp[i] = bytes[i]; bytes[i] = getWipe(); } bytes = tmp; } } // resize final byte[] tmp = new byte[index]; for (int i = 0; i < tmp.length; ++i) { // copy and wipe tmp[i] = bytes[i]; bytes[i] = getWipe(); } return tmp; } else { // mismatching property key, reset marker mark = 0; firstChar = false; } } } catch (final IOException ex) { final String message = "cannot read password from properties"; // NOI18N LOG.error(message, ex); throw new PasswordEncrypterException(message, ex); } return null; } } >>>>>>> c7929b0b28b9118832fcc496ccd799f6bdaa14c8
Solution content
/***************************************************
*
* cismet GmbH, Saarbruecken, Germany
*
*              ... and it just works.
*
****************************************************/
package de.cismet.tools;

import net.sourceforge.blowfishj.BlowfishEasy;

import org.apache.log4j.Logger;

import java.io.IOException;
import java.io.InputStream;

import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

import javax.swing.JOptionPane;
import javax.swing.UIManager;

/**
 * DOCUMENT ME!
 *
 * @author   thorsten.hell@cismet.de
 * @author   martin.scholl@cismet.de
 * @version  $Revision$, $Date$
 */
public class PasswordEncrypter extends javax.swing.JFrame {

    //~ Static fields/initializers ---------------------------------------------

    private static final transient Logger LOG = Logger.getLogger(PasswordEncrypter.class);

    private static final byte LF = 0xA;

    @Deprecated
    public static String CRYPT_PREFIX = "crypt::";                       // NOI18N
    @Deprecated
    private static final char[] MASTER_PASS = "fourtytwo".toCharArray(); // NOI18N

    private static final String CIPHER = "PBEWithMD5AndDES/CBC/PKCS5Padding";
    private static final String FACTORY = "PBEWithMD5AndDES";
    private static final int ITERATIONS = 20;
    private static final byte[] DEFAULT_SALT = new byte[] { 124, 10, 10, 54, 23, 43, 72, 78 };

    private static final char[] PE_MASTERKEY_PROP = "PasswordEncrypter.masterKey".toCharArray(); // NOI18N
    private static final char[] PE_SALT_PROP = "PasswordEncrypter.salt".toCharArray();           // NOI18N

    private static final SecureRandom RANDOM = new SecureRandom();

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton cmdGo;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JPasswordField pwfPassword1;
    private javax.swing.JPasswordField pwfPassword2;
    private javax.swing.JTextArea txtCode;
    // End of variables declaration//GEN-END:variables

    //~ Constructors -----------------------------------------------------------

    /**
     * Creates new form PasswordEncrypter.
     */
    public PasswordEncrypter() {
        initComponents();
        getRootPane().setDefaultButton(cmdGo);
    }

    //~ Methods ----------------------------------------------------------------

    /**
     * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The
     * content of this method is always regenerated by the Form Editor.
     */
    // //GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;
        jLabel1 = new javax.swing.JLabel();
        cmdGo = new javax.swing.JButton();
        txtCode = new javax.swing.JTextArea();
        jLabel2 = new javax.swing.JLabel();
        jLabel3 = new javax.swing.JLabel();
        jLabel4 = new javax.swing.JLabel();
        pwfPassword1 = new javax.swing.JPasswordField();
        pwfPassword2 = new javax.swing.JPasswordField();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle(org.openide.util.NbBundle.getMessage(PasswordEncrypter.class, "PasswordEncrypter.title")); // NOI18N
        getContentPane().setLayout(new java.awt.GridBagLayout());

        jLabel1.setFont(new java.awt.Font("MS Sans Serif", 1, 12)); // NOI18N
        jLabel1.setText(org.openide.util.NbBundle.getMessage(
                PasswordEncrypter.class,
                "PasswordEncrypter.jLabel1.text"));                 // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = 3;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 11, 3);
        getContentPane().add(jLabel1, gridBagConstraints);

        cmdGo.setText(org.openide.util.NbBundle.getMessage(PasswordEncrypter.class, "PasswordEncrypter.cmdGo.text")); // NOI18N
        cmdGo.addActionListener(new java.awt.event.ActionListener() {

                @Override
                public void actionPerformed(final java.awt.event.ActionEvent evt) {
                    cmdGoActionPerformed(evt);
                }
            });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
        getContentPane().add(cmdGo, gridBagConstraints);

        txtCode.setLineWrap(true);
        txtCode.setRows(3);
        txtCode.setOpaque(false);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
        getContentPane().add(txtCode, gridBagConstraints);

        jLabel2.setText(org.openide.util.NbBundle.getMessage(
                PasswordEncrypter.class,
                "PasswordEncrypter.jLabel2.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0);
        getContentPane().add(jLabel2, gridBagConstraints);

        jLabel3.setText(org.openide.util.NbBundle.getMessage(
                PasswordEncrypter.class,
                "PasswordEncrypter.jLabel3.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0);
        getContentPane().add(jLabel3, gridBagConstraints);

        jLabel4.setText(org.openide.util.NbBundle.getMessage(
                PasswordEncrypter.class,
                "PasswordEncrypter.jLabel4.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0);
        getContentPane().add(jLabel4, gridBagConstraints);


    /**
        pwfPassword1.addFocusListener(new java.awt.event.FocusAdapter() {

                @Override
                public void focusGained(final java.awt.event.FocusEvent evt) {
                    pwfPassword1FocusGained(evt);
                }
            });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
        getContentPane().add(pwfPassword1, gridBagConstraints);

        pwfPassword2.addFocusListener(new java.awt.event.FocusAdapter() {

                @Override
                public void focusGained(final java.awt.event.FocusEvent evt) {
                    pwfPassword2FocusGained(evt);
                }
            });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
        getContentPane().add(pwfPassword2, gridBagConstraints);

        final java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        setBounds((screenSize.width - 398) / 2, (screenSize.height - 183) / 2, 398, 183);
    } // //GEN-END:initComponents

    /**
     * DOCUMENT ME!
     *
     * @param  evt  DOCUMENT ME!
     */
    private void pwfPassword2FocusGained(final java.awt.event.FocusEvent evt) { //GEN-FIRST:event_pwfPassword2FocusGained
        pwfPassword2.setSelectionStart(0);
        pwfPassword2.setSelectionEnd(pwfPassword1.getPassword().length);
    }                                                                           //GEN-LAST:event_pwfPassword2FocusGained

    /**
     * DOCUMENT ME!
     *
     * @param  evt  DOCUMENT ME!
     */
    private void pwfPassword1FocusGained(final java.awt.event.FocusEvent evt) { //GEN-FIRST:event_pwfPassword1FocusGained
        pwfPassword1.setSelectionStart(0);
        pwfPassword1.setSelectionEnd(pwfPassword1.getPassword().length);
    }                                                                           //GEN-LAST:event_pwfPassword1FocusGained

    /**
     * DOCUMENT ME!
     *
     * @param  evt  DOCUMENT ME!
     */
    private void cmdGoActionPerformed(final java.awt.event.ActionEvent evt) {                        //GEN-FIRST:event_cmdGoActionPerformed
        final String p1 = new String(pwfPassword1.getPassword());
        final String p2 = new String(pwfPassword2.getPassword());
        if (p1.equals(p2)) {
            try {
                txtCode.setText(encryptString(String.valueOf(pwfPassword1.getPassword())));
            } catch (final PasswordEncrypterException ex) {
                txtCode.setText("exception during encryption: " + ex);
            }
        } else {
            JOptionPane.showMessageDialog(
                this,
                org.openide.util.NbBundle.getMessage(
                    PasswordEncrypter.class,
                    "PasswordEncrypter.cmdGoActionPerformed(ActionEvent).JOptionPane_anon.message"), // NOI18N
                org.openide.util.NbBundle.getMessage(
                    PasswordEncrypter.class,
                    "PasswordEncrypter.cmdGoActionPerformed(ActionEvent).JOptionPane_anon.title"),   // NOI18N
                JOptionPane.ERROR_MESSAGE);
            pwfPassword1.setText("");                                                                // NOI18N
            pwfPassword2.setText("");                                                                // NOI18N
        }
    }                                                                                                //GEN-LAST:event_cmdGoActionPerformed
     * DOCUMENT ME!
     *
     * @param   args  the command line arguments
     *
     * @throws  Exception  DOCUMENT ME!
     */
    public static void main(final String[] args) throws Exception {
        java.awt.EventQueue.invokeLater(new Runnable() {

                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (final Exception e) {
                        e.printStackTrace();
                    }
                    new PasswordEncrypter().setVisible(true);
                }
            });
    }

    /**
     * DOCUMENT ME!
     *
     * @param   code  DOCUMENT ME!
     *
     * @return  DOCUMENT ME!
     *
     * @throws  PasswordEncrypterException  DOCUMENT ME!
     */
    @Deprecated
                LOG.error(message);
    public static String decryptString(String code) throws PasswordEncrypterException {
        if ((code != null) && code.startsWith(CRYPT_PREFIX)) {
            final BlowfishEasy blowfish = new BlowfishEasy(MASTER_PASS);
            code = code.substring(CRYPT_PREFIX.length(), code.length());
            return blowfish.decryptString(code);
        } else {
            return code;
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @param   pwd  DOCUMENT ME!
     *
     * @return  DOCUMENT ME!
     *
     * @throws  PasswordEncrypterException  DOCUMENT ME!
     */
    @Deprecated
    public static String encryptString(final String pwd) throws PasswordEncrypterException {
        final BlowfishEasy blowfish = new BlowfishEasy(MASTER_PASS);
        final String code = CRYPT_PREFIX + blowfish.encryptString(pwd);

        return code;
    }

    /**
     * DOCUMENT ME!
     *
     * @param   string     DOCUMENT ME!
     * @param   wipeInput  DOCUMENT ME!
     *
     * @return  or null if the given array is null
     *
     * @throws  PasswordEncrypterException  DOCUMENT ME!
     */
    public static char[] encrypt(final char[] string, final boolean wipeInput) throws PasswordEncrypterException {
        if (string == null) {
            LOG.warn("received null array, returning null"); // NOI18N

            return null;
        }

        final byte[] bytes = bytesFromChars(string, wipeInput);

        final byte[] enc = applyCipher(bytes, Cipher.ENCRYPT_MODE);

        wipe(bytes);

        final byte[] base64 = Base64.toBase64(enc, true);
        final char[] chars = new char[base64.length];
        for (int i = 0; i < base64.length; ++i) {
            chars[i] = (char)base64[i];
            base64[i] = getWipe();
        }

        final char[] ret = new char[chars.length + 2];

        ret[0] = '{';
        for (int i = 0; i < chars.length; ++i) {
            ret[i + 1] = chars[i];
            chars[i] = (char)getWipe();
        }
        ret[ret.length - 1] = '}';

        return ret;
    }

    /**
     * Decrypts a given string that was created by {@link #encrypt(char[])}. The caller is responsible for wiping the
     * given parameter and the returned result himself.
     *
     * @param   string     the encrypted string
     * @param   wipeInput  DOCUMENT ME!
     *
     * @return  the decrypted string in a char[] or null if the given array is 
     *          null
     *
     * @throws  PasswordEncrypterException  DOCUMENT ME!
     */
    public static char[] decrypt(final char[] string, final boolean wipeInput) throws PasswordEncrypterException {
        if (string == null) {
            LOG.warn("received null array, returning null"); // NOI18N

            return null;
        }
        // for backwards compatibility
        final char[] cryptPrefix = CRYPT_PREFIX.toCharArray();
        boolean compatibilityDecrypt = true;
        if (string.length >= cryptPrefix.length) {
            for (int i = 0; i < cryptPrefix.length; ++i) {
                if (string[i] != cryptPrefix[i]) {
                    compatibilityDecrypt = false;
                    break;
                }
            }
        }

        if (compatibilityDecrypt) {
            return decryptString(String.valueOf(string)).toCharArray();
        } else if (('{' == string[0]) && ('}' == string[string.length - 1])) {
            // strip the curly braces
            final char[] base64 = new char[string.length - 2];
            for (int i = 0; i < (string.length - 2); ++i) {
                base64[i] = string[i + 1];
                if (wipeInput) {
                    string[i] = (char)getWipe();
                }
            }

            if (wipeInput) {
                string[0] = (char)getWipe();
                string[string.length - 1] = (char)getWipe();
            }

            final byte[] b64Bytes = new byte[base64.length];
            for (int i = 0; i < base64.length; ++i) {
                b64Bytes[i] = (byte)base64[i];
                base64[i] = (char)getWipe();
            }

            final byte[] bytes = Base64.fromBase64(b64Bytes, true);

            final byte[] res = applyCipher(bytes, Cipher.DECRYPT_MODE);

            wipe(bytes);

            final char[] ret = charsFromBytes(res, true);

            return ret;
        } else {
            return string;
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @param   bytes  string DOCUMENT ME!
     * @param   mode   DOCUMENT ME!
     *
     * @return  DOCUMENT ME!
     *
     * @throws  IllegalArgumentException    DOCUMENT ME!
     * @throws  PasswordEncrypterException  DOCUMENT ME!
     */
    private static byte[] applyCipher(final byte[] bytes, final int mode) {
        if (bytes == null) {
            throw new IllegalArgumentException("given bytes must not be null"); // NOI18N
        }

        Cipher pbeCipher = null;
        SecretKey pbeKey = null;
        try {
            final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(FACTORY);
            pbeKey = keyFactory.generateSecret(new PBEKeySpec(getMasterPw()));
            pbeCipher = Cipher.getInstance(CIPHER);
            pbeCipher.init(mode, pbeKey, new PBEParameterSpec(getSalt(), ITERATIONS));

            final byte[] res = pbeCipher.doFinal(bytes);

            return res;
        } catch (final Exception ex) {
            final String message = "cannot process string: mode=" + mode; // NOI18N
            LOG.error(message, ex);
            throw new PasswordEncrypterException(message, ex);
        } finally {
            // ensure re-init for wiping the cipher, when the cipher is initialised, the key is initialised, too
            if (pbeCipher != null) {
                try {
                    pbeCipher.init(mode, pbeKey, new PBEParameterSpec(getSalt(), ITERATIONS));
                } catch (final Exception ex) {
                    LOG.warn("cannot re-init the cipher", ex); // NOI18N
                }
            }
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @return  DOCUMENT ME!
     *
     * @throws  PasswordEncrypterException  DOCUMENT ME!
     */
    private static char[] getMasterPw() throws PasswordEncrypterException {
        final InputStream peStream = PasswordEncrypter.class.getResourceAsStream("PasswordEncrypter.properties");

        if (peStream == null) {
            final String message = "PasswordEncrypter properties not present"; // NOI18N
            LOG.error(message);
            throw new PasswordEncrypterException(message);
        } else {
            // we deal with ASCII only
            final byte[] bytes = safeRead(peStream, PE_MASTERKEY_PROP);
            if (bytes == null) {
                final String message = "cannot read master password from properties, not set?"; // NOI18N
                throw new PasswordEncrypterException(message);
            }

            // simple cast because of ASCII only support
            final char[] chars = new char[bytes.length];
            for (int i = 0; i < bytes.length; ++i) {
                chars[i] = (char)bytes[i];
                bytes[i] = getWipe();
            }

            return chars;
        }
    }

    /**
     * Always 8 bytes.
     *
     * @return  DOCUMENT ME!
     *
     * @throws  PasswordEncrypterException  DOCUMENT ME!
     */
    private static byte[] getSalt() throws PasswordEncrypterException {
        final InputStream peStream = PasswordEncrypter.class.getResourceAsStream("PasswordEncrypter.properties");

        if (peStream == null) {
            final String message = "PasswordEncrypter properties not present"; // NOI18N
            LOG.error(message);
            throw new PasswordEncrypterException(message);
        } else {
            final byte[] salt = safeRead(peStream, PE_SALT_PROP);
            if (salt == null) {
                LOG.warn("salt not set, using default salt");                  // NOI18N

                return DEFAULT_SALT;
            } else if (salt.length < 8) {
                LOG.warn("salt too short, filling up with default salt"); // NOI18N
                final byte[] newSalt = new byte[8];
                for (int i = 0; i < 8; ++i) {
                    if (i < salt.length) {
                        newSalt[i] = salt[i];
                        salt[i] = getWipe();
                    } else {
                        newSalt[i] = DEFAULT_SALT[i];
                    }
                }

                return newSalt;
            } else if (salt.length < 8) {
                LOG.warn("salt too long, stripping first 8 bytes"); // NOI18N
                final byte[] newSalt = new byte[8];
                for (int i = 0; i < salt.length; ++i) {
                    if (i < newSalt.length) {
                        newSalt[i] = salt[i];
                        salt[i] = getWipe();
                    } else {
                        salt[i] = getWipe();
                    }
                }

                return newSalt;
            } else {
                return salt;
            }
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @param   bytes      DOCUMENT ME!
     * @param   wipeInput  DOCUMENT ME!
     *
     * @return  DOCUMENT ME!
     *
     * @throws  IllegalArgumentException  DOCUMENT ME!
     */
    public static char[] charsFromBytes(final byte[] bytes, final boolean wipeInput) {
        if ((bytes.length % 2) != 0) {
            throw new IllegalArgumentException("cannot convert odd number of bytes");
        }

        final char[] chars = new char[bytes.length >> 1];
        for (int i = 0; i < chars.length; ++i) {
            final int p = i << 1;
            chars[i] = (char)(((bytes[p] & 0x00FF) << 8) + (bytes[p + 1] & 0x00FF));

            if (wipeInput) {
                bytes[p] = getWipe();
                bytes[p + 1] = getWipe();
            }
        }

        return chars;
    }

    /**
     * DOCUMENT ME!
     *
     * @param  bytes  DOCUMENT ME!
     */
    public static void wipe(final byte[] bytes) {
        for (int i = 0; i < bytes.length; ++i) {
            bytes[i] = getWipe();
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @param   chars      DOCUMENT ME!
     * @param   wipeInput  DOCUMENT ME!
     *
     * @return  DOCUMENT ME!
     */
    public static byte[] bytesFromChars(final char[] chars, final boolean wipeInput) {
        final byte[] bytes = new byte[chars.length << 1];
        for (int i = 0; i < chars.length; ++i) {
            final int p = i << 1;
            bytes[p] = (byte)((chars[i] & 0xFF00) >> 8);
            bytes[p + 1] = (byte)(chars[i] & 0x00FF);

            if (wipeInput) {
                chars[i] = (char)getWipe();
            }
        }

        return bytes;
    }

    /**
     * DOCUMENT ME!
     *
     * @param  chars  DOCUMENT ME!
     */
    public static void wipe(final char[] chars) {
        for (int i = 0; i < chars.length; ++i) {
            chars[i] = (char)getWipe();
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @return  DOCUMENT ME!
     */
    public static byte getWipe() {
        RANDOM.setSeed(System.nanoTime());
        final byte[] wipe = new byte[1];
        RANDOM.nextBytes(wipe);

        return wipe[0];
    }

    /**
     * Reads a property as safe as possible. This operation is completely char[] based and won't put any property values
     * into {@link String} objects. The given stream will be used as is, it won't be closed nor reset. However, if the
     * {@link InputStream#read()} operation of this implementation will change some markers or similar they won't be
     * reset, too.
*
* *

IMPORTANT: Properties are supposed to be separated by a single '=' and terminated by a line feed or EOF.

*
* *

IMPORTANT: Only ASCII encoded properties are currently supported

* * @param propertyStream the stream to read from * @param property the property to read * * @return the value of the property in a byte[] * * @throws PasswordEncrypterException DOCUMENT ME! */ public static byte[] safeRead(final InputStream propertyStream, final char[] property) throws PasswordEncrypterException { // TODO: optimise parser try { int c; int mark = 0; boolean comment = false; boolean firstChar = true; while ((c = propertyStream.read()) > 0) { if (firstChar && (c == '#')) { comment = true; firstChar = false; } else if (c == LF) { firstChar = true; comment = false; } else if (comment) { firstChar = false; } else if ((property.length > mark) && (c == property[mark])) { firstChar = false; mark++; } else if ((c == '=') && (property.length == mark)) { // read the property value byte[] bytes = new byte[100]; int p; int index = 0; while (((p = propertyStream.read()) > 0) && (p != LF)) { bytes[index] = (byte)p; index++; final byte[] tmp = new byte[bytes.length + 100]; if (index == bytes.length) { // resize and wipe for (int i = 0; i < bytes.length; ++i) { tmp[i] = bytes[i]; bytes[i] = getWipe(); } bytes = tmp; } } // resize final byte[] tmp = new byte[index]; for (int i = 0; i < tmp.length; ++i) { // copy and wipe tmp[i] = bytes[i]; bytes[i] = getWipe(); } return tmp; } else { // mismatching property key, reset marker mark = 0; firstChar = false; } } } catch (final IOException ex) { final String message = "cannot read password from properties"; // NOI18N LOG.error(message, ex); throw new PasswordEncrypterException(message, ex); } return null; } }
File
PasswordEncrypter.java
Developer's decision
Version 1
Kind of conflict
Class declaration
Comment
Import
Package declaration