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
Related
I get through Modbus some 4-Byte Float Values.
I get this 4 bytes in an array:
Array ( [0] => 67 [1] => 105 [2] => 25 [3] => 154 )
After some Bitconversion I made this:
1000011011010010001100110011010
when putting this binary string into a online converter such as
https://www.binaryconvert.com/result_float.html?hexadecimal=4369199A
I get the value of 2.331E2 which is correct (233.1).
However I fail to convert this binary in a PHP float variable. I tried to point the address to a float variable, but did not succeed.
How can I convert this binary string or the array above into a php float?
Added:
The pointer Idea was stupid, since php does not let me define the type of variable. So I tried a different approach using unpack to a float type. But it does not work either:
// This represents a 4 byte float read from modbus
$array=array(67,105,25,154);
$array=array_reverse($array);
print_r($array);
for ($i=0;$i<count($array);$i++) {
$t+=pow(2,$i*8)*$array[$i];
}
echo '<br>Binary: '.decbin($t). ' - This would be the correct Binary for 233.1';
echo '<br>float: ';
print_r(unpack('f',$t));
This code results in:
Array ( [0] => 154 [1] => 25 [2] => 105 [3] => 67 )
Binary: 1000011011010010001100110011010 - This would be the correct Binary for 233.1
float: Array ( [1] => 6.5189725839687E-10 )
No chance to get my 233.1 :(
I know I come with a possible answer a little bit later but maybe others found useful.
The conversion is a little bit complicated, I worked few hours on it to include in my application.
Firstly I created a function to get value of the Mantissa, then calculated a float number. I didn't created function for the calculation of the exponent and sign.
This example is valid for positive float numbers, for more details read this:
HOW REAL (FLOATING POINT) AND 32-BIT DATA IS ENCODED IN MODBUS RTU MESSAGES
And the script:
$array=array(67,105,25,154);
$result = pow(2,(((($array[0] * 256 + $array[1]) & 32640) >> 7)-127)) * calcMantissa((($array[1] & 127) << 16) + ($array[2] << 8) + $array[3]+1);
echo $result . "\n";
function calcMantissa($nb) {
$retValue = 1;
for ($i = 0; $i < 22; $i++) {
$retValue = $retValue + (($nb & (1 << (22 - $i))) > 0) / (pow(2,($i+1))) ;
}
return $retValue;
}
which gave the following result:
233.10000610352
how do i convert this php code to vb
im trying to do this in .net but the value is only 1 value
what is the code of .net using my php codes
this is my code in php
$ctr = 7
for ($i = 0;$i < $ctr;$i++)
{
$prenum .= '0';
}
output = 0000000
Dim prenum as string = "0"
Dim ctr as Integer = 7
For i = 0 To ctr
output = prenum
Next
output = 0
the operator '.' in php concatenates strings, the operator for vb to concatenate is '&'...
Dim prenum as string = "0"
Dim ctr as Integer = 7
For i = 0 To ctr
output = output & prenum
Next
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
I need to convert integer to a 4 byte (32 bit) hex for sending it as ACK to a device i am currently trying to integrate.
For example
3 = 00000003
15 = 0000000F
Check http://www.mathsisfun.com/binary-decimal-hexadecimal-converter.html
1. Select signed 32 bit from the dropdown
2. Enter the value in decomal text box
3. Check value in hex field.
I am using php pack function with this parameter but based on the response from the device, it does not seem to be the correct approach.
$reply = pack(L*,$num);
Is this the correct parameter or there is some other way.
Please suuggest.
i would do
$a = 15;
var_dump( sprintf("%08X", $a) );
$a = 3;
var_dump( sprintf("%08X", $a) );
this outputs
string(8) "0000000F"
string(8) "00000003
08X means make a 8 char string padded with 0 (if needed) with the argument being treated as hex. (Upper case letters)
so in your example
$reply = sprintf("%08X", $num)
I just want to accomplish something where I want to convert strings from ansi to utf8 and vice versa.
example: to_ansi(1234)
expected result: NLKJ
example: to_utf8(NLKJ)
expected result: 1234
functions I currently have are:
function to_ansi($str)
{
$newString = "";
$reversedString = strrev($str);
for($i=0; $i < strlen($reversedString); $i++ ) {
$newString .= iconv(mb_detect_encoding(), 'UTF-8', chr(ord($reversedString[$i]) * 1.5));
}
return $newString;
}
function to_utf8($str)
{
$newString = "";
$reversedString = strrev($str);
for($i=0; $i < strlen($reversedString); $i++ ) {
$newString .= iconv(mb_detect_encoding(), 'UTF-8', chr(ord($reversedString[$i]) / 1.5));
}
return $newString;
}
usnig those functions above I get
example: to_ansi(1234)
result: NLKI
example: to_utf8(NLKJ)
result: 1224
actually I'm just interpreting vbs to PHP and the original functions are:
Function ToAnsi(ByVal strPassword As String) As String
Dim strLetter As String
Dim strRevPass As String
Dim strNewPass As String
strRevPass = strReverse(strPassword)
strNewPass = ""
For a = 1 To Len(strRevPass)
strLetter = Mid$(strRevPass, a, 1)
strNewPass = strNewPass & Chr((Asc(strLetter) * 1.5))
Next a
Text2.Text = strNewPass
End Function
Function ToUTF8(ByVal strPassword As String)
Dim strLetter As String
Dim strRevPass As String
Dim strNewPass As String
strRevPass = strReverse(strPassword)
strNewPass = ""
For a = 1 To Len(strRevPass)
strLetter = Mid$(strRevPass, a, 1)
strNewPass = strNewPass & Chr(Asc(strLetter) / 1.5)
Next a
txtText3.Text = strNewPass
End Function
Why do you think that 1234 in ANSI should NLKJ in UTF-8?
The reason of your problem might be a rounding error. You're multiplying and dividing by 1.5. For instance the letter 'y' (ASCII 122) divided by 1.5 is 80 2/3, which is treated as 81 (there are no fractions in character codes). Then back: 81 * 1.5 = 121.5 which is treated as 122, resulting in a 'z'.
So it's hard to grasp what the meaning of this code is. It certainly isn't a regular ANSI to UTF-8 conversion.
It seems to do some password hashing/encoding, but in a way that is very insecure. It's just a very simple encoding algorithm that can be very easily decoded as well, apart from the fact that it is inherently broken, and mangles your data beyond repair.