Home » Java » Core Java » Secure Password Storage – Don’ts, dos and a Java example

About Jerry Orr

Jerry Orr is a software developer who currently spends most of his time on Java web applications. He has worked in a variety of domains, including commercial software, higher education, state government, and federal government.

Secure Password Storage – Don’ts, dos and a Java example

The importance of storing passwords securely
As software developers, one of our most important responsibilities is the protection of our users’ personal information. Without technical knowledge of our applications, users have no choice but to trust that we’re fulfilling this responsibility. Sadly, when it comes to passwords, the software development community has a spotty track record.
While it’s impossible to build a 100% secure system, there are fortunately some simple steps we can take to make our users’ passwords safe enough to send would-be hackers in search of easier prey.
If you don’t want all the background, feel free to skip to the Java SE example below.
The Don’ts
First, let’s quickly discuss some of the things you shouldn’t do when building an application that requires authentication:
  • Don’t store authentication data unless you really have to. This may seem like a cop-out, but before you start building a database of user credentials, consider letting someone else handle it. If you’re building a public application, consider using OAuth providers such as Google or Facebook. If you’re building an internal enterprise application, consider using any internal authentication services that may already exist, like a corporate LDAP or Kerberos service. Whether it’s a public or internal application, your users will appreciate not needing to remember another user ID and password, and it’s one less database out there for hackers to attack.
  • If you must store authentication data, for Gosling’s sake don’t store the passwords in clear text. This should be obvious, but it bears mentioning. Let’s at least make the hackers break a sweat.
  • Don’t use two-way encryption unless you really need to retrieve the clear-text password. You only need to know their clear-text password if you are using their credentials to interact with an external system on their behalf. Even then, you’re better off having the user authenticate with that system directly. To be clear, you do not need to use the user’s original clear-text password to perform authentication in your application. I’ll go into more detail on this later, but when performing authentication, you will be applying an encryption algorithm to the password the user entered and comparing it to the encrypted password you’ve stored.
  • Don’t use outdated hashing algorithms like MD5. Honestly, hashing a password with MD5 is virtually useless. Here’s an MD5-hashed password: 569a70c2ccd0ac41c9d1637afe8cd932. Go to http://www.md5hacker.com/ and you can decrypt it in seconds.
  • Don’t come up with your own encryption scheme. There are a handful of brilliant encryption experts in the world that are capable of outwitting hackers and devising a new encryption algorithm. I am not one of them, and most likely, neither are you. If a hacker gets access to your user database, they can probably get your code too. Unless you’ve invented the next great successor to PBKDF2 or bcrypt, they will be cackling maniacally as they quickly crack all your users’ passwords and publish them on the darknet.
The Dos
Okay, enough lecturing on what not to do. Here are the things you need to focus on:
  • Choose a one-way encryption algorithm. As I mentioned above, once you’ve encrypted and stored a user’s password, you never need to know the real value again. When a user attempts to authenticate, you’ll just apply the same algorithm to the password they entered, and compare that to the encrypted password that you stored.
  • Make the encryption as slow as your application can tolerate. Any modern password encryption algorithm should allow you to provide parameters that increase the time needed to encrypt a password (i.e. in PBKDF2, specifying the number of iterations). Why is slow good? Your users won’t notice if it takes an extra 100ms to encrypt their password, but a hacker trying a brute-force attack will notice the difference as they run the algorithm billions of times.
  • Pick a well-known algorithm. The National Institute of Standards and Technology (NIST) recommends PBKDF2 for passwords. bcrypt is a popular and established alternative, and scrypt is a relatively new algorithm that has been well-received. All these are popular for a reason: they’re good.
PBKDF2
Before I give show you some concrete code, let’s talk a little about why PBKDF2 is a good choice for encrypting passwords:
  • Recommended by the NIST. Section 5.3 of Special Publication 800-132 recommends PBKDF2 for encrypting passwords. Security officials will love that.
  • Adjustable key stretching to defeat brute force attacks. The basic idea of key stretching is that after you apply your hashing algorithm to the password, you then continue to apply the same algorithm to the result many times (the iteration count). If hackers are trying to crack your passwords, this greatly increases the time it takes to try the billions of possible passwords. As mentioned previously, the slower, the better. PBKDF2 lets you specify the number of iterations to apply, allowing you to make it as slow as you like.
  • A required salt to defeat rainbow table attacks and prevent collisions with other users. A salt is a randomly generated sequence of bits that is unique to each user and is added to the user’s password as part of the hashing. This prevents rainbow table attacks by making a precomputed list of results unfeasible. And since each user gets their own salt, even if two users have the same password, the encrypted values will be different. There is a lot of conflicting information out there on whether the salts should be stored someplace separate from the encrypted passwords. Since the key stretching in PBKDF2 already protects us from brute-force attacks, I feel it is unnecessary to try to hide the salt. Section 3.1 of NIST SP 800-132 also defines salt as a “non-secret binary value,” so that’s what I go with.
  • Part of Java SE 6. No additional libraries necessary. This is particularly attractive to those working in environments with restrictive open-source policies.
Finally, a concrete example
Okay, here’s some code to encrypt passwords using PBKDF2. Only Java SE 6 is required.
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Arrays;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

public class PasswordEncryptionService {

 public boolean authenticate(String attemptedPassword, byte[] encryptedPassword, byte[] salt)
   throws NoSuchAlgorithmException, InvalidKeySpecException {
  // Encrypt the clear-text password using the same salt that was used to
  // encrypt the original password
  byte[] encryptedAttemptedPassword = getEncryptedPassword(attemptedPassword, salt);

  // Authentication succeeds if encrypted password that the user entered
  // is equal to the stored hash
  return Arrays.equals(encryptedPassword, encryptedAttemptedPassword);
 }

 public byte[] getEncryptedPassword(String password, byte[] salt)
   throws NoSuchAlgorithmException, InvalidKeySpecException {
  // PBKDF2 with SHA-1 as the hashing algorithm. Note that the NIST
  // specifically names SHA-1 as an acceptable hashing algorithm for PBKDF2
  String algorithm = "PBKDF2WithHmacSHA1";
  // SHA-1 generates 160 bit hashes, so that's what makes sense here
  int derivedKeyLength = 160;
  // Pick an iteration count that works for you. The NIST recommends at
  // least 1,000 iterations:
  // http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf
  // iOS 4.x reportedly uses 10,000:
  // http://blog.crackpassword.com/2010/09/smartphone-forensics-cracking-blackberry-backup-passwords/
  int iterations = 20000;

  KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, derivedKeyLength);

  SecretKeyFactory f = SecretKeyFactory.getInstance(algorithm);

  return f.generateSecret(spec).getEncoded();
 }

 public byte[] generateSalt() throws NoSuchAlgorithmException {
  // VERY important to use SecureRandom instead of just Random
  SecureRandom random = SecureRandom.getInstance("SHA1PRNG");

  // Generate a 8 byte (64 bit) salt as recommended by RSA PKCS5
  byte[] salt = new byte[8];
  random.nextBytes(salt);

  return salt;
 }
}
The flow goes something like this:
  1. When adding a new user, call generateSalt(), then getEncryptedPassword(), and store both the encrypted password and the salt. Do not store the clear-text password. Don’t worry about keeping the salt in a separate table or location from the encrypted password; as discussed above, the salt is non-secret.
  2. When authenticating a user, retrieve the previously encrypted password and salt from the database, then send those and the clear-text password they entered to authenticate(). If it returns true, authentication succeeded.
  3. When a user changes their password, it’s safe to reuse their old salt; you can just call getEncryptedPassword() with the old salt.
Easy enough, right? If you’re building or maintaining an application that violates any of the “don’ts” above, then please do your users a favor and use something like PBKDF2 or bcrypt. Help them, Obi-Wan Developer, you’re their only hope.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

 

1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial

5. Java Interview Questions

6. Spring Interview Questions

7. Android UI Design

 

and many more ....

 

 

51 comments

  1. When authenticating the user, how do we retrieve the salt if we aren’t storing it in the table? I am very interested by your article and have learned a great deal. Just trying to implement now.

  2. What happens if a user forgets their password. Isn’t this a time when it is necessary to access the password in clear text?

    Or is it best to suggest them to create a new password/send them a new password to a registered email address?

    • > What happens if a user forgets their password. Isn’t this a time when it is necessary to access the password in clear text?

      Absolutely not! It should never be possible to retrieve someone’s clear-text password, because if *you* can do it, then someone who has stolen your database can, too. In fact, if a website ever sends you your clear-text password, you know they aren’t doing a good job protecting it.

      If a user forgets his or her password, usually the best thing to do is send a password reset link to their email address.

  3. I have stored salt in salt column and encrypted password in password column at the time of signup by using PBKDF2
    How to apply authenticate() function to authenticate user at login time.

  4. Well written, very helpful, thank you!

  5. Does the encryption / decryption affected by the OS when encrypted originally in Windows and later on retrieved from a Linux system to compare against a clear text password even when the salt are the same?

    • The underlying algorithm (PBKDF2 or bcrypt) is platform-independent. A password hashed with the same salt, algorithm, and algorithm settings (iterations, key length, etc) will be identical on any OS.

  6. I use the above getEncryptedPassword method in two separate programs, both of which query the same database. One program is a stand-alone Java program, the other is a web application deployed to Apache Geronimo. The problem I have is that, using the same plaintext password and salt, I get two different encrypted passwords for the two different programs, and thus I can log on using one program but not the other one. Do you know what could be going on?

    • The algorithm is standard and platform/installation independent. If you are using the same iteration count, salt, and plain-text password, you will get the exact same hash back. Unless there’s a bug in the JRE’s PBKDF2 implementation (very unlikely), I suspect that either the iteration count, salt, or password is different.

      • I (sort of) got to the bottom of what was going wrong. I had changed the method return type from byte[] to String, and converted your final line to “return new String(f.generateSecret(spec).getEncoded());”. Once I changed back to just using a byte[], both programs now work as expected.

  7. Hey Jerry, great tutorial, thanks!

    Just a question: is there a reason to declare these methods non static and thus instantiate the PasswordEncryptionService class?

    Is it safe to declare the class methods to be static?

    • It is technically safe to make them static, as this particular class has no state, but that’s generally an anti-pattern. It’s way too big of a topic to cover in a comment, but it makes it difficult to do things like dependency injection, extension, unit testing, etc. If, say, you decided to give this class a SecretKeyFactory pool injected by Spring, you’d end up making the methods non-static again.

  8. I’ve never really understood this when it comes to command line apps. How do you handle passwords if the application is the user–some scheduled command line app that logs into a site and downloads data for example. It needs the passwords in plain text to login to the site.

    • Storing passwords that you can use on a user’s behalf (what you’re describing) is actually a very different scenario than checking that an active user entered the correct password (the topic of this article).

      Storing a user’s password for later use is a more difficult and dangerous scenario. You of course want to encrypt the password, but if you need to decrypt it in some batch process, you have no choice but to keep the required information to decrypt the password (eg a private certificate or passphrase) on the same system. So anyone who has full access to your system will be able to decrypt those passwords, too.

      The best advice I can offer is to use an appropriate library to assist you when you truly need to be able to decrypt a user’s password for batch use. Something like Vault: https://www.vaultproject.io/

      • I have a password for a server, that I receive encrypted, but need to use it as clear txt in every single req coming to my application. My question is – is it insecure to save it in clear txt, as static member of a class?
        because decrypting every time is expensive, especially when we know it will be same , unless changed manually or the application is restarted.

        • You definitely don’t want to store it in clear text. There are a variety of ways for memory to be leaked or compromised, such as forcing a memory heap dump. You want to keep it in clear text for as short a period as possible. Some developers go as far as to only write it to a char[] and then null out each character when done, instead of waiting for garbage collection to get rid of a String.

          Have you measured how “expensive” decrypting it is? If decrypting it takes 1ms, and your average request is 500ms +/- 100ms, is the 1ms difference really noticeable? If you’re going to sacrifice security for performance, it’d better be for a demonstrably good reason.

  9. This is an incredibly well written article. Thanks a bunch for this very helpful stuff.

    Srikanth

  10. The code is not working for me..Please suggest
    /**
    *
    */
    package com.plant.DAO;

    import java.security.NoSuchAlgorithmException;

    import java.security.SecureRandom;

    import java.security.spec.InvalidKeySpecException;

    import java.security.spec.KeySpec;

    import java.util.Arrays;

    import javax.crypto.SecretKeyFactory;

    import javax.crypto.spec.PBEKeySpec;

    /**
    * @author Medha
    *
    */
    public class PassEncryptDecrypt {

    public static boolean authenticate(String attemptedPassword, byte[] encryptedPassword, byte[] salt)

    throws NoSuchAlgorithmException, InvalidKeySpecException {

    // Encrypt the clear-text password using the same salt that was used to
    // encrypt the original password

    System.out.println(“We are in Password Encryption Decryption class”);
    System.out.println(“Attempted Password is “+attemptedPassword);
    System.out.println(“Encrypted password is “+encryptedPassword);
    System.out.println(“Salt pattern is “+salt);

    byte[] encPasswordGenerated = getEncryptedPassword(attemptedPassword, salt);

    System.out.println(“comparing the attempted and password generated by authentication”);
    System.out.println(“attempted “+attemptedPassword);
    System.out.println(“Generated password is “+encPasswordGenerated);

    // Authentication succeeds if encrypted password that the user entered

    // is equal to the stored hash
    boolean res=Arrays.equals(encryptedPassword, encPasswordGenerated);
    System.out.println(“The result is “+res);
    return res;

    }

    public static byte[] getEncryptedPassword(String password, byte[] salt)

    throws NoSuchAlgorithmException, InvalidKeySpecException {

    // PBKDF2 with SHA-1 as the hashing algorithm. Note that the NIST

    // specifically names SHA-1 as an acceptable hashing algorithm for PBKDF2

    String algorithm = “PBKDF2WithHmacSHA1”;

    // SHA-1 generates 160 bit hashes, so that’s what makes sense here

    int derivedKeyLength = 160;
    // Pick an iteration count that works for you. The NIST recommends at

    // least 1,000 iterations:
    // http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf

    // iOS 4.x reportedly uses 10,000:

    // http://blog.crackpassword.com/2010/09/smartphone-forensics-cracking-blackberry-backup-passwords/

    int iterations = 20000;

    KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, derivedKeyLength);

    SecretKeyFactory f = SecretKeyFactory.getInstance(algorithm);

    byte[] encPwdGenerated= f.generateSecret(spec).getEncoded();

    return encPwdGenerated;

    }

    public byte[] generateSalt() throws NoSuchAlgorithmException {

    // VERY important to use SecureRandom instead of just Random

    SecureRandom random = SecureRandom.getInstance(“SHA1PRNG”);

    // Generate a 8 byte (64 bit) salt as recommended by RSA PKCS5

    byte[] salt = new byte[8];

    random.nextBytes(salt);

    return salt;

    }

    }

    The application logs are :
    UserName is [email protected]
    PAssword is Meher123
    Your user name entered is [email protected]
    Your password entered is Meher123
    Query: select * from PasswdDetails where username=?
    encrypted Password is ?9?E?4U ?????|?
    Salt Pattern is ??fO?
    Now Changing the password and pattern to byte[] for authentication
    Enc Password is [[email protected]
    Pattern is [[email protected]
    We are in Password Encryption Decryption class
    Attempted Password is Meher123
    Encrypted password is [[email protected]
    Salt pattern is [[email protected]
    comparing the attempted and password generated by authentication
    attempted Meher123
    Generated password is [[email protected]
    The result is false
    authenticating ……………..
    Value of result boolean is false
    Sorry, you are not a registered user! Please sign up first
    UserName in servlet coming [email protected]

    • Please help it is very urgent.
      Thanks ,
      Medha

    • The code you pasted looks correct to me, so I suspect something else is going on outside of this class. Perhaps there’s an issue storing or retrieving the password from the database? What is the database type? What are the column types for the password and salt in the PasswdDetails table?

      Also, it can sometimes be easier to understand what’s going on if you can actually see a human-friendly decoded version of the byte arrays. I usually print them out in hexadecimal, like this:

      javax.xml.bind.DatatypeConverter.printHexBinary(bytes)

  11. I don’t get the option to Sign In and see my comments
    Thanks,
    Medha

  12. Thanks Jerry for your quick response..I will paste the full code after some time

  13. Here is my table description..Salt is stored as encpattern here
    desc PasswdDetails
    Name Null Type
    ———- ——– ————-
    USERNAME NOT NULL VARCHAR2(20)
    PASSWORD VARCHAR2(100)
    ENCPATTERN VARCHAR2(100)

    My LoginServlet:
    package com.plant.servlets;

    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.Date;

    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;

    import com.plant.DAO.FetchPassDAO;
    import com.plant.DAO.LoginDAO;
    import com.plant.model.User;

    /**
    * Servlet implementation class LoginServlet
    */
    public class LoginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
    * @see HttpServlet#HttpServlet()
    */
    public LoginServlet() {
    super();
    // TODO Auto-generated constructor stub
    }

    /**
    * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
    */
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub
    doPost(request,response);
    }

    /**
    * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
    */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub
    try
    {

    User user = new User();

    user.setUserName(request.getParameter(“UName”));

    user.setPass(request.getParameter(“pass”));

    System.out.println(“UserName is “+user.getUserName());
    System.out.println(“PAssword is “+user.getPass());

    user = LoginDAO.login(user);
    System.out.println(“UserName in servlet coming “+user.getUserName());

    if (user.isValid())
    {

    HttpSession session = request.getSession(true);
    session.setAttribute(“currentSessionUser”,request.getParameter(“UName”));

    response.sendRedirect(“welcome.jsp”); //logged-in page
    }

    else
    {
    response.sendRedirect(“InvalidLogin.jsp”); //error page
    }
    }

    catch (Throwable theException)
    {
    System.out.println(theException);
    }
    }

    }

    My Java class used for login:
    /**
    *
    */
    package com.plant.DAO;

    import java.nio.charset.Charset;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;

    import com.plant.model.User;

    /**
    * @author Medha
    *
    */
    public class LoginDAO {

    static Connection currentCon = null;
    static ResultSet rs ,rst= null;
    static PreparedStatement stmt,ps = null;

    public static User login(User bean) {

    String ePass=””;
    String ePattern=””;
    String username = bean.getUserName();

    String password = bean.getPass();

    String searchQuery =
    “select * from PasswdDetails where username=?”;

    // “System.out.println” prints in the console; Normally used to trace the process
    System.out.println(“Your user name entered is ” + username);
    System.out.println(“Your password entered is ” + password);
    System.out.println(“Query: “+searchQuery);

    try
    {
    //connect to DB
    currentCon = ConnectionManager.getConnection();
    stmt=currentCon.prepareStatement(searchQuery);
    stmt.setString(1, username);
    rs = stmt.executeQuery();

    if(rs.next())

    {

    ePass=rs.getString(2);
    ePattern=rs.getString(3);
    }

    System.out.println(“encrypted Password is “+ePass);
    System.out.println(“Salt Pattern is “+ePattern);

    byte[] EncPwd = ePass.getBytes(Charset.forName(“UTF-8”));
    byte[] saltPAttern= ePattern.getBytes(Charset.forName(“UTF-8”));
    System.out.println(“Now Changing the password and pattern to byte[] for authentication”);
    System.out.println(“Enc Password is “+EncPwd);
    System.out.println(“Pattern is “+saltPAttern);

    boolean res=PassEncryptDecrypt.authenticate(password,EncPwd,saltPAttern);
    res=true;
    System.out.println(“authenticating ……………..”);
    System.out.println(“Value of result boolean is “+res);
    if(!res)
    {
    System.out.println(“Sorry, you are not a registered user! Please sign up first”);
    bean.setValid(false);
    }

    //if user exists set the isValid variable to true
    else if (res)
    {
    ps=currentCon.prepareStatement(“Select * from Users where username=?”);
    ps.setString(1, username);
    rst = ps.executeQuery();

    String firstName=””;
    String lastName=””;
    while(rst.next())
    {
    firstName = rst.getString(4);
    lastName = rst.getString(5);
    }

    System.out.println(“User FirstNAme is “+firstName);
    System.out.println(“User LastName is “+lastName);

    System.out.println(“Welcome ” + firstName);
    bean.setFName(firstName);
    bean.setLname(lastName);
    bean.setValid(true);
    }

    }catch(Exception e)
    {
    System.out.println(“Exception “+e);
    e.printStackTrace();
    }

    finally
    {

    if (rs != null && rst!=null) {
    try {
    rs.close();
    rst.close();
    } catch (Exception e)
    {
    rs = null;
    rst=null;
    }
    }

    if (stmt != null && ps!=null) {
    try {
    stmt.close();
    ps.close();
    } catch (Exception e)
    {
    stmt = null;
    ps=null;
    }
    }

    if (currentCon != null) {
    try {
    currentCon.close();
    } catch (Exception e)
    {
    currentCon = null;
    }
    }

    }

    return bean;

    //preparing some objects for connection

    }

    }

    RegistrationServlet used for Registration :
    package com.plant.servlets;

    import java.io.IOException;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    import com.plant.DAO.PassEncryptDecrypt;
    import com.plant.DAO.RegisterDAO;
    import com.plant.DAO.SecurityResponseDAO;
    import com.plant.DAO.UserIdGenerator;
    import com.plant.model.Customer;
    import com.plant.model.PasswordBean;
    import com.plant.model.SecurityQuestion;
    import com.plant.model.SecurityResponse;
    import com.plant.model.User;

    /**
    * Servlet implementation class RegistrationServlet
    */
    public class RegistrationServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
    * @see HttpServlet#HttpServlet()
    */
    public RegistrationServlet() {
    super();
    // TODO Auto-generated constructor stub
    }

    /**
    * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
    */
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub
    doPost(request,response);

    }

    /**
    * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
    */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub
    /*int count=1011;
    String userId=String.valueOf(count);
    */

    try
    {
    System.out.println(“In Reg Servlet”);

    String firstName=request.getParameter(“fName”);
    String lastName=request.getParameter(“lName”);
    String email=request.getParameter(“email”);

    String pass=request.getParameter(“pwd”);

    String uName=request.getParameter(“uName”);
    String phone=request.getParameter(“ph”);
    String userType=””;
    if(request.getParameter(“Type”)!=null)
    {
    userType=request.getParameter(“Type”);
    }

    if(userType.equals(“opt1″))
    {
    userType=”User”;
    }
    else if(userType.equals(“opt2″))
    {
    userType=”customer”;
    }
    else
    {
    userType=”Admin”;
    }
    String ques1=””;
    if(request.getParameter(“ques”)!=null)
    {
    ques1=request.getParameter(“ques”);
    }

    System.out.println(“User Type choosen is “+userType);

    System.out.println(“Question choosen is “+ques1);

    User reguser = new User();
    reguser.setFName(firstName);
    reguser.setLname(lastName);
    reguser.setObselete(“no”);
    reguser.setIs_locked(“no”);
    reguser.setEmail(email);
    reguser.setUserType(userType);

    reguser.setPass(pass);
    //reguser.setPass(passEncrypted);

    reguser.setUserName(uName);

    UserIdGenerator uid=new UserIdGenerator();
    String userId=uid.generateUniqueId();
    reguser.setUserId(userId);

    reguser.setPhNo(phone);

    String res1=request.getParameter(“secret1”);
    System.out.println(“Response is “+res1);
    SecurityResponse secRes=new SecurityResponse();
    secRes.setSecId(ques1);
    secRes.setSecRes(res1);
    secRes.setUsername(uName);

    int secResCount= SecurityResponseDAO.enterSecurityQuestion(secRes);
    if(secResCount>0)
    {
    System.out.println(“entered into Security Response table”);
    }

    System.out.println(firstName);
    System.out.println(lastName);
    System.out.println(email);
    System.out.println(pass);
    System.out.println(uName);
    System.out.println(userId);
    System.out.println(phone);
    System.out.println(pass);

    System.out.println(“callings DAO method”);

    // reguser.setPhNo(request.getParameter());
    int recCountReg= RegisterDAO.registerUser(reguser);
    System.out.println(“called DAO method”);
    if(recCountReg>0)
    System.out.println(“Registered successfully”);

    String fName=request.getParameter(“fName”);
    String lName=request.getParameter(“lName”);

    String pwd=request.getParameter(“pwd”);

    String addr1=request.getParameter(“addr1”);
    String addr2=request.getParameter(“caddr”);
    String city=request.getParameter(“city”);
    String State=request.getParameter(“state”);
    String pin=request.getParameter(“pin”);
    String cntry=request.getParameter(“country”);
    String username=request.getParameter(“uName”);

    System.out.println(fName);
    System.out.println(lName);
    System.out.println(pwd);
    System.out.println(addr1);
    System.out.println(addr2);
    System.out.println(city);
    System.out.println(State);
    System.out.println(pin);
    System.out.println(cntry);
    System.out.println(username);
    System.out.println(userId);
    System.out.println(pass);
    // System.out.println(passEncrypted);

    Customer cust=new Customer();
    cust.setFname(fName);
    cust.setLName(lName);
    cust.setPwd(pass);
    //cust.setPwd(passEncrypted);
    cust.setAddr1(addr1);
    cust.setAddr2(addr2);
    cust.setCity(city);
    cust.setState(State);
    cust.setPin(pin);
    cust.setCntry(cntry);
    cust.setUsername(username);
    cust.setUserId(userId);
    // reguser = UserDAO.registerUser(reguser);

    int custCnt=RegisterDAO.registerCustomer(cust);
    if(custCnt>0)
    System.out.println(“record successfully to Customer”);

    PassEncryptDecrypt passE=new PassEncryptDecrypt();
    byte []salt=passE.generateSalt();
    byte[] passEncypted=passE.getEncryptedPassword(pass, salt);

    String password=new String(passEncypted,”UTF-8″);
    String encPattern=new String(salt,”UTF-8″);

    PasswordBean psb=new PasswordBean();
    psb.setUserName(uName);
    psb.setEncryptedPattern(encPattern);
    psb.setPassword(password);
    System.out.println(“Password is “+password);
    System.out.println(“UserNAme is “+uName);
    System.out.println(“Salt used is “+encPattern);

    System.out.println(“Calling Class to make Encrypted Password entry in table”);

    int recInserted=RegisterDAO.entryToPasswdTable(psb);
    System.out.println(“Record in Servlet “+recInserted);
    if(recInserted>0)
    System.out.println(“record successfully to Password Details”);

    response.sendRedirect(“home.jsp”); //error page

    }catch(Throwable theException)
    {
    theException.printStackTrace();
    }
    finally
    {

    }

    }

    }

    RegisterDAO class:
    /**
    *
    */
    package com.plant.DAO;

    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.Statement;

    import com.plant.model.Customer;
    import com.plant.model.PasswordBean;
    import com.plant.model.User;

    /**
    * @author Medha
    *
    */
    public class RegisterDAO {

    static Connection currentCon=null;
    static ResultSet rs = null;
    /*static Statement stmt = null,st=null;*/

    static PreparedStatement ps=null;
    static PreparedStatement pst=null;
    static PreparedStatement psp=null;

    /*static ResultSet rst=null;*/

    public static int registerUser(User user)

    {
    int more=0;

    try
    {

    currentCon = ConnectionManager.getConnection();
    //connect to DB

    pst=currentCon.prepareStatement(“insert into Users (email,fname,lname,password,obselete,is_locked,username,userid,phoneno ,type) values (?,? ,?, ?, ?, ?, ?,?,?,?)”);
    System.out.println(“in DAO”);
    String fNAME=user.getFName();
    String lNAME=user.getLname();
    String email=user.getEmail();
    String pwd=user.getPass();
    String obs=user.getObselete();
    String lock=user.getIs_locked();
    String UName=user.getUserName();
    String UserID=user.getUserId();
    String Phone=user.getPhNo();
    String userType=user.getUserType();

    System.out.println(fNAME);
    System.out.println(lNAME);
    System.out.println(email);
    System.out.println(“pwd is”+pwd);
    System.out.println(obs);
    System.out.println(lock);
    System.out.println(UName);
    System.out.println(Phone);
    System.out.println(userType);

    System.out.println(“got the values from bean in DAO”);
    pst.setString(1,email);
    System.out.println(email);

    pst.setString(2,fNAME );
    System.out.println(fNAME);

    pst.setString(3, lNAME);
    System.out.println(lNAME);

    pst.setString(4,pwd);
    System.out.println(pwd);

    pst.setString(5, obs);
    System.out.println(obs);

    pst.setString(6,lock);
    System.out.println(lock);

    pst.setString(7,UName);
    System.out.println(UName);

    pst.setString(8,UserID);
    System.out.println(UserID);

    pst.setString(9,Phone);
    System.out.println(Phone);
    pst.setString(10, userType);
    System.out.println(“set the fields to ps”);
    more = pst.executeUpdate();
    System.out.println(“Got the record count”);
    String msg=” “;
    if(more!=0){
    msg=”Record has been inserted”;
    System.out.println(msg);
    }

    }
    catch (Exception ex)
    {
    System.out.println(“Log In failed: An Exception has occurred! ” + ex);
    }

    //some exception handling
    finally
    {

    if (pst != null) {
    try {
    pst.close();
    } catch (Exception e) {}
    pst = null;
    }

    if (currentCon != null) {
    try {
    currentCon.close();
    } catch (Exception e) {
    }

    currentCon = null;
    }

    }

    System.out.println(more+”records inserted to users”);

    return more;

    }

    public static int registerCustomer(Customer cust)
    {
    int more =0;

    try
    {
    currentCon = ConnectionManager.getConnection();

    /*this. currentCon = ConnectionManager.getConnection();*/
    ps=currentCon.prepareStatement(“insert into Customers(fname,lname,addressline1,addressline2,city,state,pincode,country,username,userid) values (?, ?, ?, ?, ?,?,?,?,?,?)”);
    System.out.println(“in DAO”);
    String fNAME=cust.getFname();
    String lNAME=cust.getLName();

    // String pwd=cust.getPwd();
    String Addr1=cust.getAddr1();
    String Addr2=cust.getAddr2();
    String city=cust.getCity();
    String state=cust.getState();
    String pin=cust.getPin();
    String cntry=cust.getCntry();
    String username=cust.getUsername();
    String UserId=cust.getUserId();
    System.out.println(fNAME);
    System.out.println(lNAME);
    /*System.out.println(pwd);*/
    System.out.println(Addr1);
    System.out.println(Addr2);
    System.out.println(city);
    System.out.println(state);
    System.out.println(pin);
    System.out.println(cntry);
    System.out.println(username);
    System.out.println(UserId);

    System.out.println(“got the values from bean in DAO”);
    ps.setString(1,fNAME);
    System.out.println(fNAME);

    ps.setString(2,lNAME );
    System.out.println(lNAME);

    /* ps.setString(3, pwd);
    System.out.println(pwd);
    */
    ps.setString(3,Addr1);
    System.out.println(Addr1);

    ps.setString(4, Addr2);
    System.out.println(Addr2);

    ps.setString(5,city);
    System.out.println(city);

    ps.setString(6,state);
    System.out.println(state);

    ps.setString(7,pin);
    System.out.println(pin);

    ps.setString(8,cntry);
    System.out.println(cntry);

    ps.setString(9,username);
    System.out.println(username);

    ps.setString(10,UserId);
    System.out.println(UserId);

    System.out.println(“set the fields to ps”);
    more = ps.executeUpdate();
    System.out.println(“Got the record count”);
    String msg=” “;
    if(more!=0){
    msg=”Record has been inserted”;
    System.out.println(msg);
    }

    }
    catch (Exception ex)
    {
    System.out.println(“Log In failed: An Exception has occurred! ” + ex);
    }

    //some exception handling
    finally
    {

    if (ps != null) {
    try {
    ps.close();
    } catch (Exception e) {
    ps = null;
    }
    }

    if (currentCon != null) {
    try {
    currentCon.close();
    } catch (Exception e) {
    }

    currentCon = null;
    }

    }

    System.out.println(more+” records inserted to customer”);

    return more;

    }

    public static int entryToPasswdTable(PasswordBean bs)
    {
    int recCount=0;
    try
    {currentCon = ConnectionManager.getConnection();
    String uName=bs.getUserName();
    String pass=bs.getPassword();
    String ePattern=bs.getEncryptedPattern();

    psp=currentCon.prepareStatement(“insert into PasswdDetails(username,password,encpattern) values (?,?,?)”);
    System.out.println(“Inserting into the Password Details “);

    psp.setString(1, uName);
    psp.setString(2,pass);
    psp.setString(3,ePattern);
    System.out.println(“Password in DAO “+pass);
    System.out.println(“UserName is “+uName);
    System.out.println(“Encrypted Pattern is “+ePattern);
    System.out.println(psp.toString());
    System.out.println(“set the fields to psp”);

    recCount = psp.executeUpdate();
    System.out.println(recCount);
    System.out.println(“Got the record count”);
    String msg=” “;
    if(recCount!=0){
    msg=”Record has been inserted”;
    System.out.println(msg);
    }

    } catch (Exception ex)
    {
    System.out.println(“Log In failed: An Exception has occurred! ” + ex);
    ex.printStackTrace();
    }

    //some exception handling
    finally
    {

    if (psp != null) {
    try {
    psp.close();
    } catch (Exception e) {
    psp = null;
    }

    if (currentCon != null) {
    try {
    currentCon.close();
    } catch (Exception e) {
    }

    currentCon = null;
    }

    }

    }
    return recCount;
    }

    }

    During Registration I am converting the generated byte[] encrypted password and salt to String and storing to database.And for login I am taking String from Databased and converting both Encrypted Password and salt(encpattern) to the byte[]..I am facing problem during login as the generated password after calling authenticate() method is different..
    I am very much thankful to you Sir..
    Thanks in advance for your hep.
    Medha

    • Wow, that’s a lot of unformatted code; difficult to follow. A couple suggestions which may or may not help:

      1. You are doing “select * from PasswdDetails where username=?”, and then getting the columns by index. This can be dicey, as the column order can be unpredictable with “select *”. I suggest either selecting explicit columns (“select username, password, encpattern…”) or retrieving columns from the ResultSet by name (“rs.getString(“password”)”, etc)

      2. Chartsets can get tricky, particularly when you’re dealing with byte arrays. I suggest either storing it in the database as a binary type (instead of varchar) or just encoding it as a hexadecimal string. The nice thing about a hex string is that it’s easier to debug. You can tweak the authenticate() method to compare strings instead of byte arrays.

      Good luck!

  14. Wouldn’t it be better to retrieve the attempted password as a char[] like JPasswordField does, since generally speaking a String is less secure and accident prone? For non-Swing apps, would using the Scanner class to read input into a char[] be the best option?

    • “a String is less secure and accident prone”

      How so?

      “would using the Scanner class to read input into a char[] be the best option?”

      I’m not sure what that buys you; Scanner is usually used for parsing text. In the case of a web application, you’d be getting the password parameter using something like request.getParameter(“password”), which gives you a String. Even if you’re using some framework like Spring MVC, it’ll be giving you a String anyway. I don’t know what would be gained by running that through a Scanner, which doesn’t even return a char[].

    • Note that just using a char[] instead of a String doesn’t make anything more secure. You need to explicitly clear out the char[] after you’re done with it, or the password will be waiting for garbage collection just like a String. And if the password was _ever_ stored as a String (as is the case when using HttpServletRequest), you’ve gained nothing.

  15. Here is my code, you don’t even need to use toCharArray() for PBEKeySpec since it takes a char[].

    /**
    * Code used and modified from: http://www.javacodegeeks.com/2012/05/secure-password-storage-donts-dos-and.html
    */
    public class PasswordEncryptionService {

    public boolean authenticate(char[] attemptedPassword, byte[] encryptedPassword, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {

    //Encrypt clear-text password using the same salt that wa used to encrypt original password
    byte[] encryptedAttemptedPassword = getEncryptedPassword(attemptedPassword, salt);

    //Authentication succeeds if value returned is True
    return Arrays.equals(encryptedPassword, encryptedAttemptedPassword);

    }

    public byte[] getEncryptedPassword(char[] password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
    //Use PBKDF2 with SHA-1 for hashing algorithm
    String algorithm = “PBKDF2WithHmacSHA1”;

    //160 bit hash
    int derivedKeyLength = 160;

    //Iteration count, at least 1000
    int iterations = 20000;

    KeySpec spec = new PBEKeySpec(password, salt, iterations, derivedKeyLength);
    SecretKeyFactory f = SecretKeyFactory.getInstance(algorithm);

    return f.generateSecret(spec).getEncoded();
    }

    public byte[] generateSalt() throws NoSuchAlgorithmException {

    //Use secure random
    SecureRandom random = SecureRandom.getInstance(“SHA1PRNG”);

    //Generate a 8 byte (64 bit) salt as recommended by RSA PKCS5
    byte[] salt = new byte[8];
    random.nextBytes(salt);

    return salt;

    }

    }

  16. This is really a helpful article. However just wanted to understand if it is ok to have a SALT at application level rather than user level?

    • Short version: application-level salt is a moderate improvement over no salt, but user-level is much better. You absolutely should have a user-level salt.

      Long version: An application-level salt is better than no salt at all, as it prevents someone from running your database through a precomputed rainbow table. However, a per-user salt makes it **much** more difficult to crack your users’ passwords, because a per-user salt makes the work done brute-forcing UserA’s password completely worthless when brute-forcing UserB’s password. If they have the same salt, then the results of brute-forcing UserA’s password can be stored and compared against UserB’s hash. This is the basic idea behind a rainbow table attack; so while an application-level salt makes rainbow tables calculated before obtaining your database useless, it still lets someone build a rainbow table in the process of cracking your database. So do a user-level salt.

  17. Hi, Say I have an app with a login screen where user enters their credentials. According to your post, I should retrieve the saved salt and password hash from my servers then authenticate() them with the password the user entered? I’m I correct? This way, the user’s password never leaves his or her phone? Is it safe to make the password authenticating on the client_side(phone) rather than on my servers?

    • No, you definitely want to hash and authenticate on the server. If you authenticate on the client, how does the server know you aren’t just faking it? And even if you hash on the client and send the hash to the server, you effectively made the hash your password.

      The client should send the plain-text password to the server (over TLS/https, of course), the server hashes the password, and compares the result to the stored hash. If they match, authentication succeeds.

  18. Hi Jerry,
    You recommended user level salt, what would be the salt for each user. I guess it would be different for every user. How do we generate/create/determine a salt for a new user ?

    Also, once we have a salt and a hashed password, can we store them both in one table as one record ?

    • Yes, each user should have their own salt, and the PasswordEncryptionService above has a generateSalt() method to do so.

      Here were my thoughts on where to store the salt:

      > There is a lot of conflicting information out there on whether the salts should be stored someplace separate from the encrypted passwords. Since the key stretching in PBKDF2 already protects us from brute-force attacks, I feel it is unnecessary to try to hide the salt. Section 3.1 of NIST SP 800-132 also defines salt as a “non-secret binary value,” so that’s what I go with.

      So yes, I consider it safe to store the hashed password and salt in the same database record.

      • Thanks Jerry for clarifying this. I am guessing the iteration number would be a static value stored in the application. We are in the estimate phase of this work. We will replace an existing hasing system with the new way and we have been told that we must use PBKDF2. In order to do that we have to support both old and new way for a wile for backward compatibility. It’s going to be bit complex until we have the new design in place and all the existing users are migrated (forcefully or naturally) to use the new way. We will start work on it sometime soon once the estimate is approved. Expect few more design questions when I start the work. Thanks for your help.

  19. Great tutorial, thanks!

    A little improvement: do not use Arrays.equals as it allows time attacks. Of course, this is not a big issue, but why the risk…

    See “Why does the hashing code on this page compare the hashes in “length-constant” time?”
    https://crackstation.net/hashing-security.htm

  20. I faced one problem when moving byte[] to String and saving in db.

    This link has information how to convert byte[] to String and vice versa

    http://www.mkyong.com/java/how-do-convert-byte-array-to-string-in-java/

  21. Elizabeth McGurty

    Just want to offer many thanks for this code… This posting may be relevant to Java with Hibernate developers.

    In Netbeans 8.1, I am using libraries: Hibernate 4.3 and Java JDK 1.8 only. With database connectivity to MySQL…

    In my User.java Hibernate class, I provide the following settings

    private byte[] cryptedPassword;
    private byte[] salt;

    … and consistent with sets and gets….

    ====>

    public byte[] getCryptedPassword() {
    return this.cryptedPassword;
    }

    public void setCryptedPassword(byte[] cryptedPassword) {
    this.cryptedPassword = cryptedPassword;
    }
    public byte[] getSalt() {
    return this.salt;
    }

    public void setSalt(byte[] salt) {
    this.salt = salt;

    ===>

    In my Users.hbn.xml… Key to notice type is binary

    I am using MySQL, both columns crypted_password and salt are data types blob

    Tested, works like a charm…

  22. Elizabeth McGurty

    Following … Key to notice binary I do not see that I posted:

    <colum

  23. Seems that I am not using this posting process properly….

    I posted …

    Cutting my teeth here…
    I wrote a little test script that may be helpful to Java with Hibernate developers. Would very much appreciate feedback…

    Hibernate 4.3
    JDK 1.8

    Declares:

    String fname = null;

    byte[] get_user_salt = new byte[8];
    byte[] get_user_epassword = new byte[8];
    private Users[] usersArray = null;
    String tpassword = null;
    byte[] p = null;
    byte[] s = null;

    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    Transaction tx = session.beginTransaction();

    /// PasswordEncrytionService class unchanged from author
    //// https://www.javacodegeeks.com/2012/05/secure-password-storage-donts-dos-and.html
    PasswordEncryptionService pes = new PasswordEncryptionService();

    try {
    get_user_salt = pes.generateSalt();

    } catch (NoSuchAlgorithmException e) {
    }

    tpassword = “12345678”;
    try {
    get_user_epassword = pes.getEncryptedPassword(tpassword, get_user_salt);
    } catch (NoSuchAlgorithmException ex) {
    Logger.getLogger(BorrowersServlet.class.getName()).log(Level.SEVERE, null, ex);
    } catch (InvalidKeySpecException ex) {
    Logger.getLogger(BorrowersServlet.class.getName()).log(Level.SEVERE, null, ex);
    }

    // Constructor called: public Users(String id, String username, String email, Date createdAt, Date updatedAt, String remoteIp, byte[] cryptedPassword, byte[] salt, String rememberToken, Date rememberTokenExpiresAt, String activationCode, String resetCode, Date activatedAt, String userAlias, String userType, Integer approved, int isRapid, Integer roleId) {
    // For this purpose not using any validation, except that id can’t be duplicate
    Users uu = new Users(“1”, “mcgurty”, “email”, null, null, “more foo”, get_user_epassword, get_user_salt, “foo”, null, “foo”, “foo”, null, “foo”, “foo”, 1, 1, 1);
    session.save(uu);
    tx.commit();

    /// commit flushes session… Haven’t got the hang of anaing session/tranaction yet…. NormallyI would place following in separate function
    if (session.isOpen() == false) {
    session = HibernateUtil.getSessionFactory().getCurrentSession();
    }
    if (tx.isActive() == false) {
    tx = session.beginTransaction();
    }

    /// NOTE: createSQLQuery does not work!!!
    List results = session.createQuery(“from Users u where u.id = ‘1’”).list();
    session.getTransaction().commit();

    // Result size should be one
    int size_of_list = results.size();
    if (size_of_list > 1){ System.out.println(“Size of result is greater than one”); }

    Users users_Array = (Users) results.get(0);
    /// getCryptedPassword and Salt are stored on database as blobs
    /// they are defined as binary for Hibernate
    p = users_Array.getCryptedPassword();
    s = users_Array.getSalt();
    System.out.println(“Success??”);

    //}

    try {
    Boolean getp = pes.authenticate(tpassword, p, s);
    System.out.println(“Are you am authenitcated user? ” + getp);

    } catch (NoSuchAlgorithmException e) {
    } catch (InvalidKeySpecException ex) {
    Logger.getLogger(BorrowersServlet.class.getName()).log(Level.SEVERE, null, ex);
    }
    //
    try {
    session.close();
    } catch (Exception e) {
    System.out.println(“Session closed”);
    }

    }

  24. Dear Mr. Orr,

    Just getting used to your posting process. Would you kindly delete messages that do not contain meaningful content…. Very much thanks.

    Liz

Leave a Reply

Your email address will not be published. Required fields are marked *

*

Want to take your Java skills to the next level?

Grab our programming books for FREE!

Here are some of the eBooks you will get:

  • Advanced Java Guide
  • Java Design Patterns
  • JMeter Tutorial
  • Java 8 Features Tutorial
  • JUnit Tutorial
  • JSF Programming Cookbook
  • Java Concurrency Essentials