Memcache hash generation - php

I got a sample Script which looks nearly like this:
$memcache = new Memcache;
$memcache->addServer('memcache_host', 11211);
$memcache->addServer('memcache_host2', 11211);
If i use now
$memcache->set('var_key', 'some really big variable');
The key get/value get stored (only on one server), of course. But when i reorder the Memcache Serverlist, its recreating the cache. I noticed it always use the second Server... But why?
I just want to know and understand, how the hash for storage gets generated.
And which factors are relevant for the hash and server selection?
I could not find anything about.
Regards!

The Answer is:
crc32($KEY) % Server.length
So in my case, i got 2 Servers with the Sample Key "var_key".
crc32('var_key') % 2
The result is 0. So the first Server is the lucky one!
crc32('var_key_bit_longer_and_longer') % 2
In this case the second server (Result is 1) gets chosen.
As we can see, the following factors are relevant:
The Key
Server count
Order of Server
That's the way how the server gets chosen, for standard hash strategy.

Am not sure how the hashing algorithm works but client library may be implemented to run a CRC on the key and do a modulus over the number of instances in the list to select an instance from the list for the set/get
Better still you can increase the changes of each server been selected at 50-50 by using weightoption
$memcache = new Memcache;
$memcache->addServer('memcache_host', 11211,true,50);
$memcache->addServer('memcache_host2', 11211,true,50);

Look at Cache::Memcached's _hashfunc(), it uses the key as its only parameter.
sub _hashfunc {
return (crc32($_[0]) >> 16) & 0x7fff;
}

Related

aspnet_membership password decryption via PHP

I've spent better half of the day trying to figure out the problem I have, and I'm at a dead end it seems.
I have a ASP application(no access to actual code, just database), in which the user passwords are stored in aspnet_membership > Password column, it also has a salt.
I've also got a copy of the machine key file, which from what I understand contains the keys neede to decryot the password?
<machineKey validationKey="**validation key**" decryptionKey="**decryption key**" validation="SHA1" decryption="AES"/>
i've tried a bunch of different ways of doing this, with open ssl, with different libraries, etc. However I seem to lack knowledge when it comes to this. I'm currently trying to use https://github.com/phpseclib/phpseclib library to decrypt the password:
$cipher = new AES(); // could use AES::MODE_CBC
// keys are null-padded to the closest valid size
// longer than the longest key and it's truncated
//$cipher->setKeyLength(128);
$cipher->setKey(**decrypt key**);
// the IV defaults to all-NULLs if not explicitly defined
$cipher->setIV($salt);
echo $cipher->decrypt($password);
However any way i'm trying todo this, I get either random return or false. I've got a very limited amount of info about the version of AES running on the ASP application or any other encryption info. Any help would be appreciated!
Hi This MachineKey has nothing to do with Salt, the salt is generating by the code at run-time using the Password provided.
.NET framework using Rfc2898DeriveBytes for encryption
Something like this
using (Rfc2898DeriveBytes rfc2898DeriveByte = new Rfc2898DeriveBytes(password, 16, 1000))
{
salt = rfc2898DeriveByte.Salt;
bytes = rfc2898DeriveByte.GetBytes(32);
}

Questions on how to generate unique key code programeatically for each project?

I want to generate a Unique Code for each project being created. I have an HTML5 webpage that allows user to create new project, each project when created successfully be assigned a unique code.
I am making a Ajax call to the PHP file on the web server which in-turns saves the project details in MySql database. I have a column in the table that stores unique code for each project created.
I am confused how do i create this code ? is it in PHP or shall i do it in MySql. I want it to be a unique code which will be used by the client to distribute to their customers.
I haven't decided on the length of the key yet but it should be around 8 Digits(combination of char & int is fine ). I know i could use HashTable in Java to create this code based on the inputs from user but i am a fresher to PHP/MySql.
Any advise ?
Note: My Aim is that the key should not be repeated
You can use PHP's uniqid() to generate a unique ID. However, this should not be used for security purposes, as explicity stated in the PHP manual. For more info, go here
Example:
$unique_key = uniqid();
echo $unique_key; // Outputs unique alphanumeric key, like 5369adb278516
Generate Code:
// $length is the length of code you want to return
function generate_code($length) {
$charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789012345678900987654321234567890";
return substr(str_shuffle($charset), 0, $length);
}
To get the verification code, it will call user_code_exists() with a parameter of the generated code which is on $code = generate_code(50).
It will check the database if there's at least one row that has the same value, if the row is 0 (code doesn't exist) it will return as true.
// Do generate and verify code existence
$verification_code = "";
while($this->user_code_exists($code = generate_code(50)) == true) {
$verification_code = $code;
break;
}
public function user_code_exists($code) {
$query = $this->db->prepare("SELECT verification_code FROM accounts WHERE verification_code = :verification_code");
$query->execute(array(':verification_code' => $code));
return ($query->rowCount() == 0) ? true : false;
}
On while loop, once it returns true, the variable $verification_code holds the unique generated code.
This is just an overview, I hope this helps.
See the answers given for this question:
What is the best way to create a random hash/string?
In particular, if you want a purely random value (as opposed to, say a hash of the project name) then see the answer by #Gajus Kuizinas, except using base64_encode rather than binhex will give a shorter but still readable value:
base64_encode(mcrypt_create_iv(8, MCRYPT_DEV_URANDOM));
will give you 11 characters: NTM2OWI0YzR
Or if you don't have the mcrypt library installed, try:
base64_encode(hex2bin(uniqid()."0")); // Derived from microtime (the "0" is needed since uniqid() gives an odd number of characters
gives 10 characters: U2m5vF8FAA after discarding the trailing '=='
If you want to be paranoid about the project code never repeating, add a unique index to the column in your MySql table that stores the unique code for each project created, and repeat the number generation if your insert into the table fails.
As noted by #Mark M above, if you are concerned about security or someone masquerading an existing project code, see #Anthony Forloney's answer in the related question link above. In particular:
Numbers used once (NONCE) - They are used on requests to prevent
unauthorized access, they send a secret key and check the key each
time your code is used.
You can check out more at PHP NONCE Library from FullThrottle
Development
I needed to do something similar, a solution to keep unique id and i ended up with a solution to use PHP function time() like this $reference_number = 'BFF-' . time(); you can change the BFF to something that makes more sense to your business logic. This way i dont have to worry about if new id that is being generated was taken up before.
I hope this helps

Memcached bug in PHP - binary protocol

I came across a bug using Memcached in PHP. Here's my piece of code:
<?php
$mc = new \Memcached();
$mc->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
$mc->addServer("127.0.0.1", 11211);
$mc->touch("key", time() + 600);
$touchResult = $mc->getResultCode();
$mc->set("key", 1, time() + 600);
$setResult = $mc->getResultCode();
echo "<pre>";
echo "Touch result: $touchResult\n";
echo "Set result: $setResult\n";
echo "</pre>";
When you run this for the first time, this is the output:
Touch result: 16
Set result: 0
And for the second time forth:
Touch result: 0
Set result: 5
Correct me if I'm wrong but this is a bug right? Does anyone know a workaround for this?
Here are the versions I use:
Ubuntu 12.04 64bit
PHP 5.3.14
memcached 2.1.0 (PECL module)
libmemcached 1.0.8
Memcached sever 1.4.13
PS. If you wonder what the result codes mean, here they are:
0 RES_SUCCESS
5 RES_WRITE_FAILURE
16 RES_NOTFOUND
[UPDATE]
I played a little more with the code and found something even more interesting. This bug happens regardless of the key that touch and set are working on. As long as the touch operation returns 0 (which means it was successful) the set operation will fail.
[UPDATE]
I managed to produce some other errors as well. e.g. acquiring some key from server and then adding some other will also lead to nasty problems (RES_END code). I believe all these problems are somehow related to binary protocol. It seems to me as if binary protocol's implementation is hardly near stable. Operations which can work without binary protocol will do just fine but once the protocol is set to binary, they will result in blocking problems.
All right.
In first time, you touch not existed key - result is RES_NOTFOUND. When you do set - you write value success - RES_SUCCESS.
In next time you touch existed key (you set it in first linch) and get result of operation RES_SUCCESS, next you try set value for existed key - result false. All right.
If you want change existing value you must use Memcached::replace() method instead of "set"

regain constant pseudo-random in PHP 5.2

I am including the same "random.inc" in foo.php and bar.php. For each, I want reproducible "random" results.
So in foo.php I always want one set of numbers and/or keywords. In bar.php another. Which shouldn't change on reload. That's what I mean by contant pseudo-random. And that's why I seeding on the url. However I still get different results for individual numbers as well as for array pickson every reload. This is the full php file:
<?
header('Content-Type: text/plain');
$seed = crc32( $_SERVER['REQUEST_URI'] );
echo "phpversion: ".phpversion()."\nseed: $seed\n";
srand( $seed ); // (seed verified to be contant as expected)
// neither single values nor array pics turn out deterministic
echo ''.rand(0,100).' '.rand(0,100).' '.rand(0,100)."\n";
$values = array( '0'=>21,'1'=>89,'2'=>96,'3'=>47,'4'=>88 );
print_r( array_rand( $values, 3 ) );
?>
In the days of PHP4.1 it was (verified) possible to achieve constant pseudo-random like this. array_rand API documentation describes as a feature that since 4.2 initialization happens automatically. Perhaps this is overriding any explicit seeding? (if so, perhaps explicit seeding should raise an internal PHP flag, preventing automatic seeding?). Btw: mt_srand() and srand() are equally not working.
I would really like to get my deterministic / constant pseudo-random back...
Update: Solution below (Windows and/or version 5.2 's fault)
Works for me (PHP/5.3.6):
<?php
$data = range(1, 100);
srand(1);
print_r(array_rand($data, 3));
... always prints:
Array
(
[0] => 21
[1] => 89
[2] => 95
)
... in my machine. Apparently, the exact numbers differ depending on the exact environment but they're reproducible.
Guys, you are all correct! (Sorry, I answer it myself now)
my web hoster runs 5.2.17 under Linux 2.6.36, and above problem exists.
under Win x64 5.3.0 everything works as expected.
So it's everyone's guess if that's an OS related bug and/or a PHP bug, fixed in 5.3.0.
Given that random constant seeding worked before, I am guessing they fixed in 5.3 the bug that came with the autoseed feature enhancement in 4.2. Anyway, Thanx again, at least there's clarity now.
The seeding functions are still available, and should still work; it's just since PHP 4.2 they are automatically seeded with the time on page load; but you can still call them to reset the random sequence to a known starting point.
[edit] I have just done a quick test program to make sure I wasn't imagining it!
mt_srand(50000);
print "rand="+mt_rand(0,10000);
Using PHP 5.2, this always results in the same value being printed (1749).
[EDIT]
As noted by #cwd and in the accepted answer to this question, there appears to be a discrepancy in PHP 5.2's behaviour with random number seeding between the Linux and Windows versions. In PHP 5.2 on Linux, the above technique does not appear to work.
Fortunately, the bug seems to have been fixed in PHP 5.3, so the solution to this problem is simply to upgrade. (PHP 5.2 is not supported any longer, so you should upgrade anyway)
Btw, if anyone else wants "constant windows-pre-5.3 pseudo-random" (of low quality, e.g. for stuff like SEO buzzwording) this is a tested workaround:
$r = abs(crc32($URL))%20; // a number between 0 and 19, based on URL
In PHP 5.2.17 and probably on all versions of PHP 5.2, (not sure about windows), we lose the capability of generating random numbers based on a seed as PHP changes the algorithm used for random numbers.
rand and mt_rand are "broken" not only because they will not give one random number, but they will also not give a same sequence of random numbers - even when using a seed!
At first the PHP developers tried to argue that this is the way that it "should" work, but we can guess they caught enough grief about the problem that they have reverted the way that it works with PHP 5.3.
See the php mt_rand page and the bug tracker to learn about this issue.

Does Security:cipher encrypted result depend on the server?

I'm working in a cakephp application where I use Security::cipher in order to encrypt some data. It works perfectly but I've moved files and DB to another server and now the encrypted result is different.
I've tried with some simple lines:
$security = new Security;
$code = $security->cipher('1234', Configure::read('Security.cipherSeed'));
When I print $code, the value is different in both servers. I've configured the same Security.cipherSeed in both core.php files.
Is Security::cipher function using some server value to encrypt?
Thank you.
Well, looking at this bug, it does appear to be an issue.
Digging into the source code, this line is what makes it work:
srand(Configure::read('Security.cipherSeed'));
Now, why does that work? Because rand() implements a pseudo-random algorithm. So for any given known seed, you can theoretically produce the same series of random output. To see if this will work, let's look at the PHP source code for rand(), specifically the internal php_rand function:
PHPAPI long php_rand(TSRMLS_D)
{
long ret;
if (!BG(rand_is_seeded)) {
php_srand(GENERATE_SEED() TSRMLS_CC);
}
We know this isn't the problem, since we're manually seeding (unless we have the suhosin patch installed on the server, then it will always reseed and hence not work).
#ifdef ZTS
ret = php_rand_r(&BG(rand_seed));
#else
# if defined(HAVE_RANDOM)
ret = random();
# elif defined(HAVE_LRAND48)
ret = lrand48();
# else
ret = rand();
# endif
#endif
Woah, did you see what happened? Depending on the server specification, is can use one of 4 different random libraries (rand(), random(), lrand48() or it's own internal random function php_rand_r)! That's why it's not portable across server installs.
Instead, use a real encryption library such as MCrypt or GPG.
Edit: I've submitted a bug report on this topic to cake.

Categories