如何在数据库中持久保存具有指定长度的salt

时间:2018-03-25 13:00:10

标签: java symfony hash salt sha512

我已经有一个包含名为User的表的数据库,该表包含表盐,密码等...

  1. 盐柱的数据长度为43
  2. 密码列包含88长度的数据
  3. 我的数据库是由symfony(ORM+FOSUserBundle)使用sha512创建的。

    我正在尝试获取salt和密码,并将它们从桌面java应用程序存储到数据库中,所以我尝试了这个类:

    import com.google.common.io.BaseEncoding;
    import org.slf4j.Logger;
    import java.io.UnsupportedEncodingException;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import com.google.common.primitives.Bytes;
    import org.slf4j.LoggerFactory;
    
    public class SHA512 {
        private static final Logger log = LoggerFactory.getLogger(SHA512.class);
        private static final String ALGORITHM = "SHA-512";
        private static final int ITERATIONS = 5000;
        private static final int SALT_SIZE = 43;
    
    
        /**
         * Private constructor.
         */
        private SHA512() {
        }
    
        public static void main(String[] args) {
            String password = "0000";
    
            try {
    
                byte[] salt = generateSalt();
                log.info("Password {}. hash algorithm {}, iterations {}, salt {}", password, ALGORITHM, ITERATIONS,
                        BaseEncoding.base64().encode(salt));
                byte[] hash = calculateHash(password, salt);
                boolean correct = verifyPassword(hash, password, salt);
    
                log.info("Entered password is correct: {}", correct);
            } catch (NoSuchAlgorithmException | UnsupportedEncodingException ex) {
                log.error(ex.getMessage(), ex);
            }
        }
    
    
        private static byte[] generateSalt() {
            SecureRandom random = new SecureRandom();
            byte[] salt = new byte[SALT_SIZE];
            random.nextBytes(salt);
    
            return salt;
        }
    
        private static byte[] calculateHash(String password, byte[] salt) throws NoSuchAlgorithmException,
                UnsupportedEncodingException {
            MessageDigest md = MessageDigest.getInstance(ALGORITHM);
            md.reset();
            md.update(Bytes.concat(password.getBytes("UTF-8"), salt));
            byte[] hash = md.digest();
    
            for (int i = 0; i < ITERATIONS; i++) {
                md.reset();
                hash = md.digest(hash);
            }
            return hash;
        }
    
        private static boolean verifyPassword(byte[] originalHash, String password, byte[] salt) throws
                NoSuchAlgorithmException, UnsupportedEncodingException {
            byte[] comparisonHash = calculateHash(password, salt);
    
            log.info("hash 1: {}", BaseEncoding.base64().encode(originalHash));
            log.info("hash 2: {}", BaseEncoding.base64().encode(comparisonHash));
    
            return comparePasswords(originalHash, comparisonHash);
        }
    
        /**
         * Compares the two byte arrays in length-constant time using XOR.
         *
         * @param originalHash   The original password hash
         * @param comparisonHash The comparison password hash
         * @return True if both match, false otherwise
         */
        private static boolean comparePasswords(byte[] originalHash, byte[] comparisonHash) {
            int diff = originalHash.length ^ comparisonHash.length;
            for (int i = 0; i < originalHash.length && i < comparisonHash.length; i++) {
                diff |= originalHash[i] ^ comparisonHash[i];
            }
    
            return diff == 0;
        }
    }
    

    我需要一个长度为43的盐,但BaseEncoding.base64().encode(salt)输出盐,长度等于60。 我将SALT_SIZE修改为30并且BaseEncoding.base64().encode(salt)输出长度等于40的salt但是,当我添加一个用户使用该盐并生成哈希时,我无法从我的Web应用程序登录此用户(已经说FOSUserBundle控制认证和编码/解码算法)

1 个答案:

答案 0 :(得分:1)

如果我正确阅读,您的摘要编码器实施中会出错。

参考点:

<强> MessageDigestPasswordEncoder.php

<强> BasePasswordEncoder.php

当您请求手动生成摘要时,基本上有两个步骤:

  1. 哈希结束:password + { + salt + }
  2. 对于每次额外的迭代:对previous digest + salt的concat进行哈希处理(请注意,此步骤不会添加{}字符)
  3. 所以,我在你的实现中看到了两个问题:

    1. 我认为你没有在迭代#0中包含{}
    2. 您未在以后的任何迭代中包含salt
    3. 希望这有点帮助...