Get Least Significant Bit in PHP from Hex - php

I have a file with hex code and I need to get all the least significant bits from every byte in the file, concatenate them, split them in groups of 8 and then convert the bytes into ASCII. My problem is to extract the LSB from every byte.
The hex file looks like this (but is much longer):
58 00 00 1F 58 00 00 00 00 00 00 00 00 00 00 1C 22 23 1F 26 25 1E 2C 26 20 31 2B 22 38 2F 26 42 36 25 47 37 24 49 39 22
My code looks like this:
<?php
// Read file, remove spaces
$file = implode('', explode(' ', file_get_contents('vogel.hex')));
// Save LSB
$bits = array();
for ($i = 1; $i < strlen($file); ++$i)
{
$bits[] = $file[$i] & 1;
}
// Split LSB array into chunks of 8 bits.
$bytes = array_chunk($bits, 8);
// Implode byte arrays, convert to decimal, convert to ASCII.
foreach ($bytes as $byte)
{
echo chr(bindec(implode('', $byte)));
}
?>
I think that the splitting and converting part should work correctly, but I think I made a mistake when extracting the LSB. Can someone provide an example how I can extract the LSB?
I slightly edited my code, so that I start reading the bits at position 1. Then the decimal representation is within the ASCII range and the script outputs an actual ASCII character.

You could simply build up the bit string within the for loop, skipping the entire array procedure:
$bits = '';
for ($i = 1; $i < strlen($file); $i++) {
$bits .= (($file[$i] & 1) == 0) ? '0' : '1';
if ($i % 8 == 0) {
echo bindec($bits);
$bits = '';
}
}
Of course, you'd have some dangling bits if the input file's size isn't a multiple of 8.

A lot of programmers might cringe at your solution, but it works just fine with both ASCII and EBCDIC. I don't know of any other character set one might possibly be using with PHP.
The least significant bit of the character digit is the same as the value it represents. So your code will work. But it really deserves to have a comment explaining it relies on the least significant bit of the ASCII/EBCDIC display codes being the same as the digit.

what about shifting the hex left for hexvalue/2 times?
$hex = 0x05;
$shiftVal = (0 + $hex)/2;
echo $hex>>$shiftVal;//should output 1
another approach is to convert the hex to a number and see if it's odd or even:
$hex = 0xad;
echo $hex%2;

Related

PHP encoding problem: how to encode base64 encoded uint8 bytes to hex

My problem is that I was some time ago base64 encoding random bytes from openssl sha256 in C (as uint8_t), feeding them into a shell script and using the output.
What I can recreate from my data now is:
Content of file.txt:
uvjWEHTUk1LnzVZul9ynRpezWfKYN3bvlx103wxACxo
test#test:~# base64 -d file.txt | od -t x1
0000000 ba f8 d6 10 74 d4 93 52 e7 cd 56 6e 97 dc a7 46
0000020 97 b3 59 f2 98 37 76 ef 97 1d 74 df 0c 40 0b 1a
The output is the same as calling in PHP:
echo bin2hex(base64_decode("uvjWEHTUk1LnzVZul9ynRpezWfKYN3bvlx103wxACxo="));
baf8d61074d49352e7cd566e97dca74697b359f2983776ef971d74df0c400b1a
What I did all the time in shell and need to do now in PHP is the following:
Again, same content of file.txt:
uvjWEHTUk1LnzVZul9ynRpezWfKYN3bvlx103wxACxo
test#test:~# base64 -d file.txt | od -t x8
0000000 5293d47410d6f8ba 46a7dc976e56cde7
0000020 ef763798f259b397 1a0b400cdf741d97
My problem here: what is now the equal procedure in PHP (to od -t x8 in shell)?
I tried pack / unpack / bin2hex / ... and can't get the same result.
I'm trying to get a string with this content:
"5293d47410d6f8ba46a7dc976e56cde7ef763798f259b3971a0b400cdf741d97"
from a starting point of base64_decode("uvjWEHTUk1LnzVZul9ynRpezWfKYN3bvlx103wxACxo="). Any ideas?
If x8 is what you really need, which is 8 bytes, then the implementation would be as simple as
<?php
$str = 'uvjWEHTUk1LnzVZul9ynRpezWfKYN3bvlx103wxACxo';
$bin = base64_decode($str);
if (strlen($bin) % 8 !== 0) {
throw new \RuntimeException('data length should be divisible by 8');
}
$result = '';
for ($i = 0; $i < strlen($bin); $i += 8) {
for ($j = $i + 7; $j >= $i; --$j) {
$result .= bin2hex($bin[$j]);
}
}
echo $result;
It iterates over blocks of 8 bytes, then dumps them in reverse order each.
Ideone: https://ideone.com/hBanqi

Generate key for encryption in PHP which can be placed directly in C++ code for decryption

I am trying to build an application which generates an encryption key which is then placed directly in the code of a C++ application to decrypt it.
I am confused as to how a string in PHP is converted to the format used in C++.
As an example, have a look at this question here:
XTEA encryption in PHP and decryption in C
How did the answer by dschulz get the string
annoying monkey
to
uint32_t key[4] = {0x6f6e6e61, 0x676e6979, 0x6e6f6d20, 0x0079656b };
And how can this be done in PHP, so it prints that line in that format?
I've tried converting strings to hex and affixing 0x but it just doesn't work, any help would be appreciated.
That is simply the ascii value of the text in hex & little endian format:
a n n o y i n g m o n k e y
Hex: 61 6e 6e 6f 79 69 6e 67 20 6d 6f 6e 6b 65 79 00
\ / \ / \ / \ /
reverse reverse reverse reverse
/ \ / \ / \ / \
{0x6f6e6e61, 0x676e6979, 0x6e6f6d20, 0x0079656b };
Use this to convert the string:
<?php
$var = "annoying monkey";
$hex = '';
for ($i=0; $i<strlen($var); $i++){
$ord = ord($var[$i]);
$hexCode = dechex($ord);
$hex .= substr('0'.$hexCode, -2);
}
echo $hex; // 616e6e6f79696e67206d6f6e6b6579
After this, you only need to split the string into chunks of 8 and reverse the groups of 2 digits (each of the 4 letters)
$parts = str_split($hex,8);
foreach($parts as $key=>$value){
// pad right to make last group 8 chars long, even if it's shorter
$parts[$key] = str_pad($value, 8, "0", STR_PAD_RIGHT);
// split it into groups of 2 digits - each letter
$innerParts = str_split($parts[$key],2);
// reverse the order
$innerParts = array_reverse($innerParts);
// join and start with '0x'
$parts[$key] = "0x".implode('',$innerParts);
}
print_r($parts);
//Array
//(
// [0] => 0x6f6e6e61
// [1] => 0x676e6979
// [2] => 0x6e6f6d20
// [3] => 0x0079656b
//)
You can see it here:
https://3v4l.org/AVObB
To get your final string,
$string = 'uint32_t key['.count($parts).'] = {'. implode(',', $parts). '};';
echo $string;
// uint32_t key[4] = {0x6f6e6e61,0x676e6979,0x6e6f6d20,0x0079656b};
kindof tricky, given that in your raw php string, they're both "big endian bit order AND big endian byte order", here's one way to convert them (this approach use more cpu than required though, there's definitely a faster way than this)
<?php
// the raw key binary, big endian bit order, big endian byte order:
$key_bit_order_big_byte_order_big = "annoying_monkey";
//<pad>
// pad it to 32bits/4 bytes (uint32_t)
$pad_bytes = strlen($key_bit_order_big_byte_order_big) % 4;
if($pad_bytes > 0){
$pad_bytes = 4 - $pad_bytes;
assert($pad_bytes > 0);
$key_bit_order_big_byte_order_big .= str_repeat("\x00", $pad_bytes);
}
//</pad>
// convert from "big endian bit order, big endian byte order" to
// "little endian bit order, big endian byte order":
$key_bit_order_little_byte_order_big = strrev($key_bit_order_big_byte_order_big);
// convert from "little endian bit order, big endian byte order" to
// "little endian bit order, little endian byte order":
$key_bit_order_little_byte_order_little = implode("", array_reverse(str_split($key_bit_order_little_byte_order_big, 4), false));
// now to c++-ify it:
$key_chunks_little_endian = str_split($key_bit_order_little_byte_order_little, 4);
foreach($key_chunks_little_endian as &$chunk){
$chunk = "0x".bin2hex($chunk);
}
unset($chunk);
echo "uint32_t key[".count($key_chunks_little_endian)."] = {".implode(", ", $key_chunks_little_endian)."};";
outputs:
uint32_t key[4] = {0x6f6e6e61, 0x676e6979, 0x6e6f6d5f, 0x0079656b};

Convert from ascii to hex in php

I'm trying to convert from ASCII to HEX in PHP but get a different result to some of the online tools that are available. I know the result I'm looking for so the online tool's result appear to be correct and my code incorrect but I can't work out why.
String: 2Ffbj?DoyXOU
Correct output: 32 46 66 62 6a 3f 44 6f 79 58 4f 55 (from linked site above)
My output: 32 46 66 62 6a 3f 44 6f 79 58 4f 75
My script:
echo bin2hex(utf8_decode("2Ffbj?DoyXOU"));
Where is the fault?
Use that:
function ascii2hex($ascii) {
$hex = '';
for ($i = 0; $i < strlen($ascii); $i++) {
$byte = strtoupper(dechex(ord($ascii{$i})));
$byte = str_repeat('0', 2 - strlen($byte)).$byte;
$hex.=$byte." ";
}
return $hex;
}
The result:
Try this:
function ascii2hex($arg){
return implode(" ",array_map(fn($x) => sprintf("%02s",strtoupper(dechex(ord($x)))),str_split($arg)));
}
Thanks Patrick Maciel for the good answer.
Now if use PHP 7.4, there maybe an error message "Array and string offset access syntax with curly braces is no longer supported". Using "[" and "]" to replace "{" and "}" can solve the problem.
Reference:
Array and string offset access syntax with curly braces is deprecated

What kind of hash/encryption is this? '0E0B020601'

I've been asked to design back-end in php for a web app having ASP front-end. So I can't really dig up those ASP files. I have the MySQL database - that's it! The programmer who made the front-end isn't responding.
How do I decode this? Or just this - "what's the name of this encryption method?"
It looks something like HEX though.
Another sample - 0E0800160E0330595D57
0 1 2 3 4 5 6 7 8 9
0E 0B 02 06 01
0E 08 00 16 0E 03 30 59 5D 57
UPDATE - When I change my password to "kachwa" (without quotes), it gets updated as 040E0C07180E in the database.
Each byte is xor'd with 0x6f.
PHP sample encryption:
function enc($pass)
{
$enc = '';
for ($i = 0; $i < strlen($pass); ++$i)
$enc .= sprintf("%02x", ord($pass[$i]) ^ 0x6f);
return $enc;
}
echo enc("kachwa"),"\n";
Output:
040e0c07180e
And for the sake of completeness:
function dec($pass)
{
$dec = '';
foreach (str_split($pass, 2) as $hex)
$dec .= chr(hexdec($hex) ^ 0x6f);
return $dec;
}
echo dec("040e0c07180e"),"\n";

PHP Problem reading the hex values between these addresses?

<?php
$file = 'file.dat';
$file_contents = file_get_contents($file);
for ($i = 0x000481; $i <= 0x00048B; $i++) {
print $i;
}
?>
I am creating an online file analyzer but I have a small problem. It outputs (which is the actual position the hex is in)
1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
when it should be
44 72 48 79 64 72 61 6C 69 73 6B
which his hex for DrHydralisk (me). Can anyone help me output the latter or just have it strait output ASCII (but hex is fine, I can just convert it)?
edit
Here is an image of what I am trying to do that I think will help.
http://imgur.com/nwenA.png
Here is the file I am trying to read, its a Starcraft replay (file.SC2Replay). Just search for DrHydralisk in a hex editor and that is where I am trying to read from.
http://www.mediafire.com/?6w8wi35q3o6ix8q
It should be (if clear text is in the file):
for( $i=0x481; $i<0x48D; $i++ ) {
printf("%X ", ord($file_contents[$i]));
}
Note the loop boundaries: 0x481 .. 0x48D
Result:
44 72 20 48 79 64 72 61 6C 69 73 6B
If the file contains hexadecimal numbers, this would be impossible because you need two bytes per hex char for the ascii character value range. So what is really in the file?
Edit
After reading your file, i did:
...
$file = 'file.SC2Replay';
$file_contents = file_get_contents($file);
for( $i=0x438; $i<0x443; $i++) {
printf("%X ", ord($file_contents[$i]));
}
for( $i=0x438; $i<0x443; $i++) {
printf("%s ", $file_contents[$i]);
}
...
And it says:
72 48 79 64 72 61 6C 69 73 6B
and
D r H y d r a l i s k
You messed up the file position ;-)
Regards
rbo
EDIT:
Thanks for providing the file, helped a lot! Beleive I got it working too:
//Do binary safe file read
$filename = 'file.SC2Replay';
$file = fopen($filename, "rb");
$contents = fread($file, filesize($filename));
fclose($file);
//position 1080 - 1091
for ($i = 0x438; $i < 0x443; $i++)
echo $contents[$i];
The reasons you were probably having problems is that first of all, a binary safe file read in php automatically replaces the bytes with the correct ASCII characters, so that threw off what position you actually needed to start reading from. Intead of 1153, it starts at 1080.
Could you explain how you are using the file you read in? Because the hex equivalent of:
11531154115511561157115811591160116111621163
is:
481 482 483 484 485 486 487 488 489 48a 48b
Also, there are two php functions you may find helpful
chr(int): returns the ascii character associated with the integer provided - http://php.net/manual/en/function.chr.php
dechex(int): returns the hex value of the integer provided - http://php.net/manual/en/function.dechex.php

Categories