如何在数据库中保留指定长度的盐
How to persist a salt with specified lenght in the database
我已经有一个包含 table 命名用户的数据库,此 table 包含 table 盐、密码等...
- salt 列有长度为 43 的数据
- 密码栏有88位长度的数据
我的数据库是由 symfony(ORM+FOSUserBundle)
他使用 sha512 创建的。
我正在尝试获取盐和密码,并将它们从桌面 java 应用程序存储到数据库中,所以我尝试了这个 Class:
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 的盐,但是,当我添加一个具有该盐并生成哈希的用户时,我无法从我的用户登录web 应用程序(已经说过 FOSUserBundle 控制身份验证和 encode/decode 算法)
如果我没看错,那么你的摘要编码器实现有误。
参考点:
MessageDigestPasswordEncoder.php
当您请求手动生成摘要时,基本上有两个步骤:
- 哈希连接:
password
+ {
+ salt
+ }
- 对于每个额外的迭代:散列
previous digest
+ salt
的连接(请注意,此步骤不添加 {
或 }
个字符)
所以,我在您的实施中发现了两个问题:
- 在我看来,您没有在迭代 #0
中包含那些 {
和 }
- 您没有在以后的任何迭代中包含盐
希望对您有所帮助...
我已经有一个包含 table 命名用户的数据库,此 table 包含 table 盐、密码等...
- salt 列有长度为 43 的数据
- 密码栏有88位长度的数据
我的数据库是由 symfony(ORM+FOSUserBundle)
他使用 sha512 创建的。
我正在尝试获取盐和密码,并将它们从桌面 java 应用程序存储到数据库中,所以我尝试了这个 Class:
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 的盐,但是,当我添加一个具有该盐并生成哈希的用户时,我无法从我的用户登录web 应用程序(已经说过 FOSUserBundle 控制身份验证和 encode/decode 算法)
如果我没看错,那么你的摘要编码器实现有误。
参考点:
MessageDigestPasswordEncoder.php
当您请求手动生成摘要时,基本上有两个步骤:
- 哈希连接:
password
+{
+salt
+}
- 对于每个额外的迭代:散列
previous digest
+salt
的连接(请注意,此步骤不添加{
或}
个字符)
所以,我在您的实施中发现了两个问题:
- 在我看来,您没有在迭代 #0 中包含那些
- 您没有在以后的任何迭代中包含盐
{
和 }
希望对您有所帮助...