Problem with serialize/unserialize and mcrypt when doing Signed Cookies
I'm working with a friend to get signed cookies on a website but I'm having a lot of problems when trying to encrypt it with mcrypt and MCRYPT_RIJNDAEL_256. I've the cookies working fine, so the problem is only when encrypting/decrypting the value of the cookie.
Here is the error is 开发者_开发百科showed when trying to decrypt the cookie:
Notice: unserialize(): Error at offset 0 of 93 bytes in /var/samba/www/xxx/src/data/include/yyy/Cookie.php on line 94
This exact line corresponds to:
$this->_cookie["value"] = unserialize(mdecrypt_generic($tv, $cookie_value));
And here is how I manage to encrypt / decrypt.
First, send cookie.
$tv = mcrypt_module_open(MCRYPT_RIJNDAEL_256, null, "ctr", null);
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($tv), MCRYPT_RAND);
mcrypt_generic_init($tv, "t3stp4ssw0rd", $iv);
$this->_cookie["value"] = base64_encode(mcrypt_generic($tv, serialize($this->_cookie["value"])));
mcrypt_generic_deinit($tv);
mcrypt_module_close($tv);
setrawcookie($this->_cookie["name"],
$this->_cookie["value"],
$this->_cookie["expire"],
$this->_cookie["path"],
$this->_cookie["domain"],
$this->_cookie["secure"],
$this->_cookie["httponly"]);
PD: Yep, lovely test password ;-)
The value I see on firebug for the cookie is:
oKWdbVLX9T+mbOut4swo/aXr0g5O/3ApqfWZ1GZlrwwMSTa+M4n8Uey0UQs827HB7tilc/OzUPWQxoNvnAIkP5CFGkvgn+j+I36qN6dB0HmOUPlkNXJlz8Tfqxrjf8Gx
My get cookie, where I've to decrypt the value is:
$this->_cookie["name"] = $cookie_name;
$this->_cookie["value"] = $_COOKIE[$cookie_name];
$cookie_value = base64_decode($this->_cookie["value"]);
$tv = mcrypt_module_open(MCRYPT_RIJNDAEL_256, null, "ctr", null);
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($tv), MCRYPT_RAND);
mcrypt_generic_init($tv, "t3stp4ssw0rd", $iv);
$this->_cookie["value"] = unserialize(mdecrypt_generic($tv, $cookie_value));
mcrypt_generic_deinit($tv);
mcrypt_module_close($tv);
return $_COOKIE[$cookie_name];
The problem is when I try to unserialize the value of the decrypted data. Anyone know where can be the problem?
Thank you in advance!
UPDATE:
$cookie_value = base64_decode($this->_cookie["value"]);
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_256, "", "cfb", "");
$ks = mcrypt_enc_get_key_size($td);
$key = substr(sha1("t3stp4ssw0rd"), 0, $ks);
$ivs = mcrypt_enc_get_iv_size($td);
$iv = substr($cookie_value, 0, $ivs);
$cookie_value = substr($cookie_value, $ivs);
mcrypt_generic_init($td, $key, $iv);
$cookie_value = mdecrypt_generic($td, $cookie_value);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
$this->_cookie["value"] = unserialize($cookie_value);
Returns me error Warning: mcrypt_generic_init(): Iv size incorrect; supplied length: 0, needed: 32
That offset error normally means that the length of one of the values doesn't correspond to the specified length denoted by the serialized data. In my experience, this normally comes down to:
- as the previous poster said, backslashes being inserted to escape characters
- Encoding issues. This normally arises where some characters are computed as having one byte when serialized, but when unserializing they suddenly have 2 bytes. This can happen when you have, say, an ISO-8859-1 character set, but then some operation changes it to UTF-8.
If I were to take a guess, I'd say that the second point is probably where your problem lies. Your procedure in the first instance is serialize->encrypt->base64_encode, then you reverse the sequence, but I suspect that, somewhere along the line, your character encoding is getting messed up.
Edited: Okay, I took a look at your code, and there's a problem with your encryption/decryption. Your decryption is not returning the decrypted value back. A while ago I came across this function (wish I could remember where so I can attribute it correctly) which is what I use for Mcrypt. It works for both encode and decode. Try it, and see if it sorts out your problem (the only thing it doesn't do is your base64_encode). I think your problem was that you were missing some required steps.
function encDec( $data, $key, $encrypt=true, $cypher='rijndael-128') {
if (function_exists('mcrypt_module_open')) {
# Serialize, if encrypting
if ( $encrypt ) { $data = serialize($data); }
# Open cipher module
if ( ! $td = mcrypt_module_open($cypher, '', 'cfb', '') )
return false;
$ks = mcrypt_enc_get_key_size($td); # Required key size
$key = substr(sha1($key), 0, $ks); # Harden / adjust length
$ivs = mcrypt_enc_get_iv_size($td); # IV size
$iv = $encrypt ?
mcrypt_create_iv($ivs, MCRYPT_RAND) : # Create IV, if encrypting
substr($data, 0, $ivs); # Extract IV, if decrypting
# Extract data, if decrypting
if ( ! $encrypt ) $data = substr($data, $ivs);
if ( mcrypt_generic_init($td, $key, $iv) !== 0 ) # Initialize buffers
return false;
$data = $encrypt ?
mcrypt_generic($td, $data) : # Perform encryption
mdecrypt_generic($td, $data); # Perform decryption
if ( $encrypt ) $data = $iv . $data; # Prepend IV, if encrypting
mcrypt_generic_deinit($td); # Clear buffers
mcrypt_module_close($td); # Close cipher module
# Unserialize, if decrypting
if ( ! $encrypt ) $data = unserialize($data);
}
return $data;
}
Make sure the quotes "
in the cookie information are not escaped using back slashes. If they quotes are escaped, remove them before encrypting. See this thread -> PHP unserialize error at offset, works on some servers, not others
精彩评论