0

I am trying to write a password encryption class that I can use to encrypt and store user passwords. I want to make sure that I am doing this correctly. This code works fine and appears to generate an encrypted password, but I wanted to post it here to get some feedback. For me, this is fairly complicated, and I know with anything in crypto, it's easy to make mistakes without realizing that you are making them.

Here is my code:

    public CipherHandler {

        public String encryptPassword(char[] plaintext, String encoding) throws Exception {

            MessageDigest msgDigest = null;
            String hashValue = null;

            /* Convert char array plaintext to byte array */
            byte[] b = new byte[plaintext.length << 1];
            for (int i = 0; i < plaintext.length; i++) {
                b[i] = (byte) plaintext[i]; //will this work regardless of encoding?
            }

            try {
                msgDigest = MessageDigest.getInstance("SHA-256");
                msgDigest.update(b);
                byte rawByte[] = msgDigest.digest();
                hashValue = (new BASE64Encoder()).encode(rawByte);
            } catch (NoSuchAlgorithmException e) {
                System.out.println("No Such Algorithm Exists");
            }

            System.out.println(hashValue);
            return hashValue;
        }            
    }

This function will generally be called from a Swing event handler where the user will enter their password into a JPassword field, which is why I am starting with a char[]. For testing, I am using this code to call the function:

CipherHandler cp = new CipherHandler();
String initPW;
try {
    initPW = cp.encryptPassword("welcome".toCharArray(), "UTF-8");
}

As this is my first attempt at this, I imagine that I have overlooked something. I'm interested in any advice or comments. I do have a couple of specific questions, though:

  1. When I convert the char[] to a byte[], I don't trust that I am doing this correctly. How do I know which encoding to use? Here, I put "UTF-8" in, mostly as a placeholder, but I am concerned that this may fail in some circumstances.

  2. I have read that I should be using salt and iterations after the password has been digested, but I can't figure out how to do this. Can somebody please advise me on this?

  3. I am using SHA-256. Is this the suggested algorithm? I have read about MD5, also. Is there one algorithm that is preferable for password encryption?

Thanks for any help. I appreciate it!

Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
AndroidDev
  • 20,466
  • 42
  • 148
  • 239
  • 3
    See [How to securely hash passwords?](http://security.stackexchange.com/questions/211/how-to-securely-hash-passwords). SHA-256 is inappropriate for password hashing, and you need a salt. – CodesInChaos Apr 08 '13 at 18:35

2 Answers2

1

Typically passwords are stored by being hashed rather than by being encrypted.

MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest(password.getBytes("UTF-8"));

Then compare the newly generated hash to the hash that you've stored in your database or wherever.

It's also a good idea to salt the password - this is a plaintext value that you append to the password prior to hashing it. This makes it more difficult for somebody to perform an offline brute force attack.

Zim-Zam O'Pootertoot
  • 17,888
  • 4
  • 41
  • 69
  • 2
    Salting is not enough, you need an expensive hash as well. Preferable scrypt, bcrypt or PBKDF2, but iterated SHA-2 is okay as well. Single iteration SHA-2 is not okay. – CodesInChaos Apr 08 '13 at 18:36
  • Thanks. How is the code that you are posting different than mine? You are using a string password (presumably), which I have read is a bad idea since they are immutable and can live in memory for a while. I am using a char[], which takes a couple of more steps to convert into a byte[], but as I compare these two code snippets, they both use a MessageDigest variable and digest that variable. I turn my encrypted (hashed) password back into a string for return purposes, but they look fundamentally the same. Am I missing something? Thanks! – AndroidDev Apr 08 '13 at 18:40
  • I agree with you about salting. Can someone suggest how I do that? I'm stuck on this point. – AndroidDev Apr 08 '13 at 18:41
  • this shows some way http://stackoverflow.com/a/2861125/1083581 and this has a complete sample http://stackoverflow.com/a/11038230/1083581 – happybuddha Apr 08 '13 at 18:47
  • Use byte[] salt = new byte[16], new Random().nextBytes(salt) to generate the salt - you can use SecureRandom instead, but this doesn't add much since the salt isn't secret. Then use System.arraycopy to copy the salt and password to an array, hash it, and delete it. – Zim-Zam O'Pootertoot Apr 08 '13 at 18:47
0

MD5 is dead and UTF-8 should probably the least of your worries. Read this
Of course, depending on your purpose of crypting your passwords(depending on what type of target audience you got), if you search long enough in the security stackexchange, youd prolly find a complete answer to your challenge.

Just my $0.02

Community
  • 1
  • 1
happybuddha
  • 1,271
  • 2
  • 20
  • 40