Alphanumeric (sha1) Semaphore in PHP? - php

PHP's "shm_get" function requires an integer semaphore key, which I realise to be a restriction of the underlying OS.
I am using the "sha1" function to hash some user input and using the hash to uniquely identify a number of resulting files and and background processes.
Is there a way to convince shm_get to accept an alphanumeric key or to convert a sha1 hash to an acceptable integer?

You can convert a hexadecimal number into a decimal number by using hexdec()
However if you have got a large number in your hash, this won't return an integer. But you need an integer. So you might want to cut it apart and only use a part of the hash.
$hash = sha1('http://www.hashcat.net/');
$hash = substr($hash, 0, 15); // ok on 64bit systems
$number = (int) hexdec($hash); // cap to PHP_INT_MAX anyway
var_dump($hash, $number);

Related

How can I create a random number from a SHA256 Hash?

Good morning,
I have to create a random number from a given 256HASH using a secret key. Everyting is fine, until I have to "convert" the hash into an integer between 0 and 15.000.000 (which is the random number). I have been playing with ord() and bytes but I don't get anything that suits me.
My original idea was to cast the SHA256 string into an integer, and then apply a divisor to obtain the modulus. But I need a random number between a very big range. 0 to 15.000.000 (fifteen million). How would you do it?
Thanks!
A hash i basically a number, just with a base of 16. Having said that, you just have to convert it to an int.
The problem is, when you convert a hash into a int like so:
echo intval(hash('sha256','asdf'),16);
You will always get 2147483647 for 32-bit systems, which is the maximum value for intval.
My suggestion would be to cut the value of the hash to a few first characters like so
echo intval(substr(hash('sha256','bsbaf'),0,6),16);
This is now the seed for the random number, you can get the random by:
$hash = hash('sha256','bsbaf');
$seed = intval(substr($hash,0,6),16);
mt_srand($seed);
echo mt_rand(0,15000000);
Note that in some cases, you can have collisions, because you are using only the first 6 chars of the hash, but for most uses this will not be a problem. It's up to you to decide if this is acceptable since I do not know your specific use case.
UPDATE: An alternative is to make modulo from the resulting seed - like so:
$hash = hash('sha256','bsbaf');
$seed = intval(substr($hash,0,6),16);
echo $seed % 15000000;

php using mcrypt_create_iv

I want to create a random ints and strings in PHP and so I decided to use mcrypt_create_iv. It is written in manual that it uses /dev/random and /dev/urandom for randomness but I can't find a simple tutorial on how to generate random Int and String using this function. I tried some code but this function gives me unreadable characters. So please can you give me a simple example of how properly I can use it?
Firstly, how do you want to use the random strings, what do you want to use them for? If it is for generating salts for passwords you can use this function to generate better random strings than those generated by uniqid() or mt_rand(). See Secure Password Hashing and see code below on how to generate a random string using mcrypt_create_iv()). If you want the strings for user identification why not try out UUID instead.
The use of mcrypt_create_iv on its own will simply generate unreadable characters. To "convert" those unreadable characters to something readable use the bin2hex function like this:
$random_string = bin2hex(mcrypt_create_iv(30, [MCRYPT_DEV_RANDOM|MCRYPT_DEV_URANDOM|MCRYPT_RAND]));
The "30" is the size of the initialization vector that you want to get. Remember, using MCRYPT_DEV_URANDOM and MCRYPT_DEV_RANDOM on Windows machines with PHP versions older than the 5.3.0 release will not work. Use MCRYPT_RAND instead for such cases.
If you want to generate random numbers, use mt_rand:
$random = mt_rand(0, 999999);
If you want a string, you can pass the resulting integer through a hash function:
$random = mt_rand(0, 999999);
$random_string = sha1($random);
mcrypt_create_iv is used in cryptography. It is totally unrelated to your requirement.
If you're looking to use the random string in security components (salts, passwords, etc.), read from /dev/urandom like so:
$random = file_get_contents('/dev/urandom', false, null, 0, 10);
...where 10 is the length, then convert like this:
$string = bin2hex($random);
$number = current(unpack('L', $random));
rand ( int $min , int $max ) use this for random numbers and for strings take a md5 or sha1 hash of the random number;

Generate random string from 4 to 8 characters in PHP

I need to generate a string using PHP, it need to be unique and need to be from 4 to 8 characters (the value of a variable).
I thought I can use crc32 hash but I can't decide how many characters, but sure it will be unique. In the other hand only create a "password generator" will generate duplicated string and checking the value in the table for each string will take a while.
How can I do that?
Thanks!
Maybe I can use that :
function unique_id(){
$better_token = md5(uniqid(rand(), true));
$unique_code = substr($better_token, 16);
$uniqueid = $unique_code;
return $uniqueid;
}
$id = unique_id();
Changing to :
function unique_id($l = 8){
$better_token = md5(uniqid(rand(), true));
$rem = strlen($better_token)-$l;
$unique_code = substr($better_token, 0, -$rem);
$uniqueid = $unique_code;
return $uniqueid;
}
echo unique_id(4);
Do you think I'll get unique string each time for a goood while?
In short, I think you'll get a pretty good random value. There's always the chance of a collision but you've done everything you can to get a random value. uniqid() returns a random value based on the current time in microseconds. Specifying rand() (mt_rand() would be better) and the second argument as true to uniqid() should make the value even more unique. Hashing the value using md5() should also make it pretty unique as even a small difference in two random values generated should be magnified by the hashing function. idealmachine is correct in that a longer value is less likely to have a collision than a shorter one.
Your function could also be shorter since md5() will always return a 32 character long string. Try this:
function unique_id($l = 8) {
return substr(md5(uniqid(mt_rand(), true)), 0, $l);
}
The problem with randomness is that you can never be sure of anything. There is a small chance you could get one number this time and the same number the next. That said, you would want to make the string as long as possible to reduce that probability. As an example of how long such numbers can be, GUIDs (globally unique identifiers) are 16 bytes long.
In theory, four hex characters (16 bits) give only 16^4 = 65536 possibilities, while eight hex characters (32 bits) give 16^8 = 4294967296. You, however, need to consider how likely it is for any two hashes to collide (the "birthday problem"). Wikipedia has a good table on how likely such a collision is. In short, four hex characters are definitely not sufficient, and eight might not be.
You may want to consider using Base64 encoding rather than hex digits; that way, you can fit 48 bits in rather than just 32 bits.
Eight bytes is 8 * 8 = 64 bits.
Reliable passwords You can only make from ascii characters a-zA-Z and numbers 0-9. To do that best way is using only cryptographically secure methods, like random_int() or random_bytes() from PHP7. Rest functions as base64_encode() You can use only as support functions to make reliability of string and change it to ASCII characters.
mt_rand() is not secure and is very old.
From any string You must use random_int(). From binary string You should use base64_encode() to make binary string reliable or bin2hex, but then You will cut byte only to 16 positions (values).
See my implementation of this functions.

Convert MD5 to base62 for URL

I have a script to convert to base 62 (A-Za-z0-9) but how do I get a number out of MD5?
I have read in many places that because the number from an MD5 is bigger than php can handle as an integer it will be inaccurate... As I want a short URL anyway and was not planning on using the whole hash, maybe just 8 characters of it....
So my question is how to get part of the number of an MD5 hash?
Also is it a bad idea to use only part of the MD5 hash?
I'm going to suggest a different thing here.. Since you are only interested in using a decimal chunk of the md5 hash why don't you use any other short numeric hash like CRC32 or Adler? Here is an example:
$hash = sprintf('%u', crc32('your string here'));
This will produce a 8 digit hash of your string.
EDIT: I think I misunderstood you, here are some functions that provide conversions to and from bases up to 62.
EDIT (Again): To work with arbitrary length numbers you must use either the bc_math or the GMP extension, here is a function that uses the bc_math extension and can also convert from base 2 up to base 62. You should use it like this:
echo bc_base_convert(md5('your url here'), 16, 62); // public base 62 hash
and the inverse:
echo bc_base_convert('base 62 encoded value here', 62, 16); // private md5 hash
Hope it helps. =)
If it's possible, I'd advise not using a hash for your URLs. Eventually you'll run into collisions... especially if you're truncating the hash. If you go ahead and implement an id-based system where each item has a unique ID, there will be far fewer headaches. The first item will be 1, the second'll be 2, etc---if you're using MySQL, just throw in an autoincrement column.
To make a short id:
//the basic example
$sid = base_convert($id, 10, 36);
//if you're going to be needing 64 bit numbers converted
//on a 32 bit machine, use this instead
$sid = gmp_strval(gmp_init($id, 10), 36);
To make a short id back into the base-10 id:
//the basic example
$id = base_convert($id, 36, 10);
//if you're going to be needing 64 bit numbers
//on a 32 bit machine, use this instead
$id = gmp_strval(gmp_init($shortid, 36));
Hope this helps!
If you're truly wanting base 62 (which can't be done with gmp or base_convert), check this out:
http://snipplr.com/view/22246/base62-encode--decode/
You can do this like this: (Not all steps are in php, it's been a long time that I've used it.)
Create a md5 hash of the script like this:
$hash = md5(script, raw_output=true);
Convert that number to base 62.
See the questions about base conversion of arbitrary sized numbers in PHP
Truncate the string to a length you like.
There's no risk in using only a few of the bits of a md5. All that changes is danger of collisions.
There actually is a Java implementation which you could probably extract. It's an open-source CMS solution called Pulse.
Look here for the code of toBase62() and fromBase62().
http://pulse.torweg.org/javadoc/src-html/org/torweg/pulse/util/StringUtils.java.html
The only dependency in StringUtils is the LifeCycle-class which provides a way to get a salted hash for a string which you might even omit all together or just copy the method over to your copy StringUtils. Voilá.
You can do something like this,
$hash = md5("The data to be hashed", true);
$ints = unpack("L*num", $hash);
$hash_str = base62($ints['num1']) . base62($ints['num2']) . base62($ints['num3']) . base62($ints['num4'])
As of PHP 5.3.2, GMP supports bases up to 62 (was previously only 36), so brianreavis's suggestion was very close. I think the simplest answer to your question is thus:
function base62hash($source, $chars = 22) {
return substr(gmp_strval(gmp_init(md5($source), 16), 62), 0, $chars);
}
Converting from base-16 to base-62 obviously has space benefits. A normal 128-bit MD5 hash is 32 chars in hex, but in base-62 it's only 22. If you're storing the hashes in a database, you can convert them to raw binary and save even more space (16 bytes for an MD5).
Since the resulting hash is just a string representation, you can just use substr if you only want a bit of it (as the function does).
You may try base62x to get a safe and compatible encoded representation.
Here is for more information about base62x, or simply -base62x in -NatureDNS.
shell> ./base62x -n 16 -enc 16AF
1Ql
shell> ./base62x -n 16 -dec 1Ql
16AF
shell> ./base62x
Usage: ./base62x [-v] [-n <2|8|10|16|32>] <-enc|dec> string
Version: 0.60
Here is an open-source Java library that converts MD5 strings to Base62 strings
https://github.com/inder123/base62
Md5ToBase62.toBase62("9e107d9d372bb6826bd81d3542a419d6") ==> cbIKGiMVkLFTeenAa5kgO4
Md5ToBase62.fromBase62("4KfZYA1udiGCjCEFC0l") ==> 0000bdd3bb56865852a632deadbc62fc
The conversion is two-way, so you will get the original md5 back if you convert it back to md5:
Md5ToBase62.fromBase62(Md5ToBase62.toBase62("9e107d9d372bb6826bd81d3542a419d6")) ==> 9e107d9d372bb6826bd81d3542a419d6
Md5ToBase62.toBase62(Md5ToBase62.fromBase62("cbIKGiMVkLFTeenAa5kgO4")) . ==> cbIKGiMVkLFTeenAa5kgO4
```
You could use a slightly modified Base 64 with - and _ instead of + and /:
function base64_url_encode($str) {
return strtr(base64_encode($str), array('+'=>'-', '/'=>'_'));
}
function base64_url_decode($str) {
return base64_decode(strtr($str, array('-'=>'+', '_'=>'/')));
}
Additionally you could remove the trailing padding = characters.
And to get the raw MD5 value (binary string), set the second parameter (named $raw_output in the manual) to true:
$raw_md5 = md5($str, true);

Good numeric hashes

I'm looking to hash a string but I need the output to be an integer so I can't do md5. Do people here have any favorite numeric hashes that they might want to enlighten me with. I'm using PHP.
Thanks!
The output of MD5 is a number, just as with pretty much every imaginable hash. It's just a number that's usually expressed in hex. Use any hash algorithm that's conveniently available to you, chop as many bits as you want off of the end, and treat those bits as a number. Any good hash will have its last (or first, or middle) n bits just as evenly distributed as the whole value.
Maybe this is good enough for you:
echo sprintf('%u', crc32($string));
EDIT: Other similar alternative,
echo hash('adler32', $string);
I think there are some good hashing and PHP specific questions already on Stackoverflow.
Try a hashing+php search here.
A short list,
How do I create a unix password hash with php
Need a simple hash in PHP
Best hashing algorithm in terms of hash collisions and performance
and php hash form string to integer, php short hash
You can use base_convert to change hexadecimal into decimal number and vice versa. If you want to convert integers (as a string) to hex you are limited to 32 bit numbers or less I belive (PHP_INT_MAX).
php -r 'foreach (hash_algos() as $hash) { echo $hash, "\n", $a = hash($hash, "test"), "\n", $b = base_convert($a, 16, 10), "\n", $c = base_convert($b, 10, 16), "\n", ($c === $a ? "yes" : "no"), "\n\n"; }' > hashes.txt
Of the available hashes I had, these are the ones I could convert between decimal and hex:
adler32
c1015d04
3238092036
c1015d04
yes
crc32
accf8b33
2899282739
accf8b33
yes
crc32b
d87f7e0c
3632233996
d87f7e0c
yes

Categories