Various HMAC_SHA256 functions in classic ASP gives different results - 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));
where $message = 'stackoverflow'; $secret = '1234567890ABCDEF';. I tried quite a lot approaches online, but none matches the PHP result:
bcb3452cd48c0f9048e64258ca24d0f3399563971d4a5dcdc531a7806b059e36
Method 1: Using dvim_brix_crypto-js-master_VB.asp online (using 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
Method 2: Pure Classic ASP Approach
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)
This method gives:
bc0511316791176484c7d80bc8faaecd8388b75fb97516181ba6b361fd032531
Method 3: Using Amazon AWS's sha256.wsc (using CrytoJS)
Dim sha
Set sha = GetObject( "script:" & Server.MapPath("sha256.wsc") )
sha.hexcase = 0
result = sha.b64_hmac_sha256(secret, message)
The WSC can be found here. This method gives (same result as Method 1):
c8375cf0c0db721ecc9c9b3a034284117d778ee8594285196c41d5020917f78c
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, "")
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
None of the above results is identical to PHP's one. What did I miss now?

Check out the following example.
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

Related

PHP Converting Hex string to Byte Array - converting VB.Net to PHP

I'm writing a PHP website that is accessing an encrypted MySQL database. The database is currently a back end to a VB.Net Windows forms program. This is all working fine, but I want to the PHP website to access some of the data and be able to decrypt/encrypt it. The fields are encrypted using Blowfish code originally written by David Ireland in VB6 and converted by Todd Acheson with a few tweaks from myself.
With the PHP Blowfish examples I've seen, the $iv is set at random, but I need it to be set to the same as that created in VB, so I'm attempting to convert the VB code to PHP.
I've started converting the code line by line, and from a technical perspective, it seems OK, but testing the first part of it doesn't provide the same results as with VB
Setting the key:
Dim aKey() as Byte = cv_BytesFromHex(MySecretKey)
Public Function cv_BytesFromHex(ByVal sInputHex As String) As Object
' Returns array of bytes from hex string in big-endian order
' E.g. sHex="FEDC80" will return array {&HFE, &HDC, &H80}
Dim i As Long
Dim M As Long
Dim aBytes() As Byte
If Len(sInputHex) Mod 2 <> 0 Then
sInputHex = "0" & sInputHex
End If
M = Len(sInputHex) \ 2
ReDim aBytes(M - 1)
For i = 0 To M - 1
Dim x = "&H" & Mid(sInputHex, i * 2 + 1, 2)
Debug.Print(x + " " + Val(x).ToString)
aBytes(i) = Val(x)
Next
cv_BytesFromHex = aBytes 'CopyArray(aBytes)
Return cv_BytesFromHex
End Function
Converting this function to PHP5.
public function cv_BytesFromHex($inputstring)
{
// Returns array of bytes from hex string in big-endian order
// e.g. shex="fedc80" will return array {&hfe, &hdc, &h80}
$i=0;
$m=0;
if (strlen($inputstring)/2 <> (int)(strlen($inputstring)/2)) {
$inputstring = "0".$inputstring;
}
$m = strlen($inputstring)/2;
echo 'Length '.strlen($inputstring).' = '.$m." elements</br>";
$abytes=array_fill(0,$m-1,0) ;
for ($i=0; $i<=$m-1;$i++) {
$raw=substr($inputstring, $i * 2 , 2);
$hexed=hexdec($raw);
echo 'Raw ='.$raw.' = '.$hexed.'</br>';
$abytes[$i]=$hexed;
}
return $abytes;
}
Testing with the key "1check".
VB output:
&H1C 28
&Hhe 0
&Hck 12
PHP output:
Length 6 = 3 elements
Raw =1c = 28
Raw =he = 14
Raw =ck = 12
So.. in this example, "1C" and "ck" give me the same values, but "he" doesn't
another example:
key =10stack
vb
&H01 1
&H0s 0
&Hta 0
&Hck 12
php
Length 8 = 4 elements
Raw =01 = 1
Raw =0s = 0
Raw =ta = 10
Raw =ck = 12
This one works:
key =1234wxyz
vb
&H12 18
&H34 52
&Hwx 0
&Hyz 0
php
Raw =12 = 18
Raw =34 = 52
Raw =wx = 0
Raw =yz = 0
Does anyone know why?
so, there is no errors here. h is ignored by hexdec and only e is decoded. cause...
https://en.wikipedia.org/wiki/Hexadecimal there is no h :)
and in VBA Val function returns 0, cause he is not valid hex-combination
<?php
function myHex($str)
{
if ($str === dechex(hexdec($str))) {
return hexdec($str);
}
return 0;
}
var_dump(myHex("he")); // returns 0

php code equivalent in asp.net vb

I am working on payment system, the original code in php working fine, Now I am rewriting it on asp.net(vb), I change it step by step and stopped at this stage for different results between "php" and ".net".
PHP CODE:
$sha1Signature = "484cea8e6bd1153674548ebab5a3673a5c3d0381";
$base64Sha1Signature = base64_encode(pack("H*",$sha1Signature));
echo $base64Sha1Signature ;
The Result : SEzqjmvRFTZ0VI66taNnOlw9A4E=
.NET CODE:
Function Pack2(strToPack As String) As Byte()
Dim raw_bytes As Byte() = New Byte(15) {}
For i As Integer = 0 To 32 - 1 Step 2
raw_bytes(i / 2) = Convert.ToByte(strToPack.Substring(i, 2), 16)
Next
Return raw_bytes
End Function
Function getBase64Code(strToCode As String, Optional pack As Boolean = False) As String
Dim byt As Byte() = System.Text.Encoding.ASCII.GetBytes(strToCode)
If pack Then
byt = Pack2(strToCode)
End If
Return Convert.ToBase64String(byt)
End Function
Dim sha1Signature As String = "484cea8e6bd1153674548ebab5a3673a5c3d0381"
Response.Write(getBase64Code(sha1Signature, True))
The Result: SEzqjmvRFTZ0VI66taNnOg==
If you see that the results are almost the same and differ in the last 4 letters only, which means I am close to success :) The results must be identical.
PHP : SEzqjmvRFTZ0VI66taNnOlw9A4E=
.NET : SEzqjmvRFTZ0VI66taNnOg==
Your loop should run from 0 to "input-string-length". Also the init of the bytearray should be half of your hex-string.
static void Main(string[] args)
{
string tmp = "484cea8e6bd1153674548ebab5a3673a5c3d0381";
Console.WriteLine(Convert.ToBase64String(Pack2(tmp)));
}
public static byte[] Pack2(string hexString)
{
byte[] bytes = new byte[hexString.Length / 2]; // two hex-digits are one byte
for (int i = 0; i < hexString.Length; i += 2)
bytes[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16);
return bytes;
}

hmacsha1 encrpyt in vba does not equal to php hmac_sha1 value with pack method

This is my VB6 Code
Private Function Encryp_HMACSHA1(pData As String, pSecretKey As String) As String
Dim encoder As Object
Dim crypto As Object
Dim i As Integer
Dim bSecretKey() As Byte
Dim bData() As Byte
Dim bEncrypted() As Byte
Set encoder = CreateObject("System.Text.UTF8Encoding")
Set crypto = CreateObject("System.Security.Cryptography.HMACSHA1")
bData = encoder.Getbytes_4(pData)
bSecretKey = encoder.Getbytes_4(pSecretKey)
crypto.Key = bSecretKey
bEncrypted = crypto.ComputeHash_2(bData)
Set encoder = Nothing
Set crypto = Nothing
Dim objXML As MSXML2.DOMDocument
Dim objNode As MSXML2.IXMLDOMElement
Set objXML = New MSXML2.DOMDocument
Set objNode = objXML.createElement("b64")
objNode.dataType = "bin.base64"
objNode.nodeTypedValue = bEncrypted
EncodeBase64 = objNode.Text
Encryp_HMACSHA1 = EncodeBase64
Set objNode = Nothing
Set objXML = Nothing
End Function
Public Function Pack(strlength As String) As String
Dim Temp As String
Dim MyString As String
Dim i As Integer
MyString = ""
For i = 1 To Len(strlength) Step 2
Temp = Mid(strlength, i, 2)
MyString = MyString & Chr(CLng("&H" & Temp))
Next
Pack = MyString
End Function
Private Sub Command1_Click()
Dim pKey As String
pKey = Pack("1989151498577ad12a9f8adf157f5abf")
Text1.Text = Encryp_HMACSHA1("test", pKey)
End Sub
result for vb is : 03AM+k4B3mPEZlkCatDvdiHOuuc=
This is my php code
$key = "1989151498577ad12a9f8adf157f5abf";
$decodeKey = pack("H*",$key);
$data = "test";
$hash = hash_hmac("SHA1", $data, $decodeKey, TRUE);
$signature = base64_encode($hash);
echo $signature;
result for the php is : 4QXpNBD/cv0sLIfFIsFGe5D57gI=
Please help in solving the equation.
And There is another problem, If we encrypt the data without pack method both are the outputs are same, but if we does with pack it shows different results.
Your VB6 Pack function is:
converting two hex digits at a time to bytes, then
converting those values to characters with ANSI-to-Unicode translation.
Then your Encryp_HMACSHA1:
takes such String values and converts them into Byte arrays using conversion to UTF-8, and
feeds that into crypto.Key to munch on.
Playing fast and loose using Strings in this manner has corrupted your key value.
I was apply to reproduce the incorrect signature result by taking known-working VB6 code and altering it to perform the same distortion.
I'm not sure why you are using this great big heavy .Net inter-clop approach to doing part of the job and then taking another really heavy run through an MSXML DOM just for Base64 encoding. Wow, do you have enough RAM for this to even run?
I used the HS1.cls from the attachment (HS1 Demo 1-1.zip) at:
[VB6] HMAC-SHA-256, HMAC-SHA-1 Using Crypto API #35
Then all that was required was:
Private Function HMACSHA1(ByVal Data As String, ByVal Key As String) As String
With New HS1
.InitHmac .Decode(Key, edfHexRaw)
HMACSHA1 = .Encode(.HMACSHA1(.ToUTF8(Data)), edfBase64, efNoFolding)
End With
End Function
Where Data is VB6/Windows "Unicode" text (UCS-2/UTF-16LE) and Key is a "Unicode" string of hexadecimal text. E.g.:
txtSignature.Text = HMACSHA1("test", "1989151498577ad12a9f8adf157f5abf")
Sure enough, it produces:
4QXpNBD/cv0sLIfFIsFGe5D57gI=
This is also far lighter weight than using (a.) the .Net CLR and Framework libraries plus "interop" and (b.) MSXML as super-fat wrappers around simple API calls.
But you could keep all of that overhead if you really want to as long as you correct your "String of hex digits to Key" parsing logic.
If "1989151498577ad12a9f8adf157f5abf" is supposed to be the key in hexadecimal the php code is correct.
Verify if Encryp_HMACSHA1 expects the key to be data or a hexadecimal string.
Verify if the keys after conversion to data are the same by displaying them in hex

TripleDES encryption not getting same value in PHP as in VB

I found a lot of solutions that explain how to look at C# versus PHP, but none specific to VB. I did find one helpful hint about PHP padding with zeroes, but that didn't solve the problem as I matched that in VB and it didn't help. Anyway I am familiar with VB and we have another developer familiar with PHP and we are trying to make our functions match so that tripleDES encryption spits out the same value in both. We are integrating with a third party application, and I know the VB code is spitting out the correct value but PHP is not. I have both VB and PHP code listed below, would anyone out there be familiar enough with both to have any idea why the PHP code isn't returning the correct value? I know the value that is being returned from PHP is the correct length, but there is something off and it's not matching. Please help.
VB:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Dim dataToHash As String
Dim encryptedText As String = ""
dataToHash = "hereismystring"
Dim buffer As Byte() = Encryption(dataToHash, "abcd1234")
encryptedText = Convert.ToBase64String(buffer)
lblToken.Text = encryptedText.ToString()
End Sub
Public Shared Function Encryption(ByVal PlainText As String, ByVal key As String) As Byte()
Dim des As TripleDES = CreateDES(key)
Dim ct As ICryptoTransform = des.CreateEncryptor()
Dim input As Byte() = Encoding.Unicode.GetBytes(PlainText)
Return ct.TransformFinalBlock(input, 0, input.Length)
End Function
Private Shared Function CreateDES(ByVal key As String) As TripleDES
Dim md5 As MD5 = New MD5CryptoServiceProvider()
Dim des As TripleDES = New TripleDESCryptoServiceProvider()
des.Key = md5.ComputeHash(Encoding.Unicode.GetBytes(key))
des.IV = New Byte(des.BlockSize / 8 - 1) {}
des.Padding = PaddingMode.Zeros
Return des
End Function
PHP:
$start = "hereismystring";
$cipher = MCRYPT_TRIPLEDES;
$mode = MCRYPT_MODE_CBC;
$rawKey = "abcd1234";
$ssoKey = md5($key_encoded,true);
$key_size = strlen($ssoKey);
$iv_size = mcrypt_get_iv_size(MCRYPT_TRIPLEDES, MCRYPT_MODE_CBC);
$ssoIV = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$user_str = mb_convert_encoding($start,"UTF-16LE");
$key_blocksize = mcrypt_get_block_size($cipher,$mode);
$key_padding_size = $key_blocksize - (strlen($user_str) % $key_blocksize);
$user_str .= str_repeat(chr($key_padding_size), $key_padding_size);
$key_iv = mcrypt_create_iv(mcrypt_get_iv_size($cipher,$mode),"");
$key_triple = substr($key_encoded,0,mcrypt_get_key_size($cipher,$mode));
$key_encoded_text = mcrypt_encrypt($cipher,$key_triple,$user_str,$mode,$key_iv);
$final = base64_encode($key2_encoded_text);
echo "<p>" . $final </p>";
?>
Thanks,
Joe

How do I convert mcrypt_encrypt from PHP into .NET code?

I'm looking to convert this function from PHP to VB. Could anyone help me understand why the output is not correct?
//get img
$img = file_get_contents('https://www.random.org/analysis/randbitmap-rdo-section.png');
//pad
$blocksize = 16;
$pad = $blocksize - (strlen($img) % $blocksize);
$paddedimg = $img . str_repeat(chr($pad), $pad);
//encrypt
$data = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, 'abcdefghijklmnop', $paddedimg, MCRYPT_MODE_ECB);
//output
echo base64_encode($data);
The above outputs;
wYkugZmmsCHNwFOr7sAgk6yUU2I+2rOtBmXAIcPleue+dT4zIvkSA6UYmW6tickeoIbyCylxrb5n ...
[rest truncated but goes on and total is 29484 characters]
Here's what I have in VB;
Public Sub GetBase64EncryptedImg()
Dim Img As Byte() = Nothing
Using wc As New WebClient
Img = wc.DownloadData("https://www.random.org/analysis/randbitmap-rdo-section.png")
End Using
MsgBox(EncryptECB(Img))
End Sub
Public Function EncryptECB(Data As Byte()) As String
Dim Key As Byte() = Encoding.UTF8.GetBytes("abcdefghijklmnop")
Dim Encrypted As Byte() = Nothing
Using rj As New RijndaelManaged()
Try
rj.Padding = PaddingMode.PKCS7
rj.Mode = CipherMode.ECB
rj.KeySize = 128
rj.BlockSize = 128
rj.Key = Key
Dim ms As New MemoryStream()
Using cs As New CryptoStream(ms, rj.CreateEncryptor(rj.Key, rj.IV), CryptoStreamMode.Write)
Using sr As New StreamWriter(cs)
sr.Write(Data)
End Using
Encrypted = ms.ToArray()
End Using
Finally
rj.Clear()
End Try
End Using
Return Convert.ToBase64String(Encrypted)
End Function
The VB outputs;
pVngUaXYYv1tJSPzjDuwKw==
That's it, nowhere close to the right number of characters. Where am I going wrong here?
EDIT: Re being marked as duplicate, that question/answer gives back a base64 encoded string. mcrypt_encrypt doesn't, so I'm not sure how to apply the code in that answer.
EDIT2: That duplicate gives uses an IV value whereas the code above doesn't. Would that not differentiate the two to deserve a unique answer? Or is it as simple as removing the line setting the IV property of the RijndaelManaged object?
EDIT3: Completely reworked the question

Categories