重新生成不匹配存储数据库哈希的SHA-1哈希

时间:2013-11-26 23:55:44

标签: java security jpa hash message-digest

我正在尝试使用键拉伸结合UUID作为salt来实现SHA1密码哈希。 salt在我的usersTable中作为列存储在数据库后端内,因此每个用户都将生成自己独特的盐。

我的问题是,当我尝试重新生成密码哈希时,哈希值不匹配,我没有看到问题所在。

registerUser从createUser获取用户对象,然后将其持久保存到数据库中。然后我使用validatePassword重新生成哈希。请参阅下面的完整代码段。这是我第一次尝试保护密码,显然我已经在某个地方搞砸了,但我无法发现这个错误。

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));
    }

}

1 个答案:

答案 0 :(得分:1)

在调用this.password之前,您确定validatePassword()设置正确吗?您是否检查了inputTextcreateUser()validatePassword()的初始值,以确保它们匹配?

这种散列密码的方法并不安全。由于散列函数输出中的冲突,您执行的迭代越多,生成的散列将包含的熵越少。为了保持原始密码中的不可预测性,您需要为每轮散列添加密码。

执行此操作的最佳方法是使用现有的密码散列库(如scrypt或bcrypt),或者至少使用大多数Java运行时内置的密钥派生函数(如PBKDF2)。