简体   繁体   中英

Regenerating SHA-1 hash not matching stored database hash

I'm trying to implement SHA1 password hashing with key-stretching combined with a UUID as a salt. The salt is stored as a column in my usersTable inside the database backend, thus each user will be generated their own unique salt.

My problem is that when I attempt to regenerate the password hashes, the hashes are not matching up and I'm not seeing where the issue lies.

registerUser fetches a user object from createUser, and then persists it into the database. I then use validatePassword to regenerate the hash. See below for full code snippets. This is my first attempt at securing passwords, clearly I have goofed somewhere but I can't spot the bug.

public void registerUser() {
    try {

        Usertable newUser = createUser();

        // user constructed at this point, persist it to the database.
        utx.begin();
        em.persist(newUser);
        utx.commit();

        // Register user with Meter
        Meter myMeter = (Meter) em.createNamedQuery("Meter.findByMeterid").setParameter("meterid", this.meterId).getSingleResult();
        myMeter.setUsername(newUser);

        utx.begin();
        em.merge(myMeter);
        utx.commit();

    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(RegisterBean.class.getName()).log(Level.SEVERE, null, ex);
    } catch (NotSupportedException ex) {
        Logger.getLogger(RegisterBean.class.getName()).log(Level.SEVERE, null, ex);
    } catch (SystemException ex) {
        Logger.getLogger(RegisterBean.class.getName()).log(Level.SEVERE, null, ex);
    } catch (RollbackException ex) {
        Logger.getLogger(RegisterBean.class.getName()).log(Level.SEVERE, null, ex);
    } catch (HeuristicMixedException ex) {
        Logger.getLogger(RegisterBean.class.getName()).log(Level.SEVERE, null, ex);
    } catch (HeuristicRollbackException ex) {
        Logger.getLogger(RegisterBean.class.getName()).log(Level.SEVERE, null, ex);
    } catch (SecurityException ex) {
        Logger.getLogger(RegisterBean.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IllegalStateException ex) {
        Logger.getLogger(RegisterBean.class.getName()).log(Level.SEVERE, null, ex);
    }

}

private Usertable createUser() throws NoSuchAlgorithmException {
    Security securityLevel = (Security) em.createNamedQuery("Security.findBySecurityid").setParameter("securityid", SECURITY_LEVEL_USER).getSingleResult();
    Usertable newUser = new Usertable();

    // generate UUID to be used as a salt.
    UUID salt = UUID.randomUUID();

    // generate hash
    MessageDigest msgDigest = MessageDigest.getInstance("SHA-1");
    String inputText = new String(salt.toString() + this.password);
    for (int i = 0; i < ITERATIONS; i++) {
        msgDigest.update(inputText.getBytes());
        byte rawByte[] = msgDigest.digest();
        inputText = (new BASE64Encoder()).encode(rawByte);
    }

    String hashValue = inputText;

    newUser.setUsername(this.userName);
    newUser.setSecurityid(securityLevel);
    newUser.setSalt(salt.toString());
    newUser.setPassword(hashValue);

    return newUser;
}

public void validatePassword(FacesContext context, UIComponent ui, Object passwordField) {
    try {
        UIInput userNameInput = (UIInput) context.getViewRoot().findComponent("regform:userName");
        String userName = (String) userNameInput.getValue();

        Usertable myUser = (Usertable) em.createNamedQuery("Usertable.findByUsername").setParameter("username", userName).getSingleResult();

        // generate hash
        MessageDigest msgDigest = MessageDigest.getInstance("SHA-1");
        String inputText = new String(myUser.getSalt() + this.password);
        for (int i = 0; i < ITERATIONS; i++) {
            msgDigest.update(inputText.getBytes());
            byte rawByte[] = msgDigest.digest();
            inputText = (new BASE64Encoder()).encode(rawByte);
        }

        if (!inputText.equals(myUser.getPassword())) {
            String message = "Username or password incorrect";
            throw new ValidatorException(new FacesMessage(message));
        } else {
            // password is valid, store user into session and mark logged in.
            this.myUser = myUser;
        }

    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(LoginBean.class.getName()).log(Level.SEVERE, null, ex);
    } catch (NoResultException ex) {
        String message = "Username or password incorrect";
        throw new ValidatorException(new FacesMessage(message));
    }

}

Are you sure that this.password is set correctly before validatePassword() is called? Have you inspected the initial value of inputText in both createUser() and validatePassword() to ensure that they match?

This method of hashing passwords is not secure. Because of collisions in the hash function output, the more iterations you perform, the less entropy the resulting hash will contain. To preserve the same level of unpredictability found in the original password, you need to add the password to each round of hashing.

The best way to do this is to use an existing password hashing library, like scrypt or bcrypt, or at least a key derivation function like PBKDF2, which is built into most Java runtimes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM