Good day, I am making my hashing algorthm, so I am rewriting it to C++ from PHP.
But result in C++ is different than php result. PHP result contains more than 10 characters, C++ result only 6 - 8 characters. But those last 8 characters of PHP result are same as C++ result.
So here is PHP code:
<?php function JL1($text) {
$text.="XQ";
$length=strlen($text);
$hash=0;
for($j=0;$j<$length;$j++) {
$p=$text[$j];
$s=ord($p);
if($s%2==0) $s+=9999;
$hash+=$s*($j+1)*0x40ACEF*0xFF;
}
$hash+=33*0x40ACEF*0xFF;
$hash=sprintf("%x",$hash);
return $hash; } ?>
And here C++ code:
char * JL1(char * str){
int size=(strlen(str)+3),s=0; //Edit here (+2 replaced with +3)
if(size<=6) //Edit here (<9 replaced with <=6)
size=9;
char *final=new char[size],temp;
strcpy(final,str);
strcat(final,"XQ");
long length=strlen(final),hash=0L;
for(int i=0;i<length;i++){
temp=final[i];
s=(int)temp;
if(s%2==0)s+=9999;
hash+=((s)*(i+1)*(0x40ACEF)*(0xFF));
}
hash+=33*(0x40ACEF)*(0xFF);
sprintf(final,"%x",hash); //to hex string
final[8]='\0';
return final; }
Example of C++ result for word: "Hi!" : 053c81be
And PHP result for this word: 324c053c81be
Does anyone know,where is that mistake and how to fix that, whether in php or in cpp code?
By the way, when I cut those first letters in php result I get C++ result, but it wont help, because C++ result have not to be 8 characters long, it can be just 6 characters long in some cases.
Where to begin...
Data types do not have fixed guaranteed sizes in C or C++. As such, hash may overflow every iteration, or it may never do so.
chars can be either signed or unsigned, therefore converting one to an integer may result in negative and positive values on different implementations, for the same character.
You may be writing past the end of final when printing the value of hash into it. You may also be cutting the string off prematurely when setting the 9th character to 0.
strcat will write past the end of final if str is at least 7 characters long.
s, a relatively short-lived temporary variable, is declared way too soon. Same with temp.
Your code looks very crowded with almost no whitespace, and is very hard to read.
The expression "33*(0x40ACEF)*(0xFF)" overflows; did you mean 0x4DF48431L?
Consider using std::string instead of char arrays when dealing with strings in C++.
long hash in C++ is most likely limited to 32 bits on your platform. PHP's number isn't.
sprintf(final, "%x", hash) produces a possibly incorrect result. %x interprets the argument as an unsigned int, which is 32 bits on both Windows and Linux x64. So it's interpreting a long as an unsigned int, if your long is more than 32 bits, your result will get truncated.
See all the issues raised by aib. Especially the premature termination of the result.
You will need to deal with the 3rd point yourself, but I can answer the first two. You need to clamp the result to 32 bits: $hash &= 0xFFFFFFFF;.
If you clamp the final value, the php code will produce the same results as the C++ code would on x64 Linux (that means 64 bit integers for intermediate results).
If you clamp it after every computation, you should get the same results as the C++ code would on 32 bit platforms or Windows x64 (32 bit integers for intermediate results).
There seems to be a bug here...
int size=(strlen(str)+2),s=0;
if(size<9)
size=9;
char *final=new char[size],temp;
strcpy(final,str);
strcat(final,"XQ");
If strlen was say 10, then size will be 12 and 12 chars will be allocated.
You then copy in the original 10 characters, and add XQ, but the final terminating \0 will be outside of the allocated memory.
Not sure if that's your bug or not but it doesn;t look right
Related
I am trying to solve a CTF in which the juggling type should be used. The code is:
if ($_GET["hash"] == hash("ripemd160", $_GET["hash"]))
{
echo $flag;
}
else
{
echo "<h1>Bad Hash</h1>";
}
I made a script in python which checks random hashes in ripemd160 that begins with "0e" and ends with only numbers. The code is:
def id_generator(size, chars=string.digits):
return ''.join(random.choice(chars) for _ in range(size))
param = "0e"
results = []
while True:
h = hashlib.new('ripemd160')
h.update("{0}".format(str(param)).encode('utf-8'))
hashed = h.hexdigest()
if param not in results:
print(param)
if hashed.startswith("0e") and hashed[2:].isdigit():
print(param)
print(hashed)
break
results.append(param)
else:
print("CHECKED")
param = "0e" + str(id_generator(size=10))
Any suggestions on how to solve it? Thank you!
There seems to be a bit of misunderstanding in the comments, so I'll start by explaining the problem a little more:
Type juggling refers to the behaviour of PHP whereby variables are implicitly cast to different data types under certain conditions. For example, all the following logical expressions will evaluate to true in PHP:
0 == 0 // int vs. int
"0" == 0 // str -> int
"abc" == 0 // any non-numerical string -> 0
"1.234E+03" == "0.1234E+04" // string that looks like a float -> float
"0e215962017" == 0 // another string that looks like a float
The last of these examples is interesting because its MD5 hash value is another string consisting of 0e followed by a bunch of decimal digits (0e291242476940776845150308577824). So here's another logical expression in PHP that will evaluate to true:
"0e215962017" == md5("0e215962017")
To solve this CTF challenge, you have to find a string that is "equal" to its own hash value, but using the RIPEMD160 algorithm instead of MD5. When this is provided as a query string variable (e.g., ?hash=0e215962017), then the PHP script will disclose the value of a flag.
Fake hash collisions like this aren't difficult to find. Roughly 1 in every 256 MD5 hashes will start with '0e', and the probability that the remaining 30 characters are all digits is (10/16)^30. If you do the maths, you'll find that the probability of an MD5 hash equating to zero in PHP is approximately one in 340 million. It took me about a minute (almost 216 million attempts) to find the above example.
Exactly the same method can be used to find similar values that work with RIPEMD160. You just need to test more hashes, since the extra hash digits mean that the probability of a "collision" will be approximately one in 14.6 billion. Quite a lot, but still tractable (in fact, I found a solution to this challenge in about 15 minutes, but I'm not posting it here).
Your code, on the other hand, will take much, much longer to find a solution. First of all, there is absolutely no point in generating random inputs. Sequential values will work just as well, and will be much faster to generate.
If you use sequential input values, then you also won't need to worry about repeating the same hash calculations. Your code uses a list structure to store previously hashed values. This is a terrible idea. Searching for an item in a list is an O(n) operation, so once your code has (unsuccessfully) tested a billion inputs, it will have to compare every new input against each of these billion inputs at each iteration, causing your code to grind to a complete standstill. Your code would actually run a lot faster if you didn't bother checking for duplicates. When you have time, I suggest you learn when to use lists, dicts and sets in Python.
Another problem is that your code only tests 10-digit numbers, which means it can only test a maximum of 10 billion possible inputs. Based on the numbers given above, are you sure this is a sensible limit?
Finally, your code is printing every single input string before you calculate its hash. Before your program outputs a solution, you can expect it to print out somewhere in the order of a billion screenfuls of incorrect guesses. Is there any point in doing this? No.
Here's the code I used to find the MD5 collision I mentioned earlier. You can easily adapt it to work with RIPEMD160, and you can convert it to Python if you like (although the PHP code is much simpler):
$n = 0;
while (1) {
$s = "0e$n";
$h = md5($s);
if ($s == $h) break;
$n++;
}
echo "$s : $h\n";
Note: Use PHP's hash_equals() function and strict comparison operators to avoid this sort of vulnerability in your own code.
I want to convert byte array to UINT64 using PHP.
I can do this easily in C# but I want to do this in PHP.
Here is C# code.
bytes = Encoding.UTF8.GetBytes(hashed);
BitConverter.ToUInt64(bytes, 0);
I want to convert this to PHP.
I tried to use pack() function but this does not works.
Let's say this is a byte array.
$bytes = [101,102,54,55,99,55,56,49];
pack("J*","101","102","54","55","99","55","56","49");
This shows a warning.
epack(): 7 arguments unused on line
How can I fix this?
The major issue here (if I understand it correctly) is you're using PHP numbers to represent a byte array however unpack requires an input string. If you keep the array as is then PHP seems to just convert the numbers to strings meaning a 101 will be '101' which in turn is 3 bytes, which breaks the whole thing down.
You need to first convert the numbers to bytes. A byte is essentially as an unsigned char so you could first pack your array into unsigned chars and then unpack them:
$bytes = [101,102,54,55,99,55,56,49];
$unpacked = unpack("J", pack('C*', ...$bytes));
echo current($unpacked);
Explanation:
C is the pack code for unsigned char and * indicates that you need to use all array entries. This will generate a string of characters based on the array. You can then unpack this string using J (if you know for a fact that the bytes were generated in a big endian byte order) or P if you know the bytes were generated in little endian order or Q if you want to use the machine order. If the bytes were generated in the same machine then Q would probably be a better choice than J otherwise you need to know the endianess.
Example: http://sandbox.onlinephpfunctions.com/code/5cba2c29522f7b9f9a0748b99fac768012e759ce
Note: This is my personal understanding of what is happening so anyone with better pack/unpack knowledge can let me know if I got things wrong.
Today I just made an interesting discovery while testing what happens calculating bitwisely in php like INF ^ 0 (^ => Bitwise Operator for Exclusive OR (XOR)) what gave me int(-9223372036854775808) => greatest possible negative value in a 64-Bit system.
But then I was asking myself: "Why is the result going negative in XOR when the "positive infinit" means 9223372036854775807 (63 Bits on 1 with a leading 0) and 0 (64 Bits on 0 => 0 xor 0 = 0) What is PHP's infinit value though and what is the calculation behind it? And why do I get a (correct?) negative value when I use "negative infinit"(A leading 1 against a leading 0 on 0 => 1 xor 0 = 1?".
Another interesting point is that this just happens on PHP Version 5.5.9-1, and not e.g. on 5.3.x. and 5.6.x (where i've tested it)! Maybe someone has an idea what happens there? Tested it on three versions but just mine (5.5.9-1) gives those results:
Just to let you guys know, it's just an abstract playaround i've done for fun but I find it's interesting. Maybe someone can help here or explain me a wrong thought I have? Just tell me if someone needs more informations about anything!
EDIT: Accordingly to jbafford it would be great to get a complete answere, so i'll just quote him: why does 5.5 and 5.6 result in PHP_INT_MIN, and everything else return 0?
First off, ^ itself isn't what's special here. If you XOR anything with zero, or OR anything with zero, you just get back the original answer. What you're seeing here is not part of the operation itself, but rather what happens before the operation: the bitwise operators take integers, so PHP converts the float to an integer. It's in the float-to-integer conversion that the weird behaviour appears, and it's not exclusive to the bitwise operators. It also happens for (int), for example.
Why does it produce these weird results? Simply because that's what the C code PHP is written in produces when converting a float to an integer. In the C standard, C's behaviour for float-to-integer conversions is undefined for the special values of INF, -INF and NAN (or, more accurately, for "integral parts" an integer can't represent: §6.3.1.4). This undefined behaviour means the compiler is free to do whatever it wants. It just so happens in this case that the code it generates produces the minimum integer value here, but there's no guarantee that will always happen, and it's not consistent across platforms or compilers.1 Why did the behaviour change between 5.4 and 5.5? Because PHP's code for converting floats to integers changed to always perform a modulo conversion. This fixed the undefined behaviour for very large floating-point numbers,2 but it still didn't check for special values, so for that case it still produced undefined behaviour, just slightly different this time.
In PHP 7, I decided to clean up this part of PHP's behaviour with the Integer Semantics RFC, which makes PHP check for the special values (INF, -INF and NAN) and convert them consistently: they always convert to integer 0. There's no longer undefined behaviour at work here.
1 For example, a test program I wrote in C to try to convert Infinity to an integer (specifically a C long) has different results on 32-bit and 64-bit builds. The 64-bit build always produces -9223372036854775808, the minimum integer value, while the 32-bit build always produces 0. This behaviour is the same for GCC and clang, so I guess they're both producing very similar machine code.
2 If you tried to convert a float to an integer, and that float's value was too big to fit in an integer (e.g. PHP_INT_MAX * 2, or PHP_INT_MIN * 2), the result was undefined. PHP 5.5 makes the result consistent, though unintuitive (it acts if the float was converted to a very large integer, and the most significant bits were discarded).
Your float(INF) gets implicitly casted to an Integer.
and XOR with 0 does not change the first parameter. So basically this is just a cast from float to int which is undefined for values which are not in the integer range. (for all other values it will be truncated towards zero)
https://3v4l.org/52bA5
I am tasked with converting some Fortran code to PHP and am stumbling at the last hurdle.
In essence the Fortran converts a REAL into a binary CHAR(4) which it ultimately writes to file.
The Fortran (which also confuses me) is as follows:
FUNCTION MKS(x)
CHARACTER (LEN=4) :: MKS ! The 4-character string which is returned to
REAL :: x ! The incoming single-precision variable
CHARACTER (LEN=1), DIMENSION(4) :: a ! A working variable
CHARACTER (LEN=4) :: d ! A working variable
CALL MKS1(x,a) ! Send x - get back a(1), a(2), a(3), a(4)
! Note: x will hold the first 32 bits referenced
! and a will hold the next 32 bits
d = a(1) // a(2) // a(3) // a(4) ! concatenate into 1 string (d)
MKS = d ! assign string to variable MKS
END FUNCTION MKS
SUBROUTINE MKS1 (b,c)
IMPLICIT NONE
CHARACTER (LEN=1), DIMENSION(4) :: b ! array with incoming 32 bits
CHARACTER (LEN=1), DIMENSION(4) :: c ! array with each character returned
INTEGER :: i ! DO Loop counter
DO i=1,4
c(i) = b(i)
END DO
END SUBROUTINE MKS1
I have attempted to recreate this function using php as follows
pack('CCCC', $value & 0x000F,
($value>>8) & 0x000F,
($value>>16) & 0x000F,
($value>>24) &0x000F);
But on comparing the output values using the *nix od command shows completely different results.
What is the correct way to pack the equivalent to a Fortran REAL into a char[4] Array in PHP?
It turned out to be quite simple.
Your FORTAN REAL is stored as an IEEE 754 32 bit floating point number.
The output from your od was misleading. Converting it to hex gives the following.
0115040 0134631 0005077
0x20, 0x9A, 0x99, 0xB9, 0x3f, 0x0a
The first and last bytes of the file are redundant, they are a space and a carriage return respectively. The bit we're after is the middle 4 bytes.
Using pack we can convert from floats (warning - endianness is machine dependant).
The following:
var_dump(bin2hex(pack('f', 1.450)));
Gives us a familar sequence of bytes.
string(8) "9a99b93f"
So instead of converting to hex, output that to a file with a space at the start and a carriage return at the end, and you'll have an identical file. (as long as your PHP/machine configuration doesn't do something mad with floats - but even then if you follow the IEEE 754 spec, you should be able to reproduce it)
This might be an extended comment rather than an answer.
You are, in the statement
CALL MKS1(x,a)
passing a REAL argument where the subroutine expects an array of 4 length-1 characters. You deserve all the bad things which happen to you :-) You can only compile this because you haven't required explicit interfaces on your subroutines.
What do you want the 4 characters that your PHP program reads to be ? If, for instance, your Fortran wrote the REAL into 4 bytes in a binary file and your PHP read 4-bytes as 4 single characters would you get the characters you want ? I'm uncertain of what your requirement is.
the topic pretty much describes what we would like to accomplish.
a) start with a possible range of integers, for example, 1 to 10000.
b) take any md5 hash, run it thru this algo.
c) result that pops out will be an integer between 1 to 10000.
we are open to using another hashing method too.
the flow would ideally look like this:
string -> md5(string) -> algo(md5(string),range) -> resulting integer within range
is something like this possible?
final note: the range will always start with 1.
if you have an answer, feel free to post just the general idea, or if you so desire, php snippet works too :)
thanks!
Since MD5 (and SHA-1, etc.) will give you 128 bits of data (in PHP, you'll get it in hexadecimal string notation, so you need to convert it to an integer first). That number modulo 10000 will give you your integer.
Note however that many different hashes will convert to the same integer; this is unavoidable with any sort of conversion to your integer range, as the modulo operation essentially maps a larger set of numbers (in this case, 128 bits, that is numbers from 0 to 340,282,366,920,938,463,463,374,607,431,768,211,456) to a smaller set of numbers (less than 17 bits, numbers from 1 to 100,000).
since the range that we want will always start at 1, the following works great. all credit goes to Piskvor, as he was the one who provided the basic idea of how to go at this.
the code below seams to accomplish what we want. please chime in if this can be (not the code, its just for reference, but if the idea) improved at all. running the code below will result in 6305 / 10000 unique results. that in our case is good enough.
<?
$final=array();
$range=10000;
for($i=1;$i<=$range;$i++){
$string='this is my test string - attempt #'.$i;
echo 'initial string: '.$string.PHP_EOL;
$crc32=crc32($string);
echo 'crc32 of string: '.$crc32.PHP_EOL;
$postalgo=$crc32%$range;
echo 'post algo: '.$postalgo.PHP_EOL;
if(!in_array($postalgo,$final)){
$final[]=$postalgo;
}
}
echo 'unique results for '.($i-1).' attempts: '.count($final).PHP_EOL;
?>
enjoy!