Encrypting passwords using Java

Discussion in 'Java' started by Andy Grove, Feb 12, 2004.

  1. Andy Grove

    Andy Grove Guest

    I've just spent the best part of an hour tracking down the right
    information to get password encryption/decryption and
    storage/retrieval of secret keys working. I've created this utility
    class which now serves my needs and I am posting it here in the hope
    that it saves other people some time. Enjoy ;-)

    Andy Grove.
    http://www.codefutures.com/weblog/andygrove


    /**
    * Utility class to encrypt and decrypt passwords using Java
    cryptography.
    */

    package com.codefutures.security;

    import sun.misc.BASE64Encoder;
    import sun.misc.BASE64Decoder;

    import javax.crypto.Cipher;
    import javax.crypto.SecretKey;
    import javax.crypto.KeyGenerator;
    import javax.crypto.spec.SecretKeySpec;
    import java.security.*;
    import java.io.IOException;

    public class PasswordUtil
    {
    private static final String CIPHER_TYPE = "DES/ECB/PKCS5Padding";

    public static String encrypt(String password, Key key)
    {
    try {
    Cipher cipher = Cipher.getInstance(CIPHER_TYPE);
    cipher.init(Cipher.ENCRYPT_MODE, key);

    byte[] outputBytes = cipher.doFinal( password.getBytes()
    );

    BASE64Encoder encoder = new BASE64Encoder();
    String base64 = encoder.encode(outputBytes);

    return base64;
    }
    catch (Exception e) {
    throw new RuntimeException( "Failed to encrypt password",
    e );
    }
    }

    public static String decrypt(String password, Key key)
    {
    try {
    BASE64Decoder decoder = new BASE64Decoder();
    byte encrypted[] = decoder.decodeBuffer(password);

    Cipher cipher = Cipher.getInstance(CIPHER_TYPE);
    cipher.init(Cipher.DECRYPT_MODE, key);

    byte[] outputBytes = cipher.doFinal( encrypted );
    String ret = new String( outputBytes );

    return ret;
    }
    catch (Exception e) {
    throw new RuntimeException( "Failed to decrypt password",
    e );
    }
    }

    /**
    * Create a key for use in the cipher code
    */
    public static Key generateRandomKey()
    throws NoSuchAlgorithmException
    {
    KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
    keyGenerator.init(new SecureRandom());
    SecretKey secretKey = keyGenerator.generateKey();
    return secretKey;
    }

    /**
    * Encode a secret key as a string that can be stored for later
    use.
    *
    * @param key
    * @return
    */
    public static String encodeKey(Key key)
    {
    BASE64Encoder encoder = new BASE64Encoder();
    return encoder.encode(key.getEncoded());
    }

    /**
    * Reconstruct a secret key from a string representation.
    *
    * @param encodedKey
    * @return
    * @throws IOException
    */
    public static Key decodeKey(String encodedKey)
    throws IOException
    {
    BASE64Decoder decoder = new BASE64Decoder();
    byte raw[] = decoder.decodeBuffer(encodedKey);
    SecretKey key = new SecretKeySpec( raw, "DES" );
    return key;
    }


    }
     
    Andy Grove, Feb 12, 2004
    #1
    1. Advertising

  2. Andy Grove

    SPG Guest

    Not *the* andy grove from Orbware? Did some time at Knowhow in Woking??

    "Andy Grove" <> wrote in message
    news:...
    > I've just spent the best part of an hour tracking down the right
    > information to get password encryption/decryption and
    > storage/retrieval of secret keys working. I've created this utility
    > class which now serves my needs and I am posting it here in the hope
    > that it saves other people some time. Enjoy ;-)
    >
    > Andy Grove.
    > http://www.codefutures.com/weblog/andygrove
    >
    >
    > /**
    > * Utility class to encrypt and decrypt passwords using Java
    > cryptography.
    > */
    >
    > package com.codefutures.security;
    >
    > import sun.misc.BASE64Encoder;
    > import sun.misc.BASE64Decoder;
    >
    > import javax.crypto.Cipher;
    > import javax.crypto.SecretKey;
    > import javax.crypto.KeyGenerator;
    > import javax.crypto.spec.SecretKeySpec;
    > import java.security.*;
    > import java.io.IOException;
    >
    > public class PasswordUtil
    > {
    > private static final String CIPHER_TYPE = "DES/ECB/PKCS5Padding";
    >
    > public static String encrypt(String password, Key key)
    > {
    > try {
    > Cipher cipher = Cipher.getInstance(CIPHER_TYPE);
    > cipher.init(Cipher.ENCRYPT_MODE, key);
    >
    > byte[] outputBytes = cipher.doFinal( password.getBytes()
    > );
    >
    > BASE64Encoder encoder = new BASE64Encoder();
    > String base64 = encoder.encode(outputBytes);
    >
    > return base64;
    > }
    > catch (Exception e) {
    > throw new RuntimeException( "Failed to encrypt password",
    > e );
    > }
    > }
    >
    > public static String decrypt(String password, Key key)
    > {
    > try {
    > BASE64Decoder decoder = new BASE64Decoder();
    > byte encrypted[] = decoder.decodeBuffer(password);
    >
    > Cipher cipher = Cipher.getInstance(CIPHER_TYPE);
    > cipher.init(Cipher.DECRYPT_MODE, key);
    >
    > byte[] outputBytes = cipher.doFinal( encrypted );
    > String ret = new String( outputBytes );
    >
    > return ret;
    > }
    > catch (Exception e) {
    > throw new RuntimeException( "Failed to decrypt password",
    > e );
    > }
    > }
    >
    > /**
    > * Create a key for use in the cipher code
    > */
    > public static Key generateRandomKey()
    > throws NoSuchAlgorithmException
    > {
    > KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
    > keyGenerator.init(new SecureRandom());
    > SecretKey secretKey = keyGenerator.generateKey();
    > return secretKey;
    > }
    >
    > /**
    > * Encode a secret key as a string that can be stored for later
    > use.
    > *
    > * @param key
    > * @return
    > */
    > public static String encodeKey(Key key)
    > {
    > BASE64Encoder encoder = new BASE64Encoder();
    > return encoder.encode(key.getEncoded());
    > }
    >
    > /**
    > * Reconstruct a secret key from a string representation.
    > *
    > * @param encodedKey
    > * @return
    > * @throws IOException
    > */
    > public static Key decodeKey(String encodedKey)
    > throws IOException
    > {
    > BASE64Decoder decoder = new BASE64Decoder();
    > byte raw[] = decoder.decodeBuffer(encodedKey);
    > SecretKey key = new SecretKeySpec( raw, "DES" );
    > return key;
    > }
    >
    >
    > }
     
    SPG, Feb 12, 2004
    #2
    1. Advertising

  3. Andy Grove

    Andy Grove Guest

    Yes, the very same! I'll drop you a line separately ...


    "SPG" <> wrote in message news:<_NIWb.2602$>...
    > Not *the* andy grove from Orbware? Did some time at Knowhow in Woking??
    >
    > "Andy Grove" <> wrote in message
    > news:...
    > > I've just spent the best part of an hour tracking down the right
    > > information to get password encryption/decryption and
    > > storage/retrieval of secret keys working. I've created this utility
    > > class which now serves my needs and I am posting it here in the hope
    > > that it saves other people some time. Enjoy ;-)
    > >
    > > Andy Grove.
    > > http://www.codefutures.com/weblog/andygrove
    > >
    > >
    > > /**
    > > * Utility class to encrypt and decrypt passwords using Java
    > > cryptography.
    > > */
    > >
    > > package com.codefutures.security;
    > >
    > > import sun.misc.BASE64Encoder;
    > > import sun.misc.BASE64Decoder;
    > >
    > > import javax.crypto.Cipher;
    > > import javax.crypto.SecretKey;
    > > import javax.crypto.KeyGenerator;
    > > import javax.crypto.spec.SecretKeySpec;
    > > import java.security.*;
    > > import java.io.IOException;
    > >
    > > public class PasswordUtil
    > > {
    > > private static final String CIPHER_TYPE = "DES/ECB/PKCS5Padding";
    > >
    > > public static String encrypt(String password, Key key)
    > > {
    > > try {
    > > Cipher cipher = Cipher.getInstance(CIPHER_TYPE);
    > > cipher.init(Cipher.ENCRYPT_MODE, key);
    > >
    > > byte[] outputBytes = cipher.doFinal( password.getBytes()
    > > );
    > >
    > > BASE64Encoder encoder = new BASE64Encoder();
    > > String base64 = encoder.encode(outputBytes);
    > >
    > > return base64;
    > > }
    > > catch (Exception e) {
    > > throw new RuntimeException( "Failed to encrypt password",
    > > e );
    > > }
    > > }
    > >
    > > public static String decrypt(String password, Key key)
    > > {
    > > try {
    > > BASE64Decoder decoder = new BASE64Decoder();
    > > byte encrypted[] = decoder.decodeBuffer(password);
    > >
    > > Cipher cipher = Cipher.getInstance(CIPHER_TYPE);
    > > cipher.init(Cipher.DECRYPT_MODE, key);
    > >
    > > byte[] outputBytes = cipher.doFinal( encrypted );
    > > String ret = new String( outputBytes );
    > >
    > > return ret;
    > > }
    > > catch (Exception e) {
    > > throw new RuntimeException( "Failed to decrypt password",
    > > e );
    > > }
    > > }
    > >
    > > /**
    > > * Create a key for use in the cipher code
    > > */
    > > public static Key generateRandomKey()
    > > throws NoSuchAlgorithmException
    > > {
    > > KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
    > > keyGenerator.init(new SecureRandom());
    > > SecretKey secretKey = keyGenerator.generateKey();
    > > return secretKey;
    > > }
    > >
    > > /**
    > > * Encode a secret key as a string that can be stored for later
    > > use.
    > > *
    > > * @param key
    > > * @return
    > > */
    > > public static String encodeKey(Key key)
    > > {
    > > BASE64Encoder encoder = new BASE64Encoder();
    > > return encoder.encode(key.getEncoded());
    > > }
    > >
    > > /**
    > > * Reconstruct a secret key from a string representation.
    > > *
    > > * @param encodedKey
    > > * @return
    > > * @throws IOException
    > > */
    > > public static Key decodeKey(String encodedKey)
    > > throws IOException
    > > {
    > > BASE64Decoder decoder = new BASE64Decoder();
    > > byte raw[] = decoder.decodeBuffer(encodedKey);
    > > SecretKey key = new SecretKeySpec( raw, "DES" );
    > > return key;
    > > }
    > >
    > >
    > > }
     
    Andy Grove, Feb 12, 2004
    #3
  4. Andy Grove

    Jon A. Cruz Guest

    Andy Grove wrote:


    > byte[] outputBytes = cipher.doFinal( password.getBytes()


    BIG problem right there.

    You've just made a call that will, given the same inputs, return
    different results depending on the time of day, users whim, etc.

    Especially with cryptography, never call String.getBytes(). Instead
    always use String.getBytes(String) and feed it a known, proper encoding.


    > byte[] outputBytes = cipher.doFinal( encrypted );
    > String ret = new String( outputBytes );


    And the same thing applies here. Instead of leaving things up to the
    whim of the default platform encoding of the moment, instead give it an
    explicit encoding. Use new String(byte[], String) instead of new
    String(byte[]).
     
    Jon A. Cruz, Feb 12, 2004
    #4
  5. Andy Grove

    Matt Parker Guest

    Jon A. Cruz wrote:

    > Andy Grove wrote:
    >
    >
    >> byte[] outputBytes = cipher.doFinal( password.getBytes()

    >
    > BIG problem right there.
    >
    > You've just made a call that will, given the same inputs, return
    > different results depending on the time of day, users whim, etc.
    >
    > Especially with cryptography, never call String.getBytes(). Instead
    > always use String.getBytes(String) and feed it a known, proper encoding.
    >
    >
    >> byte[] outputBytes = cipher.doFinal( encrypted );
    >> String ret = new String( outputBytes );

    >
    > And the same thing applies here. Instead of leaving things up to the
    > whim of the default platform encoding of the moment, instead give it an
    > explicit encoding. Use new String(byte[], String) instead of new
    > String(byte[]).


    Also, the OP shouldn't really be using the sun.misc.* packages. These are
    not part of the API and are subject to change at the whim of Sun.

    Matt

    --
    Not so interesting...
    http://www.mpcontracting.co.uk
     
    Matt Parker, Feb 12, 2004
    #5
  6. Andy Grove

    Anton Spaans Guest

    "Andy Grove" <> wrote in message
    news:...
    > I've just spent the best part of an hour tracking down the right
    > information to get password encryption/decryption and
    > storage/retrieval of secret keys working. I've created this utility
    > class which now serves my needs and I am posting it here in the hope
    > that it saves other people some time. Enjoy ;-)
    >
    > Andy Grove.
    > http://www.codefutures.com/weblog/andygrove
    >
    >
    > /**
    > * Utility class to encrypt and decrypt passwords using Java
    > cryptography.
    > */
    >
    > package com.codefutures.security;
    >
    > import sun.misc.BASE64Encoder;
    > import sun.misc.BASE64Decoder;
    >
    > import javax.crypto.Cipher;
    > import javax.crypto.SecretKey;
    > import javax.crypto.KeyGenerator;
    > import javax.crypto.spec.SecretKeySpec;
    > import java.security.*;
    > import java.io.IOException;
    >
    > public class PasswordUtil
    > {
    > private static final String CIPHER_TYPE = "DES/ECB/PKCS5Padding";
    >
    > public static String encrypt(String password, Key key)
    > {
    > try {
    > Cipher cipher = Cipher.getInstance(CIPHER_TYPE);
    > cipher.init(Cipher.ENCRYPT_MODE, key);
    >
    > byte[] outputBytes = cipher.doFinal( password.getBytes()
    > );
    >
    > BASE64Encoder encoder = new BASE64Encoder();
    > String base64 = encoder.encode(outputBytes);
    >
    > return base64;
    > }
    > catch (Exception e) {
    > throw new RuntimeException( "Failed to encrypt password",
    > e );
    > }
    > }
    >
    > public static String decrypt(String password, Key key)
    > {
    > try {
    > BASE64Decoder decoder = new BASE64Decoder();
    > byte encrypted[] = decoder.decodeBuffer(password);
    >
    > Cipher cipher = Cipher.getInstance(CIPHER_TYPE);
    > cipher.init(Cipher.DECRYPT_MODE, key);
    >
    > byte[] outputBytes = cipher.doFinal( encrypted );
    > String ret = new String( outputBytes );
    >
    > return ret;
    > }
    > catch (Exception e) {
    > throw new RuntimeException( "Failed to decrypt password",
    > e );
    > }
    > }
    >
    > /**
    > * Create a key for use in the cipher code
    > */
    > public static Key generateRandomKey()
    > throws NoSuchAlgorithmException
    > {
    > KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
    > keyGenerator.init(new SecureRandom());
    > SecretKey secretKey = keyGenerator.generateKey();
    > return secretKey;
    > }
    >
    > /**
    > * Encode a secret key as a string that can be stored for later
    > use.
    > *
    > * @param key
    > * @return
    > */
    > public static String encodeKey(Key key)
    > {
    > BASE64Encoder encoder = new BASE64Encoder();
    > return encoder.encode(key.getEncoded());
    > }
    >
    > /**
    > * Reconstruct a secret key from a string representation.
    > *
    > * @param encodedKey
    > * @return
    > * @throws IOException
    > */
    > public static Key decodeKey(String encodedKey)
    > throws IOException
    > {
    > BASE64Decoder decoder = new BASE64Decoder();
    > byte raw[] = decoder.decodeBuffer(encodedKey);
    > SecretKey key = new SecretKeySpec( raw, "DES" );
    > return key;
    > }
    >
    >
    > }


    I think it's better to use Java's MessageDigesters to generate hash-values
    out of passwords (SHA, MD5 digesters). These hash-values can not be
    decrypted ever (with reasonable resources), but they satisfy the 'equal'
    constraint (if two passwords (strings) are the same, their hash-value is the
    same). You get the encrypted (using SHA or MD5) hash-value from the user. If
    this hash-value is the same as the hash-value you've stored in your
    database, then the user can be authenticated.

    For protection against network eaves-dropping (and if you don't mind storing
    passwords in decryptable form in your database), you could modify original
    passwords with a random string (make a hashvalues out of
    "<password>+<modifier>", for example). Each request will generate a new
    randomly generated modifier.

    -- Anton Spaans.
     
    Anton Spaans, Feb 12, 2004
    #6
  7. Andy Grove

    Andy Grove Guest

    "Jon A. Cruz" <> wrote in message news:<>...
    > Andy Grove wrote:
    >
    >
    > > byte[] outputBytes = cipher.doFinal( password.getBytes()

    >
    > BIG problem right there.
    >
    > You've just made a call that will, given the same inputs, return
    > different results depending on the time of day, users whim, etc.
    >
    > Especially with cryptography, never call String.getBytes(). Instead
    > always use String.getBytes(String) and feed it a known, proper encoding.
    >
    >
    > > byte[] outputBytes = cipher.doFinal( encrypted );
    > > String ret = new String( outputBytes );

    >
    > And the same thing applies here. Instead of leaving things up to the
    > whim of the default platform encoding of the moment, instead give it an
    > explicit encoding. Use new String(byte[], String) instead of new
    > String(byte[]).



    Thanks for pointing that one out. I've introduced a DEFAULT_ENCODING
    constant with a value of "UTF-8" and I'm passing that into the methods
    you highlighted.

    Cheers,

    Andy Grove
    http://www.codefutures.com/weblog/andygrove
     
    Andy Grove, Feb 13, 2004
    #7
  8. Andy Grove

    Jon A. Cruz Guest

    Andy Grove wrote:
    >
    > Thanks for pointing that one out. I've introduced a DEFAULT_ENCODING
    > constant with a value of "UTF-8" and I'm passing that into the methods
    > you highlighted.


    Glad I could help.

    Next minor gotchas:

    1) On older VM's, the string used was "UTF8" and not the proper "UTF-8". :)

    2) On some systems, where it's still a requirement by the specs, many
    vendors don't support that at all. This is mainly J2ME.
     
    Jon A. Cruz, Feb 14, 2004
    #8
  9. Andy Grove <> scribbled the following:
    > Yes, the very same! I'll drop you a line separately ...


    > "SPG" <> wrote in message news:<_NIWb.2602$>...
    >> Not *the* andy grove from Orbware? Did some time at Knowhow in Woking??


    And for *that* you two had to quote the whole 100+ -line program?

    --
    /-- Joona Palaste () ------------- Finland --------\
    \-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
    "The trouble with the French is they don't have a word for entrepreneur."
    - George Bush
     
    Joona I Palaste, Feb 14, 2004
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Elliot M. Rodriguez

    Impersonation Question - Encrypting Passwords

    Elliot M. Rodriguez, Nov 4, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    412
    Elliot M. Rodriguez
    Nov 4, 2003
  2. =?Utf-8?B?VGF5bw==?=

    Encrypting Passwords

    =?Utf-8?B?VGF5bw==?=, May 27, 2004, in forum: ASP .Net
    Replies:
    3
    Views:
    376
    Nick Gilbert
    May 27, 2004
  3. Replies:
    2
    Views:
    418
    Michael Borgwardt
    Apr 15, 2004
  4. Ben Knight
    Replies:
    0
    Views:
    138
    Ben Knight
    Feb 8, 2009
  5. TheDeerHunter

    Encrypting long passwords

    TheDeerHunter, Mar 26, 2007, in forum: Perl Misc
    Replies:
    5
    Views:
    155
    bytebro
    Mar 26, 2007
Loading...

Share This Page