我这里有一个基于Symfony2的旧应用程序,现在我正在使用Java的Dropwizard开发替代品。我已经将所有用户记录从旧数据库迁移到新数据模型中。我还添加了新的密码字段,并导入了旧密码和盐字段。
现在我想执行众所周知的过程。让用户登录,尝试使用新密码字段。如果失败,则尝试使用迁移的密码,如果它们有效,则使用新算法对明文密码进行编码,并将新哈希存储在新密码字段中。这样用户就可以将其密码哈希从旧过程转移到新过程。
听起来很简单,通常都能正常工作,但是Symfony和PHP让我发疯。
我卡住的地方是如何使用Java创建与Symfony相同的哈希值。 旧应用程序使用MessageDigestPasswordEncoder,采用默认值"sha512"、base64编码和5000次迭代。
重要的方法包括: MessageDigestPasswordEncoder:
现在我想执行众所周知的过程。让用户登录,尝试使用新密码字段。如果失败,则尝试使用迁移的密码,如果它们有效,则使用新算法对明文密码进行编码,并将新哈希存储在新密码字段中。这样用户就可以将其密码哈希从旧过程转移到新过程。
听起来很简单,通常都能正常工作,但是Symfony和PHP让我发疯。
我卡住的地方是如何使用Java创建与Symfony相同的哈希值。 旧应用程序使用MessageDigestPasswordEncoder,采用默认值"sha512"、base64编码和5000次迭代。
重要的方法包括: MessageDigestPasswordEncoder:
public function encodePassword($raw, $salt) {
if ($this->isPasswordTooLong($raw)) {
throw new BadCredentialsException('Invalid password.');
}
if (!in_array($this->algorithm, hash_algos(), true)) {
throw new \LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm));
}
$salted = $this->mergePasswordAndSalt($raw, $salt);
$digest = hash($this->algorithm, $salted, true);
// "stretch" hash
for ($i = 1; $i < $this->iterations; ++$i) {
$digest = hash($this->algorithm, $digest.$salted, true);
}
return $this->encodeHashAsBase64 ? base64_encode($digest) : bin2hex($digest);
}
还有BasePasswordEncoder:
protected function mergePasswordAndSalt($password, $salt) {
if (empty($salt)) {
return $password;
}
if (false !== strrpos($salt, '{') || false !== strrpos($salt, '}')) {
throw new \InvalidArgumentException('Cannot use { or } in salt.');
}
return $password.'{'.$salt.'}';
}
这看起来很简单,但我被卡住了。 按照以下步骤进行操作:
- 将盐和明文密码合并为 "password{salt}"
- 使用 SHA-512 对此字符串进行散列,并将结果作为二进制字符串存储在 digest 变量中
- 迭代 5k 次,并使用 digest 和合并的明文密码重新散列为 digest
- 将 digest 编码为 base64
以下是我在 Java 中的尝试:
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public void legacyEncryption(String salt, String clearPassword) throws UnsupportedEncodingException, NoSuchAlgorithmException {
// Get digester instance for algorithm "SHA-512" using BounceCastle
MessageDigest digester = MessageDigest.getInstance("SHA-512", new BouncyCastleProvider());
// Create salted password string
String mergedPasswordAndSalt = clearPassword + "{" + salt + "}";
// First time hash the input string by using UTF-8 encoded bytes.
byte[] hash = digester.digest(mergedPasswordAndSalt.getBytes("UTF-8"));
// Loop 5k times
for (int i = 0; i < 5000; i++) {
// Concatenate the hash bytes with the clearPassword bytes and rehash
hash = digester.digest(ArrayUtils.addAll(hash, mergedPasswordAndSalt.getBytes("UTF-8")));
}
// Log the resulting hash as base64 String
logger.info("Legace password digest: salt=" + salt + " hash=" + Base64.getEncoder().encodeToString(hash));
}
有人看到问题了吗?我觉得区别在于:
PHP: binary.binary
和
JAVA: addAll(byte[],byte[])
预先感谢您的帮助。