我需要从php获取与使用Spring Security ShaPasswordEncoder对象的encodePassword方法获得的结果相同的值。
我无权修改相应的Java代码,因此仅php应该可以解决此问题。
Java代码:
ShaPasswordEncoder shaPasswordEncoder = new ShaPasswordEncoder(256);
shaPasswordEncoder.setIterations(1000);
String password = "123456789";
String salt = "123456";
String hash2 = shaPasswordEncoder.encodePassword(password, salt);
System.out.println(hash2);
我尝试了以下方法:
$password = "123456789";
$salt = "123456";
$hash = hash_pbkdf2('sha256', $password, $salt, 1000);
echo 'hash_pbkdf2 result : '.$hash.'<br>';
$out = $salt.$password;
for ($i = 0; $i < 1000; $i++) $out = hash('sha256', $out);
echo 'hash result : '.$out.'<br>';
Java结果:
9379d5a5fdd899cdf588b075988b9e94d2b3fe5cb44e593dd4a241f4757c8eec
php结果:
hash_pbkdf2 result : 2794f28c44aa958663637ebeed391b533854fb2f4b7b7d09f521de8c1fe5c6bb
hash result : b0782b680af7a13aeffc61006d2799d69ddc0465c33f376b40d946dd232f62ed
我想使php的结果值等于Java的结果值。我该怎么办?
答案 0 :(得分:0)
这是我解决这个问题的过程;我在这里将其完整写出来,以帮助您学习该过程,而不仅仅是这个解决方案。
来自ShaPasswordEncoder
的来源(为简洁起见删除了评论):
public class ShaPasswordEncoder extends MessageDigestPasswordEncoder {
public ShaPasswordEncoder() {
this(1);
}
public ShaPasswordEncoder(int strength) {
super("SHA-" + strength);
}
}
在我看来,这是一个非常瘦的包装器类。调用new ShaPasswordEncoder(256)
与调用new MessageDigestPasswordEncoder("SHA-256")
实际上是相同的,所以让我们看一下that的来源:
public class MessageDigestPasswordEncoder extends BaseDigestPasswordEncoder {
private final String algorithm;
private int iterations = 1;
[...]
public String encodePassword(String rawPass, Object salt) {
String saltedPass = mergePasswordAndSalt(rawPass, salt, false); /* 1 */
MessageDigest messageDigest = getMessageDigest();
byte[] digest = messageDigest.digest(Utf8.encode(saltedPass)); /* 2 */
// "stretch" the encoded value if configured to do so
for (int i = 1; i < this.iterations; i++) { /* 3 */
digest = messageDigest.digest(digest);
}
if (getEncodeHashAsBase64()) {
return Utf8.decode(Base64.encode(digest));
} else {
return new String(Hex.encode(digest)); /* 4 */
}
}
[...]
}
啊,现在我们到了某个地方。那里还有一些其他方法,但是我们现在只真正关心encodePassword
。它可以按您期望的那样工作。从编号的行:
mergePasswordAndSalt
方法,我们将在接下来的内容中进行探讨messageDigest.digest
方法的输入和输出都是原始字节数组,而不是十六进制编码的字符串如所承诺的,这是mergePasswordAndSalt
方法的来源:
protected String mergePasswordAndSalt(String password, Object salt, boolean strict) {
if (password == null) { /* 1 */
password = "";
}
if (strict && (salt != null)) { /* 2 */
if ((salt.toString().lastIndexOf("{") != -1)
|| (salt.toString().lastIndexOf("}") != -1)) {
throw new IllegalArgumentException("Cannot use { or } in salt.toString()");
}
}
if ((salt == null) || "".equals(salt)) {
return password;
} else {
return password + "{" + salt.toString() + "}"; /* 3 */
}
}
再次从编号部分开始:
{
和}
个字符;由于下一点,这些是不允许的password{salt}
的形式输出加盐的密码我们在这里看到了为什么您在PHP中重现该算法的尝试失败了。
根据此信息,查看是否可以构建行为相同的PHP函数。今晚晚些时候可以访问环境进行测试时,我将编辑完整的PHP解决方案。