2016-11-24 40 views
1

因此,我正在编写一个java程序,它从用户处获取用户名和密码,从数据库(mysql)中检索散列的密码,并对用户进行身份验证。哈希密码和salt在我的数据库中保存为TEXT数据类型。我的问题是,当我比较存储的密码和用户输入的密码(当然,在运行散列算法之后),结果总是为false。我复制了2个哈希值,并将它们在另一个程序中进行比较,结果相同。这里是我的代码(请忽略了一个事实,我的代码很容易受到SQL注入攻击,我以后打算固定:比较哈希结果总是返回false,即使它们完全相同

public class Security { 

public static void main(String[] args) throws UserNotExistingException { 
    Security s=new Security(); 
    s.signUp("John.Smith", "John Smith", "[email protected]", "test"); 
    System.out.println(s.Authenticate("John.Smith" , "test")); 
} 

public boolean Authenticate(String username, String password) throws UserNotExistingException { 
    String dbpass = null; 
    byte[] salt = null; 
    try { 
     // Load driver for connecting to db 
     Class.forName("com.mysql.jdbc.Driver"); 
     // Establishing connection to db 
     Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/vote sys", "root", ""); 
     // Creating statement object to be executed on dbms 
     Statement stmt = con.createStatement(); 
     ResultSet rs = stmt.executeQuery("select pass, salt from user_acc where username = '" + username + "';"); 

     if (rs.next()) { 
      dbpass = rs.getString(2); 
      String temp = rs.getString(2); 
      System.out.println(temp); 
      salt = temp.getBytes(); 
     } 
     for (byte i : salt) 
      System.out.print(i); 
     System.out.println(); 
     // Terminating connection to db 
     con.close(); 
    } catch (Exception e) { 
     System.out.println(e); 
    } 
    if (dbpass == null || salt == null) 
     throw new UserNotExistingException("User " + username + " doesn't exist"); 

    try { //this is where im facing the problem, the condition is always returning true when its not 
     String hashed=generateHash(password, salt); 
     System.out.println(hashed); 
     if (hashed.compareTo(dbpass)!=0) 
      return false; 


    } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { 
     e.printStackTrace(); 
    } 

    return true; 
} 

private static String generateHash(String password, byte[] salt) 
     throws NoSuchAlgorithmException, InvalidKeySpecException { 
    int iterations = 1000; 
    char[] chars = password.toCharArray(); 

    PBEKeySpec spec = new PBEKeySpec(chars, salt, iterations, 64 * 8); 
    SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
    byte[] hash = skf.generateSecret(spec).getEncoded(); 
    return iterations + ":" + toHex(salt) + ":" + toHex(hash); 
} 

private static byte[] getSalt() throws NoSuchAlgorithmException { 
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); 
    byte[] salt = new byte[16]; 
    sr.nextBytes(salt); 
    return salt; 
} 

private static String toHex(byte[] array) throws NoSuchAlgorithmException { 
    BigInteger bi = new BigInteger(1, array); 
    String hex = bi.toString(16); 
    int paddingLength = (array.length * 2) - hex.length(); 
    if (paddingLength > 0) { 
     return String.format("%0" + paddingLength + "d", 0) + hex; 
    } else { 
     return hex; 
    } 
} 

public void signUp(String username, String name, String email, String password) { 
    String dbuser = "", dbemail = ""; 
    try { 
     // Load driver for connecting to db 
     Class.forName("com.mysql.jdbc.Driver"); 
     // Establishing connection to db 
     Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/vote sys", "root", ""); 
     // Creating statement object to be executed on dbms 
     Statement stmt = con.createStatement(); 
     ResultSet rs = stmt.executeQuery("select username, email from user_acc where username = '" + username 
       + "' or email = '" + email + "';"); 

     if (rs.next()) { 
      dbuser = rs.getString(2); 
      dbemail = rs.getString(2); 
     } 
     if (!dbuser.equals("") || !dbemail.equals("")) 
      throw new UserNotExistingException("Username or email already exists"); 

     byte[] salt = getSalt(); 
     for (int i = 0; i < salt.length; i++) { 
      System.out.print(salt[i]); 
     } 
     System.out.println(); 
     String temp= new String(salt); 
     System.out.println(temp); 
     String hashedPass = generateHash(password, salt); 
     System.out.println(hashedPass); 
     stmt.executeUpdate("INSERT INTO `user_acc`(`username`, `name`, `email`, `pass`, `salt`) VALUES ('" 
       + username + "','" + name + "','" + email + "','" + hashedPass + "','" + temp + "');"); 

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

}

回答

0

您尝试将盐存储为一个字符串(其中saltbyte[]):

String temp= new String(salt); 

后来到提取它:

salt = temp.getBytes(); 

您不能将字节数组转换为字符串并返回,并希望检索相同的字节。 docs for (String(byte[]))说:

未指定给定字节在默认字符集中无效时此构造函数的行为。

由于您的密码格式已经包含salt作为十六进制字符串,因此您无需单独存储盐。相反,从该字符串中提取盐和密码散列的十六进制字符串,将它们转换为byte[],并在比较中使用它们。

相关问题