我试图按照here.中的代码获取哈希密码,目前我仅使用salt
方法的代码hash
方法和isExpectedPassword
方法。
我从一个文本字段获得密码:
char[] passCharArray = txtPassword.toString().toCharArray();
然后,我调用该类以获得盐值(我将其称为Encryptor
而不是原始帖子中的Passwords
):
byte[] salt = Encryptor.getNextSalt();
然后我得到了哈希密码:
byte[] hashedPass = Encryptor.hash(passCharArray, salt);
使用以下代码,我打印结果以查看发生了什么并对结果进行注释:
String saltString = Arrays.toString(salt);
System.out.println("SALT: " + saltString);
//SALT: [18, 117, -98, 41, 92, 124, 118, 17, 107, 14, 0, -81, 110, 70, 10, 42]
String hashedPassString = Arrays.toString(hashedPass);
System.out.println("HASHED PASS: " + hashedPassString);
//HASHED PASS: [44, -127, -43, 84, 40, -16, -46, -71, 109, -44, -41, 47, -61, -119, 21, 99, -23, 101, -13, 116, -12, 118, -66, 44, 104, 5, 4, 18, -55, 47, 59, 116]
System.out.println("Passwords match: " + Encryptor.isExpectedPassword(passCharArray, salt, hashedPass));
//Passwords match: false
下面的两个是我放入System.out.print
方法中的isExpectedPassword
,以查看一个被调用时具有什么值。
//Encryptor pwdHash: [-103, -87, 53, -75, 59, 11, 77, 116, 123, 59, 68, -35, 16, -68, 42, 34, -32, 75, 22, -94, -37, -26, 16, 20, 7, -46, -6, -20, -88, 104, -121, 77]
//Encryptor expectedHash: [44, -127, -43, 84, 40, -16, -46, -71, 109, -44, -41, 47, -61, -119, 21, 99, -23, 101, -13, 116, -12, 118, -66, 44, 104, 5, 4, 18, -55, 47, 59, 116]
因此,基本上hashedPass
(和expectedHash
)应该与pwdHash
相同,但事实并非如此。我不明白我在做什么错。我在代码中缺少什么吗?在我不知情的情况下会有什么变化吗?
这是我的完整代码,以防万一,以防万一:
public class Encryptor {
private static final Random RANDOM = new SecureRandom();
private static final int ITERATIONS = 10000;
private static final int KEY_LENGTH = 256;
private Encryptor(){}
public static byte[] getNextSalt(){
byte[] salt = new byte[16];
RANDOM.nextBytes(salt);
return salt;
}
public static byte[] hash(char[] password, byte[] salt) {
PBEKeySpec spec = new PBEKeySpec(password, salt, ITERATIONS, KEY_LENGTH);
Arrays.fill(password, Character.MIN_VALUE);
try {
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
return skf.generateSecret(spec).getEncoded();
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new AssertionError("Error while hashing a password: " + e.getMessage(), e);
} finally {
spec.clearPassword();
}
}
public static boolean isExpectedPassword(char[] password, byte[] salt, byte[] expectedHash) {
byte[] pwdHash = hash(password, salt);
String s = Arrays.toString(pwdHash);
System.out.println("Encryptor pwdHash: " + s);
String s2 = Arrays.toString(expectedHash);
System.out.println("Encryptor expectedHash: " + s2);
Arrays.fill(password, Character.MIN_VALUE);
if (pwdHash.length != expectedHash.length) return false;
for (int i = 0; i < pwdHash.length; i++) {
if (pwdHash[i] != expectedHash[i]) return false;
}
return true;
}
}
public class Controller implements Initializable {
@FXML
private Button btnLogin;
//Some private variables
@FXML
private AnchorPane ancPane;
@FXML
private ImageView imgLogo;
@FXML
private Hyperlink hplRegister;
@FXML
private TextField txtUsername;
@FXML
private TextField txtPassword;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
//Some styling
hplRegister.setOnAction(event -> {
//Registering event
});
btnLogin.setOnAction(event -> {
try {
//Loading fxml data
// I've put the code here just for testing purposes
// and will not be the final placement.
char[] passCharArray = txtPassword.toString().toCharArray();
byte[] salt = Encryptor.getNextSalt();
byte[] hashedPass = Encryptor.hash(passCharArray, salt);
String saltString = Arrays.toString(salt);
System.out.println("SALT: " + saltString);
String hashedPassString = Arrays.toString(hashedPass);
System.out.println("HASHED PASS: " + hashedPassString);
System.out.println("Passwords match: " + Encryptor.isExpectedPassword(passCharArray, salt, hashedPass));
}catch (Exception e){
e.printStackTrace();
}
});
}
//Some getter methods.
}
答案 0 :(得分:1)
问题是您要清除密码。当您对密码进行哈希处理时,会清除char数组并用空格填充,这会清除passCharArray
。当您第二次通过密码时,它基本上是在检查密码的哈希值与空白数组的哈希值。那些绝对不匹配。
在实际情况下,您将从数据库或其他来源获得盐和哈希密码。传入的版本在传递给isExpectedPassword