1

What is the difference between this implementation of auth key generator in PHP:

<?php
$password = "834ff7b651a6cb1b2f39c70bf43d3e78";
$timestamp = round(microtime(true) * 1000);
$hash = md5($password.$timestamp);
echo "\n Timestamp: ".$timestamp;
echo "\n Hash: ".$hash."\n";
?>

and this one in python:

import hashlib
import time
import ipdb
import math
def microtime(get_as_float = False) :
    if get_as_float:
        return time.time()
    else:
        return '%f %d' % math.modf(time.time())

password = "834ff7b651a6cb1b2f39c70bf43d3e78"
timestamp = round(microtime(get_as_float=True)*1000)
m = hashlib.md5()
m.update(password + str(timestamp))
hash = m.hexdigest()
print(str(int(timestamp)))
print(hash)

If the timestamp generation works in PHP in another way than my implementation in Python?

Because I check it during the auth on the service which uses this timestamp in pair with hash calculated from password and timestamp concatenated together and in case with PHP I can pass, but in case with Python I cannot.

Thanks!

Павел Иванов
  • 1,863
  • 5
  • 28
  • 51
  • Are you running the python code on linux/unix? Otherwise [`time`](https://docs.python.org/3/library/time.html) will not be a unix timestamp value. Why are you running `int(timestamp)` in python? It would cut off any digits < 1. Relevant e.g. for 0.8 which would be 0 or 1 whenever you use `int` or `round`. – Seth Mar 16 '17 at 07:55
  • 1
    @HankyPanky `time` just gives you seconds while `microtime` gives you a higher resolution? – poke Mar 16 '17 at 08:21
  • I don't know what you mean by "password" here, but [don't hash user's password](http://stackoverflow.com/questions/401656/secure-hash-and-salt-for-php-passwords) (In fact, don't use md5 at all unless it is for backward-compatibility. [PHP](http://php.net/manual/en/function.hash.php) and [Python](https://docs.python.org/2/library/hashlib.html) both support SHA-2.) – kennytm Mar 16 '17 at 08:27
  • @HankyPanky Maybe you want to read what you just wrote again? `microtime(true)` gives you something like `1489680955.2224`. Multiplied by 1000 and rounded, this makes perfect sense. (It’s being multiplicated, not divided) – poke Mar 16 '17 at 08:32
  • @kennytm You might want to change that link title because *“don’t hash user’s password”* seems like a very bad suggestion when you indeed should use a cryptographically secure hash function for storing a user’s password. (It’s just that md5 shouldn’t be used for that purpose anymore; but there are other use cases where md5 is fine—and OP’s use case could be one of those, we don’t know) – poke Mar 16 '17 at 08:33
  • Yep true, my bad. Thanks – Hanky Panky Mar 16 '17 at 08:34
  • @poke (Can't edit a comment after 5 minutes) OK you should `pbkdf2`/`scrypt`/`argon2` user's password. (Those are key-derivation functions, not cryptographic hash functions. SHA-3/BLAKE2b are cryptographically secure hash functions but it is completely wrong to use SHA-3/BLAKE2b to hash and store the password) – kennytm Mar 16 '17 at 08:39

1 Answers1

0

If you are using Python 2, note that round() returns a floating point value. When you str() it, it will be formatted like a float:

>>> str(round(time.time() * 1000))
'1.48965165075e+12'

(Python will start to print numbers in scientific notation when the value is ≥ 1011 (year 1973), but even if it is < 1011 there will be an extra .0 at the end. PHP will print in scientific notation when ≥ 1014 (year 5138).)

Consider explicitly format instead:

m.update(password)
m.update('%.0f' % timestamp)

Since you wrote print(str(int(timestamp))) probably it is just an oversight? You could also use str(int(timestamp)) here

m.update(password)
m.update(str(int(timestamp)))

but in Python 2 if timestamp is ≥ 262 (year 292278994) there will be an extra L at the end.

kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005