2016-11-24 58 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[],並在比較中使用它們。