4

我发现自己需要将网站平台从 Java 更改为 PHP,但我想保留所有用户的密码......

在将散列值写入网站密码之前,我让这段代码进行了密码散列:

MessageDigest md = null;
md = MessageDigest.getInstance("SHA");
md.update(plaintext.getBytes("UTF-8"));
byte raw[] = md.digest();
hash = new Base64().encodeToString(raw).replaceAll("\n", "").replaceAll("\r", "");

我认为 Java 代码对密码进行了 SHA-1 哈希处理,但在此之前它被字节编码为 UTF-8,然后它被 Base64 编码。

我想让 PHP 代码做同样的事情,即返回与 Java 中相同的密码相同的哈希值,只是似乎执行 SHA-1 哈希的 PHP 代码不会返回相同的 SHA (-1,不是 Base64 编码,我认为?)与 Java Base64 解码的哈希值相比的值......这可能与我在 PHP 中的密码不是首先编码 UTF-8 字节的事实有关(我怎么能在PHP中做到这一点)拜托?

ps

另一个奇怪的事情......我在 Java 中的密码都是 28 个字符长(通常是这样rnwn4zTNgH30l4pP8V05lRVGmF4=的)......但是Base64().decode(hash)这些密码哈希的值是 10 个字符长(一个例子[B@14e1f2b)。

我认为 Base64 为每 3 个字符增加了 1 个字符(28 或 27,不包括填充 = 宪章,比这 10 个字符大三分之一)所以我是否以某种方式错误地进行了解码调用?

最重要的是,PHP 中的 SHA-1 密码散列值是 40 个字符长(在 UTF-8 mysql 数据库中),像这样dd94709528bb1c83d08f3088d4043f4742891f4f吗?

4

3 回答 3

5

[B@14e1f2b绝对不是哈希。byte[]这是从to隐式转换的结果String

看起来你做了这样的事情:

String decodedHash = Base64().decode(hash); // Produces [B@14e1f2b

但是,哈希的正确表示是字节数组:

byte[] decodedHash = Base64().decode(hash); 
于 2011-01-22T16:33:56.960 回答
3

我通常使用 Java 来计算与 PHP sha1() 函数完全相同的 SHA-1 哈希值如下。关键是 toHexString 用于以可打印的方式显示原始字节。如果您使用 PHP 函数并希望获得与您的卷积过程相同的结果,则需要在 PHP 中使用参数 $raw_output 为 true 来获取原始字节并应用 Base64。完整的源代码

/**
 * Compute a SHA-1 hash of a String argument
 *
 * @param arg the UTF-8 String to encode
 * @return the sha1 hash as a string.
 */
public static String computeSha1OfString(String arg) {
    try {
        return computeSha1OfByteArray(arg.getBytes(("UTF-8")));
    } catch (UnsupportedEncodingException ex) {
        throw new UnsupportedOperationException(ex);
    }
}

private static String computeSha1OfByteArray(byte[] arg) {
    try {
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        md.update(arg);
        byte[] res = md.digest();
        return toHexString(res);
    } catch (NoSuchAlgorithmException ex) {
        throw new UnsupportedOperationException(ex);
    }
}

private static String toHexString(byte[] v) {
    StringBuilder sb = new StringBuilder(v.length * 2);
    for (int i = 0; i < v.length; i++) {
        int b = v[i] & 0xFF;
        sb.append(HEX_DIGITS.charAt(b >>> 4)).append(HEX_DIGITS.charAt(b & 0xF));
    }
    return sb.toString();
}
于 2011-01-22T16:41:16.793 回答
1

PHP 的sha1 () 默认将输出的每个字节编码为十六进制,但您可以通过true作为第二个参数传递来获取原始输出:

$digest = sha1($password, true); // This returns the same string of bytes as md.digest()

然后将摘要传递给base64_encode就完成了:

base64_encode(sha1($password, true));

这将返回与您的 java 代码完全相同的 SHA-1 哈希。

于 2011-01-22T16:45:11.983 回答