0

How to cut/copy the password in the JPasswordField into the clipboard by using the non-String API. Thereby closing a window for the hacker to see the password.

According to this link https://stackoverflow.com/a/8885343/2534090 the char array is different from the text.

public static void main(String[] args) {
    Object pw = "Password";
    System.out.println("String: " + pw);

    pw = "Password".toCharArray();
    System.out.println("Array: " + pw);
}

Prints:

String: Password
Array: [C@5829428e

What i want to be in the clipboard is [C@5829428e but not Password

I tried using StringSelection to copy the contents in the clipboard but it's constructor takes a String which is immutable and not safe.

Community
  • 1
  • 1
JavaTechnical
  • 8,846
  • 8
  • 61
  • 97
  • 1
    I am really confused while reading your question. You want to get the char-Array of a JPasswordField and have already found the method for this. What do you exactly want to do with the password? – snrlx Jul 17 '13 at 17:46
  • this might give you some heads up: http://stackoverflow.com/questions/17706393/how-do-enable-cut-copy-in-jpasswordfield – Nitesh Verma Jul 17 '13 at 17:47
  • See when you print the char array, you get a different output, when you print the getText() you get the text (i.e. the password). Now my question is how to get that different output into clipboard! – JavaTechnical Jul 17 '13 at 17:48
  • When you print the char array how? The char array contains the password just like the String does. – user207421 Jul 18 '13 at 01:46
  • @EJP See this link http://stackoverflow.com/a/8885343/2534090 – JavaTechnical Jul 18 '13 at 05:58
  • Are you referring to the fact that char[].toString() doesn't reveal the contents? – user207421 Jul 18 '13 at 11:32

1 Answers1

1

You can use a custom TransferHandler to do this.

According to the section from the Swing tutorial on Using and Creating a Data Flavor you should be able to use the char[] as the object written to the clipboard.

However, I couldn't get it working and ended up writing a StringBuilder to the clipboard. I commented out the code were I attempted to use the char[], maybe someone else can figure out what I did wrong.

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
import java.io.*;

public class PasswordHandler extends TransferHandler
{
//  public final static DataFlavor CHAR_ARRAY_FLAVOR = new DataFlavor(char[].class, "Char Array");
    public final static DataFlavor CHAR_ARRAY_FLAVOR = new DataFlavor(StringBuilder.class, "StringBuilder");

    @Override
    public int getSourceActions(JComponent c)
    {
        return COPY;
    }

    @Override
    public Transferable createTransferable(final JComponent c)
    {
        return new Transferable()
        {
            @Override
            public Object getTransferData(DataFlavor flavor)
            {
                JPasswordField textField = (JPasswordField)c;
//              return textField.getPassword();
                return new StringBuilder( textField.getText() );
            }

            @Override
            public DataFlavor[] getTransferDataFlavors()
            {
                DataFlavor[] flavors = new DataFlavor[1];
                flavors[0] = CHAR_ARRAY_FLAVOR;
                return flavors;
            }

            @Override
            public boolean isDataFlavorSupported(DataFlavor flavor)
            {
                return flavor.equals(CHAR_ARRAY_FLAVOR);
            }
        };
    }

    @Override
    public boolean canImport(TransferSupport support)
    {
        boolean canImport = support.isDataFlavorSupported(CHAR_ARRAY_FLAVOR);
        return canImport;
    }

    @Override
    public boolean importData(TransferSupport support)
    {
//      char[] password;
        StringBuilder password;

        try
        {
//          password = (char[])support.getTransferable().getTransferData(CHAR_ARRAY_FLAVOR);
            password = (StringBuilder)support.getTransferable().getTransferData(CHAR_ARRAY_FLAVOR);
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return false;
        }

        JPasswordField textField = (JPasswordField)support.getComponent();
        textField.setText(password.toString());
        return true;
    }

    private static void createAndShowUI()
    {
        JPasswordField tf1 = new JPasswordField(10);
        JPasswordField tf2 = new JPasswordField(10);

        TransferHandler handler = new PasswordHandler();
        tf1.setTransferHandler( handler );
        tf2.setTransferHandler( handler );
        tf1.putClientProperty("JPasswordField.cutCopyAllowed",true);
        tf2.putClientProperty("JPasswordField.cutCopyAllowed",true);

        JFrame frame = new JFrame("Password Copy");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(tf1, BorderLayout.WEST);
        frame.add(tf2, BorderLayout.EAST);
        frame.add(new JTextField(), BorderLayout.SOUTH);
        frame.pack();
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}

The code takes the entire text from the password field. If you only want the selected characters then you will need to modify the getTransferData() method to only add the selected characters to the StringBuilder.

camickr
  • 321,443
  • 19
  • 166
  • 288