2

I'm working on a little script that will allow me to store relatively secure information in a cookie to validate a user login without the use of sessions. Part of the output is an encrypted salt to use when generating a hmac_hash with some of the information stored in the cookie, and some of the user information in the database.

However, after some testing, I've ran into a problem with the encryption/decryption of the strings and causing different hash results.

ie:

$str = '123456abcdef';
$hash1 = sha1($str);

$v1 = do_encrypt($str);
$v2 = do_decrypt($v1);

$hash2 = sha1($v2);

and I end up with

$hash1 - d4fbef92af33c1789d9130384a56737d181cc6df 
$hash2 - 0d6034f417c2cfe1d60d263101dc0f8354a1216f

but when I echo both strings, they are both 123456abcdef.

The do_encrypt function is as follows:

function do_encrypt($value) {

    $salt = generate_salt();
    $td = mcrypt_module_open('rijndael-256', '', 'cbc', '');
    mcrypt_generic_init($td, $ek, $salt);
    $encrypted_data = mcrypt_generic($td, $value);

    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);
    return base64_encode($salt.$encrypted_data);    
}

The do_decrypt function:

function do_decrypt($value) {

    $data = base64_decode($value);
    $salt = substr($data, 0, 32);
    $data = substr($data, 32, strlen($data));
    $td = mcrypt_module_open('rijndael-256', '', 'cbc', '');
    mcrypt_generic_init($td, $ek, $salt);
    $decrypted_data = mdecrypt_generic($td, $data);

    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);
    return $decrypted_data;
}

for both functions $ek is an encryption key pulled from another file.

I'm trying to understand why the characters that display are the same, but the actual variables are different (otherwise the hash results would be the same), and is there any way to ensure that both strings are identical for hashing purposes?

Thanks, Ryan.

itsreeyan
  • 174
  • 1
  • 9
  • But you just said the encrypt generates a random salt, how do you know that salt when you decrypt it? And could you just show us the functions? – Jess Oct 09 '11 at 05:33
  • 1
    Encryption/decryption is not relevant in hashing, there is only hashing to match one hashed value to another generated hash value. Encryption `!=` hashing. – Jared Farrish Oct 09 '11 at 05:35
  • @jaredfarrish I know the difference between the two. I am encrypting an additional piece to be stored in the cookie, that when it is retrieved, I can decrypt the value to use as the hmac salt. – itsreeyan Oct 09 '11 at 05:36
  • @mazzzzz I've added the do_encrypt function. – itsreeyan Oct 09 '11 at 05:38
  • What is the "purpose" of decrypting the cookie value? – Jared Farrish Oct 09 '11 at 05:39
  • @jarredfarrish There probably isn't one, I was just playing around with some ideas, and came across this issue. My question is more about my interest in what causes this, and why. – itsreeyan Oct 09 '11 at 05:41
  • Can you please add the `do_decrypt` function? – Tarek Fadel Oct 09 '11 at 05:47
  • 1
    Rolling your own encryption technique is going to be error-prone. You would need to be very methodical with what you were doing. If you can, take a look at http://php.net/manual/en/book.openssl.php; you will almost always be better off using known, proven techniques than homegrown techniques when doing encryption and hashing. – Jared Farrish Oct 09 '11 at 05:47
  • @tarekfadel Added do_decrypt. – itsreeyan Oct 09 '11 at 05:52
  • @jarredfarish Thanks for the read. Again, this is just a bit of testing, and I'm curious how two strings that are identical to look at provide a different result when hashed. What process in the encryption/decryption causes the change? – itsreeyan Oct 09 '11 at 05:55
  • @Ryan can you var_dump both strings? I suspect one has trailing/leading whitespace. – tobyodavies Oct 09 '11 at 06:09
  • @tobyodavies var_dump results: str = string(12) "123456abcdef" v2 = string(32) "123456abcdef" So, why is the v2 nearly triple the size for the same string? – itsreeyan Oct 09 '11 at 06:21
  • It's likely that mcrypt has a block size of 32 characters and that any encrypted/decrypted string must be a multiple of this many bytes. – tobyodavies Oct 09 '11 at 06:40
  • @JaredFarrish he's not rolling his own, he's using a widely used implementation of rijndael – tobyodavies Oct 09 '11 at 07:31
  • @tobyodavies - He is using rijndael to encrypt a hash. At best, it's overkill and unnecessary; at worst, it may introduce a vulnerability or negatively impact user experience. If you need a hash, use a hash algorithm appropriate for the task. There is nothing "more secure" about encrypting any kind of a data in a cookie to relogin a user, as opposed to using a session key or hash value for looking up a session stored in a database. This is why I said *technique*. – Jared Farrish Oct 09 '11 at 14:08
  • @JaredFarrish errr, no he's not, he's hashing values and encrypting them independent of one another. The hash is just checking they are the same, which they weren't because of the block size... – tobyodavies Oct 10 '11 at 05:24
  • @tobyodavies In the actual implementation, the salt for hash_hmac() was being encrypted and stored with the actual hash so that the salt can be unencrypted and used to recreate the actual hash, it was just for a bit more security, which I mentioned in the opening paragraph. But, for simplicity sake, the example I provided was sufficient to ask my question. – itsreeyan Oct 10 '11 at 10:52

1 Answers1

2

As per comments, it looks like you are getting trailing nulls - It's likely that mcrypt has a block size of 32 bytes and that any encrypted/decrypted string must be a multiple of this many bytes.

Taken from the mcrypt_encrypt documentation:

If the size of the data is not n * blocksize, the data will be padded with '\0'.

tobyodavies
  • 27,347
  • 5
  • 42
  • 57
  • You were right. Doing $v2 = str_replace("\0", "", $v2); on the string made the hashes the same. Thanks! – itsreeyan Oct 09 '11 at 06:54