经典 ASP 中的各种 HMAC_SHA256 函数给出不同的结果

人气:885 发布:2022-10-16 标签: php asp-classic cryptojs

问题描述

不知何故,我需要在 Classic ASP 中生成一个哈希,它相当于 PHP 的以下函数的输出:

Somehow I need to generate a hash in Classic ASP which is equivalent to PHP's following function's output:

$hash = hash_hmac('SHA256', $message, pack('H*', $secret));

其中 $message = 'stackoverflow';$secret = '1234567890ABCDEF';.我在网上尝试了很多方法,但没有一个与 PHP 结果匹配:

where $message = 'stackoverflow'; $secret = '1234567890ABCDEF';. I tried quite a lot approaches online, but none matches the PHP result:

bcb3452cd48c0f9048e64258ca24d0f3399563971d4a5dcdc531a7806b059e36

方法一:在线使用dvim_brix_crypto-js-master_VB.asp(使用CrytoJS)

Function mac256(ent, key) 
    Dim encWA
    Set encWA = ConvertUtf8StrToWordArray(ent)
    Dim keyWA
    Set keyWA = ConvertUtf8StrToWordArray(key)
    Dim resWA
    Set resWA = CryptoJS.HmacSHA256(encWA, key)
    Set mac256 = resWA
End Function

Function ConvertUtf8StrToWordArray(data)
    If (typename(data) = "String") Then
        Set ConvertUtf8StrToWordArray = CryptoJS.enc.Utf8.parse(data)
    Elseif (typename(data) = "JScriptTypeInfo") Then
        On error resume next
        'Set ConvertUtf8StrToWordArray = CryptoJS.enc.Utf8.parse(data.toString(CryptoJS.enc.Utf8)) 
        Set ConvertUtf8StrToWordArray = CryptoJS.lib.WordArray.create().concat(data) 'Just assert that data is WordArray
        If Err.number>0 Then
            Set ConvertUtf8StrToWordArray = Nothing
        End if
        On error goto 0
    Else
        Set ConvertUtf8StrToWordArray = Nothing
    End if
End Function

脚本可以在这里找到.该方法给出:

The script can be found here. This method gives:

c8375cf0c0db721ecc9c9b3a034284117d778ee8594285196c41d5020917f78c

方法 2:纯经典 ASP 方法

Public Function HMAC_SHA256(prmKey, prmData)
    Dim theKey : theKey = prmKey
    Dim Block_Size, O_Pad, I_Pad
    Block_Size = 64
    O_Pad = 92 'HEX: 5c'
    I_Pad = 54 'HEX: 36'

    Dim iter, iter2
    If Len(theKey) < Block_Size Then
        For iter = 1 to Block_Size - Len(theKey)
            theKey = theKey & chr(0)
        Next
    ElseIf Len(theKey) > Block_Size Then
        theKey = SHA256(theKey)
    End If

    Dim o_key_pad : o_key_pad = ""
    Dim i_key_pad : i_key_pad = ""
    For iter = 1 to Block_Size
        o_key_pad = o_key_pad & Chr(Asc(Mid(theKey,iter,1)) xor O_Pad)
        i_key_pad = i_key_pad & Chr(Asc(Mid(theKey,iter,1)) xor I_Pad)
    Next

    HMAC_SHA256 = SHA256(o_key_pad & SHA256(i_key_pad & prmData))
End Function
result = HMAC_SHA256(secret, message)

这个方法给出:

bc0511316791176484c7d80bc8faaecd8388b75fb97516181ba6b361fd032531

方法3:使用亚马逊AWS的sha256.wsc(使用CrytoJS)

Dim sha
Set sha = GetObject( "script:" & Server.MapPath("sha256.wsc") )
sha.hexcase = 0
result = sha.b64_hmac_sha256(secret, message)

可以找到 WSC 这里.该方法给出(与方法1相同的结果):

The WSC can be found here. This method gives (same result as Method 1):

c8375cf0c0db721ecc9c9b3a034284117d778ee8594285196c41d5020917f78c

我认为问题在于 pack() 部分,它将十六进制字符串更改为二进制.因此,我找到了一种在 ASP 中重现 pack() 函数的方法:

I think the problem is the pack() part, which changes the Hex string to binary. Therefore, I found a way to reproduce the pack() function in ASP:

Dim key2, hexarr, binstr
key2 = "12 34 56 78 90 AB CD EF"
hexarr = Split(key2)
ReDim binarr(UBound(hexarr))

For i = 0 To UBound(hexarr)
  binarr(i) = Chr(CInt("&h" & hexarr(i)))
Next

binstr = Join(binarr, "")

其中 key2 是原始密钥,每 2 个字符添加一个空格.通过将 secret 替换为 binstr,这些方法现在产生:

where the key2 is the original secret with space added in every 2 characters. By replacing the secret with binstr, the methods now produce:

Method 1: 8ab9e595eab259acb10aa18df7fdf0ecc5ec593f97572d3a4e09f05fdd3aeb8f
Method 2: d23fcafb41d7b581fdae8c2a4a65bc3b19276a4bd367eda9e8e3de43b6a4d355
Method 3: 8ab9e595eab259acb10aa18df7fdf0ecc5ec593f97572d3a4e09f05fdd3aeb8f

以上结果都与 PHP 的结果不同.我现在错过了什么?

None of the above results is identical to PHP's one. What did I miss now?

推荐答案

看看下面的例子.

这种方法的唯一要求是 Microsoft .Net Framework 2.0(从 Windows Server 2003 R2 开始预安装)才能使用 Com Interops.

The only requirement with this approach is Microsoft .Net Framework 2.0 (preinstalled starting from Windows Server 2003 R2) to use Com Interops.

我试图在评论中进行描述,但请随时提出问题.

I tried to be descriptive in the comments but feel free to ask questions about it.

'Returns Byte(), UTF-8 bytes of unicode string
Function Utf8Bytes(text)
    With Server.CreateObject("System.Text.UTF8Encoding")
        Utf8Bytes = .GetBytes_4(text)
    End With
End Function

'Returns String, sequential hexadecimal digits per byte
'data As Byte()
Function BinToHex(data)
    With Server.CreateObject("MSXML2.DomDocument").CreateElement("b64")
        .dataType = "bin.hex"
        .nodeTypedValue = data
        BinToHex = .text
    End With
End Function

'Returns Byte(), a keyed hash generated using SHA256 method
'data As String, key As Byte()
Function HashHmacSha256(data, key)
    With Server.CreateObject("System.Security.Cryptography.HMACSHA256")
        .Key = key
        HashHmacSha256 = .ComputeHash_2(UTF8Bytes(data))
    End With
End Function

'Returns Byte(), of a packed hexadecimal string
'instead of PHP's pack('H*'
Function HexToBin(data)
    With Server.CreateObject("MSXML2.DomDocument").CreateElement("b64")
        .dataType = "bin.hex"
        .text = data
        HexToBin = .nodeTypedValue
    End With
End Function

packed_secret = HexToBin("1234567890ABCDEF")
message = "stackoverflow"
binary_hash = HashHmacSha256(message, packed_secret)
string_hash = BinToHex(binary_hash)

Response.Write string_hash

298