Lou*_*ong 41 java security encryption hash salt
我一直在寻找,最接近的答案是:如何生成一个随机的字母数字字符串?
我想根据这个CrackStation教程来遵循这个工作流程:
存储密码
使用CSPRNG生成长的随机盐.
将salt添加到密码中,并使用标准加密哈希函数(如SHA256)对其进行哈希处理.
将salt和hash都保存在用户的数据库记录中.
验证密码
从数据库中检索用户的salt和hash.
将salt添加到给定密码并使用相同的哈希函数对其进行哈希处理.
将给定密码的哈希值与数据库中的哈希值进行比较.如果匹配,则密码正确.否则,密码不正确.
我不知道如何生成SALT.我想出了如何使用MessageDigest生成哈希.我尝试使用SecureRandom,但nextByte方法产生乱码.
编辑:我不知道选择哪个答案,对我来说太复杂了,我决定使用jBCrypt; jBCript很容易使用,在幕后做所有复杂的事情.所以我会让社区投票给出最佳答案.
ass*_*ias 51
受到这篇文章和帖子的启发,我使用此代码生成并验证散列的盐渍密码.它只使用JDK提供的类,没有外部依赖.
过程是:
getNextSalt
hash
方法生成盐渍和散列密码.该方法返回一个byte[]
可以使用salt保存在数据库中的方法isExpectedPassword
方法检查详细信息是否匹配/**
* A utility class to hash passwords and check passwords vs hashed values. It uses a combination of hashing and unique
* salt. The algorithm used is PBKDF2WithHmacSHA1 which, although not the best for hashing password (vs. bcrypt) is
* still considered robust and <a href="https://security.stackexchange.com/a/6415/12614"> recommended by NIST </a>.
* The hashed value has 256 bits.
*/
public class Passwords {
private static final Random RANDOM = new SecureRandom();
private static final int ITERATIONS = 10000;
private static final int KEY_LENGTH = 256;
/**
* static utility class
*/
private Passwords() { }
/**
* Returns a random salt to be used to hash a password.
*
* @return a 16 bytes random salt
*/
public static byte[] getNextSalt() {
byte[] salt = new byte[16];
RANDOM.nextBytes(salt);
return salt;
}
/**
* Returns a salted and hashed password using the provided hash.<br>
* Note - side effect: the password is destroyed (the char[] is filled with zeros)
*
* @param password the password to be hashed
* @param salt a 16 bytes salt, ideally obtained with the getNextSalt method
*
* @return the hashed password with a pinch of 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();
}
}
/**
* Returns true if the given password and salt match the hashed value, false otherwise.<br>
* Note - side effect: the password is destroyed (the char[] is filled with zeros)
*
* @param password the password to check
* @param salt the salt used to hash the password
* @param expectedHash the expected hashed value of the password
*
* @return true if the given password and salt match the hashed value, false otherwise
*/
public static boolean isExpectedPassword(char[] password, byte[] salt, byte[] expectedHash) {
byte[] pwdHash = hash(password, salt);
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;
}
/**
* Generates a random password of a given length, using letters and digits.
*
* @param length the length of the password
*
* @return a random password
*/
public static String generateRandomPassword(int length) {
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i++) {
int c = RANDOM.nextInt(62);
if (c <= 9) {
sb.append(String.valueOf(c));
} else if (c < 36) {
sb.append((char) ('a' + c - 10));
} else {
sb.append((char) ('A' + c - 36));
}
}
return sb.toString();
}
}
Run Code Online (Sandbox Code Playgroud)
Rau*_*wal 11
关于你想要生成盐的方式你是对的,即它只是一个随机数.对于这种特殊情况,它可以保护您的系统免受可能的字典攻击.现在,对于第二个问题,您可以做的不是使用UTF-8编码,而是可能需要使用Base64.这里是用于生成散列的示例.我正在使用Apache Common Codecs来执行base64编码,您可以选择自己的编码
public byte[] generateSalt() {
SecureRandom random = new SecureRandom();
byte bytes[] = new byte[20];
random.nextBytes(bytes);
return bytes;
}
public String bytetoString(byte[] input) {
return org.apache.commons.codec.binary.Base64.encodeBase64String(input);
}
public byte[] getHashWithSalt(String input, HashingTechqniue technique, byte[] salt) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance(technique.value);
digest.reset();
digest.update(salt);
byte[] hashedBytes = digest.digest(stringToByte(input));
return hashedBytes;
}
public byte[] stringToByte(String input) {
if (Base64.isBase64(input)) {
return Base64.decodeBase64(input);
} else {
return Base64.encodeBase64(input.getBytes());
}
}
Run Code Online (Sandbox Code Playgroud)
以下是直接来自OWASP的密码哈希标准实践的一些额外参考
归档时间: |
|
查看次数: |
83151 次 |
最近记录: |