PHP What is this kind of key called? Similar to UUID - php

In a web application I'm working on, i need to generate unique id's with an excessive length. Longer than typical UUID's. Another similar web app uses keys that look like this:
cb745abbc635c03f0c259b65y5da57c06e12ef51
What are these called? and how can i create unique ones in PHP? I've tried the UID method, however they are kinda short.

The example you posted is a 40 character hex string, which therefore looks suspiciously like a SHA1 hash. PHP's built-in sha1() function will hash an input string into just such a hash.
If you pass microtime(true) (to get the current time with microseconds as a float) as input, you'll get a value unique in time. Concatenate it with a hostname for a 40 character globally unique value.
echo sha1(microtime(true) . $hostname));
Note that while this type of value is probably satisfactory as a unique identifier for a database object, user ID, etc, it should not be considered cryptographically secure, as its sequence could be easily guessed.

This might be a hash generated from sha1 which is widely used:
From the PHP documentation:
If the optional raw_output is set to TRUE, then the sha1 digest is instead returned in raw binary format with a length of 20, otherwise the returned value is a 40-character hexadecimal number.
echo (sha1("whatever"));
Note that is not certain since it exists multiple other hashing algorithms that will give you a 40 characters length:
echo (hash("ripemd160", "whatever"));
echo (hash("tiger160,3", "whatever"));
echo (hash("tiger160,4", "whatever"));
echo (hash("haval160,3", "whatever"));
echo (hash("haval160,4", "whatever"));
echo (hash("haval160,5", "whatever"));

Related

PHP hashing method, same output every time

So if I do something like sha1($data) the result will be BLAHBLAH123. However if I do it again it will be BLAHAHS316. The same thing happens with md5. So my question is, what is a consistent way to hash values?
So like function($data) will return BLAHBLAHBLAH123 each time it is evaluated with the same $data parameter.
EDIT: I have a specific purpose in mind for this that isn't passwords so security isn't a concern.
EDIT: For example, md5($data) will not return BLAHBLAH every time, sometimes it'll return BLAHHHAL. I don't want that. I want it to return the same thing, BLAHBLAH everytime!
The output of a hashing operation will only change if the input has changed.
For example:
echo sha1( 'test' );
a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
If you wish it to change everytime, you could append a timestamp to the input:
echo sha1( 'test'.time() )
3d68b7693768f199623f31f820b1ba29b0a58769
Hashing function are deterministic (they would be useless if this was not the case).
In computer science, a deterministic algorithm is an algorithm which, given a particular input, will always produce the same output, with the underlying machine always passing through the same sequence of states.
Consider another (eg. time) input to the domain as in sha1(microtime() . $data) if you want 'different output'. I'm not sure how useful this will be in practice.
Password hash functions use a salt (randomly generated, stored separately) as additional input so the same plain-text password will result in a different stored hash value.
Hashing method - to give the same value, but not easy to predict or decode is what i think you are looking for.
You can use use a constant string val and do a hash of that string to get the same value always, if you want to change the value you can change the constant and get a different hash value
$constStr = "hashThis";
$hashWord = md5($constStr);
// it will return the same value always, as long as the constStr is the same
Two different input with same md5 or sha1 output?
That's possible but way to hard. Take a look at here: https://crypto.stackexchange.com/questions/1434/are-there-two-known-strings-which-have-the-same-md5-hash-value
The return value will change as long as your $data variable changes, you can't get same hashing value from different strings

What is the password parameter to openssl_encrypt?

The PHP documentation for the openssl_encrypt functions states
string openssl_encrypt ( string $data , string $method , string
$password [, int $options = 0 [, string $iv = "" ]] )
Can somebody help me understand what the argument named $password is?
An answer could include a confirmation or rejection of the idea, that besides named $password the parameter indeed is used as the key for the encryption.
What is the password parameter to openssl_encrypt? Is it a password string (with only printable characters) or is it a key (with non-prinatable characters and ASCII-Z terminators)?
Explanation
I am stuck with the documention of PHP's openssl_encrypt. Being a nice guy and trying to do the "RTM" I cannot make much sense with the imho unsatisfying documentation.
The problem is that for me there is a difference between a password and a key when it comes to encryption. A key is directly the parameter used for encryption and hence necessarily of a specific size - "the keylength" - i.e. 128/256/512 bits depending on the cipher and keylength desired. A password on the other hand is a to my understanding a human readable string entered via the keyboard which may in difference be of any length and which is before being used to encrypt first converted into a key.
hence schematic difference:
password => key => encryption
key => encryption
Unfortunatelly in the PHP openssl_encrypt documentation I cannot find any information how to use a key. The only thing suggested is a parameter "password".
Can anybody give me a glue how a key can be used?
Surely I donot want to enter the key as the password parameter as I want a specific key to be used in encryption. I do not want this key to be simply missunderstood as a parameter and serve for another key being calculated from my "key mistaken as password".
Additionally the mistery continues looking at the documention regarding the initialization vector parameter in the same openssl_encrypt function. It simply states:
iv A non-NULL Initialization Vector.
and that iv should be a string. Given that the iv is normaly a binary data of a certain length and for instance a string terminating \0 (hex 0x00) can be occuring inside I am puzzled what format is desired.
In essence I feel very much left alone with the PHP documentation which also states
WARNING This function is currently not documented; only its argument
list is available.
Update
I did some testing, and "trying around" to help me figure out what the password parameter is.
using this code:
$pass="0123456789abcdefghijklmnob";
$iv="0123456789abcdef";
echo "using $pass results:\n";
echo openssl_encrypt("test secret string", 'aes-128-cbc', $pass,NULL,$iv);
I get this result:
using 0123456789abcdefghijklmnob results:
XjEeaLucY38Y6XEUceYMYKTebR4kOp3s727ipMl5KNc=
Then changing the length of the "password" parameter:
$pass="0123456789abcdefg"; //hijklmnob";
$iv="0123456789abcdef";
echo "using $pass results:\n";
echo openssl_encrypt("test secret string", 'aes-128-cbc', $pass,NULL,$iv);
I get still the same encrypted code:
using 0123456789abcdefg results:
XjEeaLucY38Y6XEUceYMYKTebR4kOp3s727ipMl5KNc
It seems by way of testing yet not by way of being informed by the documentation that
the password is indeed only considered up to the first 16 bytes which seem to be the 128 bit that would be the key.
It frightens me that in such a sensitive function (used for encryption) the documentation is bad and excessive input of one poorly documented parameter is not even warned about. Also I am quite convinced that password should rather be named key as it seems those 16 bytes do directly represent the key.
The $password parameter is indeed the key. The key size depends on the AES mode you're using (as you know).
As you noted in your update, for AES-128, only the first 16 characters/bytes count for the key. For AES-256, it would be the first 32 characters.
When one uses the openssl_encrypt() and openssl_decrypt() functions, one can simply pass a 32 character human-readable password for the $password/key parameter.
For example, my input for the password parameter might be $password = "This is 32 characters long......";
Most people don't like having to write up a plaintext password that is a fixed length, so they might compute a hash and truncate it to the correct length. They would use this hash as their encryption key/password.
For example, I could compute an MD5 hash of a password/phrase of any length that I would like and then use that as my AES password/key:
$plaintextPass = 'This is my password. This password is not exactly 32 bytes, but that is okay because I am hashing this.';
$password = hash('md5', $plaintextPass); /* the encryption key */
With that in place, no matter what plaintext password I use, I can have a valid 32 character/byte string as my encryption key/password. This does reduce the entropy of the encryption key/password, though, because a normal 32 character string has a larger key space than an MD5 hash output (256 possibilities per byte vs. 16 possibilities per byte); however, 16^32 is still certainly out of the range of brute force.
Off topic: In some of my personal programs, I have been working on using 32 randomly generated bytes with values between 0-255. This would make the entropy of the encryption key 256^32 which is infeasible to bruteforce. This will also be resistant to dictionary attacks because the 32-bytes are randomly generated using a cryptographically secure pseudo-random number generator (CSPRNG).
So, to sum this all up, yes, the $password parameter is indeed the key used for encryption. I agree with you that is should be written as $key in the documentation, but oh well. The password/key which you select for encryption can be humanly readable as long as it satisfies the length requirements of the hashing key. To satisfy these length requirements, one can hash a human-readable/plaintext password and use the hash of that password as the key ($password parameter), but the human-readable password should still be long and unique.
The documentation is not very clear, however this comment on the openssl_encrypt() PHP doc page really helped me when I was trying to understand the function. The comment provides an example as well as useful information. To direct quote the author of the comment:
Because the password parameter documented here is not the password.
...
It is the key!
[Comment minorly edited]

Is there a chance of uniqid('foo') having the same value as uniqid('foo2') in PHP?

Since uniqid() provides a random string based on the value given, is it even possible, and if so, what are the chances of uniqid('foo') equalling uniqid('foo2')?
uniqid() does not provide a random value based on the string.
Per documentation:
Gets a prefixed unique identifier based on the current time in microseconds.
foo and foo2 will only be used to prefix the value. For example, this code:
echo uniqid('foo') . "\n";
echo uniqid('foo2');
would output:
foo510aac3bedcdb
foo2510aac3bedd03
As long as the prefix is different, the values won't collide. However with the same prefix, a collision would be possible if the 2 requests are made at the same microsecond. If you are worried about collision, set the second parameter to true to add more entropy to your value.

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;

Can memcached keys contain spaces?

I seem to have problems with memcached keys that have spaces, though I can't pinpoint exactly what.
A more explicit answer (referred to by Dustin, but not referenced):
Keys
Data stored by memcached is identified with the help of a key. A key
is a text string which should uniquely identify the data for clients
that are interested in storing and retrieving it. Currently the
length limit of a key is set at 250 characters (of course, normally
clients wouldn't need to use such long keys); the key must not include
control characters or whitespace.
Source: protocol.txt (Specific Version)
No. Memcached keys cannot contain spaces.
Memcached clients seem not to validate keys in favor of performance.
What I usually do is create a method named createWellFormedKey($key) and pass the returned result to the set() and get() methods of the memcached client.
I do not use md5 and sha1 hashing unless the base64 version exceeds 250 characters. This is because md5 and sha1 are more expensive operations performance wise.
A sample PHP code looks like this:
/**
* Generates a well formed key using the following algorithm:
* 1. base64_encode the key first to make sure all characters are valid
* 2. Check length of result, less than 250 then return it
* 3. Length of result more than 250 then create a key that is md5($validKey).sha1($validKey).strlen($validKey)
*/
private function createWellFormedKey($key) {
// Get rid of all spaces, control characters, etc using base64
$validKey = base64_encode($key);
$validKeyLength = strlen($validKey);
// 250 is the maximum memcached can handle
if (strlen($validKey) < 250) {
return $validKey;
}
$validKey = md5($validKey).sha1($validKey).$validKeyLength;
return $validKey;
}
At the moment I'm playing around with memcached with PHP and the Problem described IMHO can be easily solved by using hash algorithms like md5 and sha1 (or any other).
I'm using a combination of a md5-hash, sha1-hash and sha256 + the length of the key given.
Obviously this method can be reduced to two hash-methods + length of the key, so you can easily avoid using space or other characters that should not be in the key.
In my opinion the hash-collions are avoided because the chance that both hash algorithms have a collision is nearly 0. By additionally using the key length in the key the problem of a collision is 0.
Applications using the memcached binary protocol can use whitespace-containing keys, though there is still a 250-byte length limit.

Categories