Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong HMAC using PHP 5.0.4 #1034

Closed
romucifu opened this issue Sep 13, 2016 · 13 comments
Closed

Wrong HMAC using PHP 5.0.4 #1034

romucifu opened this issue Sep 13, 2016 · 13 comments
Labels

Comments

@romucifu
Copy link

romucifu commented Sep 13, 2016

I'm trying to enable HMAC Hashing (SHA256) with PHP 5.0.4 and using phpseclib 1.0.3 (to my knowledge in this case phpseclib relies on a native PHP spec), the sample code I'm using it's pretty simple:

    include('Crypt/Hash.php');
    define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL);

    $hash = new Crypt_Hash('sha256');
    $hash->setKey('abcdefg');
    echo bin2hex($hash->hash('something'));

it generates an HMAC with this string:

e678e33c727ddf7172d3521cf9c0c2a15b66e03eb96d77795fa4adb338dc24a9

But apparently, this string is invalid because doing the same with this online tools:

http://www.freeformatter.com/hmac-generator.html
http://beautifytools.com/hmac-generator.php
http://www.jetcityorange.com/hmac/

I get this string:

9a43ff294bdfed399e2d5a3d739a4efb7eccc23269b80b3f0d855937d35ae06f

What am I doing wrong?

Note: SHA1 encoding works perfectly.
Thanks in advance.

@terrafrost
Copy link
Member

I think you posted about this on stackoverflow: http://stackoverflow.com/questions/39275323/wrong-hmac-using-php-5-0-4

Anyway, I'm not able to reproduce the problem on Windows on 5.0.4 or 5.0.5 (the latest version of 5.0 on http://museum.php.net/php5/). I tried it using mhash and internal mode.

Can you post your phpinfo()?

@romucifu
Copy link
Author

Yes, I've posted this on "stackoverflow.com" too.
The library is using "internal mode".

I've attached the "phpinfo" data of the server (RedHat Linux with PHP 5.0.4).

Thanks.
phpinfo_504.txt

@romucifu
Copy link
Author

I'm using phpseclib 1.0.3

@romucifu
Copy link
Author

More info...

This problem also affects another host with PHP 5.0.4 32-bit Linux OS.

I've first spotted the problem in the "_rightRotate" function of the "Crypt_Hash" class:

function _rightRotate($int, $amt)
    {
        $invamt = 32 - $amt;
        $mask = (1 << $invamt) - 1;
        return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask);
    }

In the fist call of the "_sha256" function "main loop":

 // Main loop
            for ($i = 0; $i < 64; $i++) {
                $s0 = $this->_rightRotate($a,  2) ^ ...

Enters the function with the values "1779033703" for "$int" and "2" for "$amt", but the result is different in 32-bit or 64-bit machines.

Result in 32-bit machines: -628983399
Result in 64-bit machines: 3665983897

I don't know if you could replicate this.

@bantu
Copy link
Member

bantu commented Sep 28, 2016

@romucifu As I tried to explain in the other ticket, this is not necessarily an indicator for a bug. Try using printf('%X', $a); for printing those integers. It should yield DA827999 on both platforms.

@romucifu
Copy link
Author

@bantu Thanks bantu! Sorry for the misunderstanding. Clearly this issue is beyond my understanding, I really can't understand why "echo" shows different values.

@romucifu
Copy link
Author

romucifu commented Sep 28, 2016

In the php documentation for integers:

"Integer overflow: If PHP encounters a number beyond the bounds of the integer type, it will be interpreted as a float instead. Also, an operation which results in a number beyond the bounds of the integer type will return a float instead."

It is possible that when converting this values to float the subsequent bitwise operations doesn't work correctly?

Also a note from the changelog of PHP 5.3.0:
"Changed floating point behaviour to consistently use double precision on all platforms and with all compilers. (Christian Seiler)"

And an interesting post from stackoverflow.com:
http://stackoverflow.com/questions/11402469/bitwise-operations-on-big-integers-in-php-5-2-and-php-5-3

@romucifu
Copy link
Author

romucifu commented Sep 29, 2016

It's a weird issue because at least in our server farm the problem affects only 32-bit Linux systems.

I'm able to reproduce the problem on three servers, two 32-Bit Linux OS with PHP 5.0.4 and one 32-Bit Linux OS with PHP 5.2.9.

The rest of my servers: four 64-Bit Linux OS with PHP 5.3.3, two 64-Bit Linux OS with PHP 7.0 and EVEN one 64-Bit Linux OS with PHP 5.2.9 don't exhibit the problem.

But terrafrost tested the issue with 32-bit versions (I assume all windows versions of PHP prior to 7.0 are 32-bit versions) of PHP 5.0.4 & 5.0.5 without problems.

So... could it be a problem related only to LINUX based 32-Bit systems (or just some distributions) and the reason they changed this in PHP 5.3.0?
"Changed floating point behaviour to consistently use double precision on all platforms and with all compilers. (Christian Seiler)"

Excerpt related to this update:

"Basically, on x86 systems without SSE FP arithmetics don't really use IEEE 754 double arithmetic by default but rather a double-extended type for internal calculations - which leads to problems since FP behaviour is not reproducible on different platforms - compare to for example x86 with SSE or x86_64 where SSE is nearly always used, or PPC etc. - there you get real IEEE 754 double arithmetic. The makes sure PHP changes the internal FPU precision of x86 to IEEE 754 double precision in order to get the same results for FP calculations on all platforms."

@romucifu
Copy link
Author

To answer myself, all of my affected systems have SSE FP arithmetics, so seems like this change in PHP 5.3.0 is not the root of the problem.

32-bit PHP 5.2.9 Linux OS:
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 15
model name : Intel(R) Core(TM)2 CPU 4300 @ 1.80GHz
stepping : 2
cpu MHz : 1795.631
cache size : 2048 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 2
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 10
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx lm constant_tsc pni monitor ds_cpl est tm2 cx16 xtpr lahf_lm
bogomips : 3593.14

32-bit PHP 5.0.4 Linux OS:
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 15
model name : Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz
stepping : 2
cpu MHz : 2493.708
cache size : 0 KB
physical id : 0
siblings : 2
runqueue : 0
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 15
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts mmx fxsr sse sse2 ss ht nx lm
bogomips : 4980.73

@romucifu
Copy link
Author

I've edited the original post just to note that I'm using CRYPT_HASH_MODE_INTERNAL to reproduce the problem.

@bantu bantu added the bug label Sep 29, 2016
@terrafrost
Copy link
Member

I think https://github.com/terrafrost/phpseclib/tree/1.0-32bit-fixes should fix the issue for you. LMK!

@romucifu
Copy link
Author

romucifu commented Oct 6, 2016

@terrafrost YES! it works! now I have the same result on all of my hosts 32 or 64 Bit and with any PHP version. Awesome job.

Thanks!

@terrafrost
Copy link
Member

Glad to hear it! The fix has been merged into 1.0 / 2.0 / master.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants