为了账号安全,请及时绑定邮箱和手机立即绑定

如何在php中获得与spring弹性框架中的encodePassword相同的值?

如何在php中获得与spring弹性框架中的encodePassword相同的值?

波斯汪 2019-04-18 14:15:34
我需要从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结果:9379d5a5fdd899cdf588b075988b9e94d2b3fe5cb44e593dd4a241f4757c8eecphp结果:hash_pbkdf2 result : 2794f28c44aa958663637ebeed391b533854fb2f4b7b7d09f521de8c1fe5c6bbhash result : b0782b680af7a13aeffc61006d2799d69ddc0465c33f376b40d946dd232f62ed我想让php的结果值等于Java的结果值。我该怎么办?
查看完整描述

1 回答

?
汪汪一只猫

TA贡献1898条经验 获得超8个赞

这是我经历过这个过程的过程; 我在这里完整地写出来帮助你学习这个过程,而不仅仅是这个解决方案。

ShaPasswordEncoder(为简洁起见删除注释)的来源:

public class ShaPasswordEncoder extends MessageDigestPasswordEncoder {
    public ShaPasswordEncoder() {
        this(1);
    }

    public ShaPasswordEncoder(int strength) {
        super("SHA-" + strength);
    }}

对我来说,看起来像一个非常薄的包装类。呼叫new ShaPasswordEncoder(256)是有效地与调用new MessageDigestPasswordEncoder("SHA-256"),所以让我们来看看源

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。它的工作原理与你期望的一样。从编号行:

  1. 加密密码

    • 这使用了看起来很无辜的mergePasswordAndSalt方法,我们接下来会看一下

  2. 哈希盐渍密码

    • 请注意这里的UTF-8编码 - 这并不总是默认编码

  3. 重复散列输出以进行其他迭代

    • 请注意,messageDigest.digest方法的输入和输出都是原始字节数组,而不是十六进制编码的字符串

  4. 返回最终输出的十六进制编码字符串

正如所承诺的,这是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 */
    }}

再次从编号部分:

  1. 检查空密码

  2. 检查是否存在{}字符; 由于下一点,这些是不允许的

  3. 在表单中输出salted密码 password{salt}

在这里,我们看到为什么您尝试在PHP中复制此算法失败。

从这些信息中,看看是否可以构建一个行为相同的PHP函数。我将在今晚晚些时候编辑一个完整的PHP解决方案,当时我可以访问一个环境来测试它。


查看完整回答
反对 回复 2019-05-15
  • 1 回答
  • 0 关注
  • 731 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信