【问题标题】:What is the .NET equivalent of the PHP function hash_hmac()PHP 函数 hash_hmac() 的 .NET 等价物是什么
【发布时间】:2011-12-25 04:02:08
【问题描述】:

我正在将一些代码从 PHP 移植到 .NET(我不是 PHP 开发人员),除了以下行之外,这一切看起来都非常简单:

public function hash($message, $secret)
{
    return base64_encode(hash_hmac('sha1', $message, $secret));
}

如何将此功能移植到 .NET?

base64编码是这样完成的,但是如何复制hash_hmac()呢?

Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(tmpString));

谢谢!

【问题讨论】:

  • .NET 版本的哈希值是否必须与 PHP 版本的哈希值相同,或者您可以随意使用任何哈希算法?
  • 我希望您将其用作消息验证码,而不是用作密码哈希。 1 次迭代 HMAC 对于密码哈希来说太快了。
  • @CodeInChaos 我使用它作为 MAC 来签署 API 请求。我不确定您所说的“太快”是什么意思,因为它在内部使用普通的 SHA1 散列 - 这是散列密码的标准,那么为什么出于兴趣而不能为此目的工作呢?此外,这是散列,而不是加密,所以它太快的事实似乎无关紧要,除非我错过了什么。
  • 将其用作 MAC 时,速度很快就可以了。当散列密码快速时不好,因为它使蛮力更快。这就是为什么使用减慢哈希的原因,例如 PBKDF2,它基本上是迭代的 HMAC,或 bcrypt。
  • 另外,你的php代码不是base64编码的十六进制字符串吗?

标签: php asp.net encryption hash cryptography


【解决方案1】:

如果您正在寻找 HMAC,那么您应该使用派生自 [System.Security.Cryptography.HMAC][1] 的类。

hash_hmac('sha1', $message, $secret)

在这种情况下,它将是[System.Security.Cryptography.HMACSHA1][2]

更新(更简单的代码,不依赖于 ASCII)

static string Hash (string message, byte[] secretKey)
{
    using (HMACSHA1 hmac = new HMACSHA1(secretKey))
    {
        return Convert.ToBase64String(
           hmac.ComputeHash(System.Text.UTF8.GetBytes(message));
    }
}

【讨论】:

    【解决方案2】:

    使用HashAlgorithm,即SHA1CryptoServiceProvider,例如:

    byte[] SHA1Hash (byte[] data)
    {
        using (var sha1 = new SHA1CryptoServiceProvider()) 
        {
            return sha1.ComputeHash(data);
        }
    }
    

    【讨论】:

    • 谢谢!与 hash_hmac() 函数相比,这会为字节兼容哈希生成一个字节吗?
    • 另外,我不太明白它是如何工作的,因为我需要将“消息”和“秘密”作为两个单独的参数传入。当它只需要一个参数时,我该怎么做?我刚刚注意到有一个 System.Security.Cryptography.HMACSHA1 类可能更适合我的需求。
    • 有很多选项,我猜你甚至可以使用HashAlgorithm.Create("SHA1");至于消息和秘密,您只需将两者结合起来 - 鉴于您已经在进行转换和获取字节等,我想我会把它留给读者练习。从技术上讲,不同实现的结果应该是相同的。
    【解决方案3】:

    最后我设法创建了一个基于 HMACSHA1 类的解决方案:

    private string Hash(string message, byte[] secretKey)
    {
        byte[] msgBytes = System.Text.Encoding.UTF8.GetBytes(message);
        byte[] hashBytes;
        using (HMACSHA1 hmac = new HMACSHA1(secretKey))
        { 
            hashBytes = hmac.ComputeHash(msgBytes); 
        }
        var sb = new StringBuilder();
        for (int i = 0; i < hashBytes.Length; i++) 
              sb.Append(hashBytes[i].ToString("x2"));
        string hexString = sb.ToString();
        byte[] toEncodeAsBytes = System.Text.ASCIIEncoding.ASCII.GetBytes(hexString);
        return System.Convert.ToBase64String(toEncodeAsBytes);
    }
    

    更新:稍微压缩了代码 - 不需要这么多辅助函数。

    【讨论】:

    • .NET 版本似乎需要更多代码才能与 PHP 版本完全兼容!但也许我还没有给出最紧凑的例子。
    • 小心使用ASCII,因为它不会转换string 中的每个字符(例如,使用UTF8Unicode)。另外我不知道您为什么要将hashBytes 转换为字符串,只是为了将其转换为十六进制然后对其进行base64 编码?!?兼容性?如果您简单地使用Convert.ToBase64String (hashBytes);,您的代码会简单得多
    • @poupou 因为如果我不这样做,我似乎会得到完全不同的结果。这是我发布问题的最初原因。这似乎是我可以复制我正在使用的 API 所需的 PHP 函数行为的唯一方法。我认为在这种情况下使用 ASCII 是安全的,因为我首先只是散列 ASCII 字符串。我将尝试将其更改为 UTF8,看看它是否仍然兼容。刚看到你的回答,明天我也试试。
    • 对于 ASCII 字符串,UTF8 将给出相同的结果。对于代码点 >127 的字符串,ASCII 会显示奇怪的行为。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-02
    • 2014-07-21
    相关资源
    最近更新 更多