I tried to encrypt an array then decrypt it back to string by calling a function, it's seem return the correct value if I does all encrypt and decrypt at once time in the function, however, if I return the encrypt value, then call the function again to decrypt it will return me some strange code.
Example 1:
public main()
{
$dataArray = array("one"=>1, "two"=>2, "three"=>3);
$a = $this->encryptDecryptInfo(json_encode($dataArray),$this->key);
var_dump($a);
}
public function encryptDecryptInfo($text,$key)
{
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256,
$text= base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CFB, $iv));
return mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($text), MCRYPT_MODE_CFB, $iv);
}
This will return me the correct value which is string(27) "{"one":1,"two":2,"three":3}"
Example 2:
public main()
{
$dataArray = array("one"=>1, "two"=>2, "three"=>3);
$a = $this->encryptDecryptInfo(json_encode($dataArray),$this->key,"encrypt");
$b = $this->encryptDecryptInfo($a,$this->key,"decrypt");
var_dump($b);
}
public function encryptDecryptInfo($text,$key,$type)
{
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CFB), MCRYPT_RAND);
if($type == "encrypt")
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CFB, $iv));
else return mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($text), MCRYPT_MODE_CFB, $iv);
}
However if I do my code in this way, it will return me strange value which is like this string(27) "�ÔérôŸY éXgíœÈÐN*é౜CµÖ" .
Deos anyone know why this is happen? Both encrypt and decrypt coding are the same for example 1 and example 2, but why it will return strange code in example instead? Any way to fix this issue?
I think this is encoding issue look for UTF here - http://php.net/manual/en/function.base64-encode.php in the comments there is a UTF8 safe encoding function.
By passing the parameters left and right you are changing the encoding and you loose it in the translation. Welcome to PHP :)
You must use the same IV for decryption. Just save it along with encrypted data, for example:
if($type == "encrypt") {
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CFB), MCRYPT_RAND);
return base64_encode($iv . '##' .
mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CFB, $iv));
} else {
list($iv, $data) = explode('##', base64_decode($text));
return mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $data, MCRYPT_MODE_CFB, $iv);
}
I had a similar issue. In the database I originally set it up for 16 characters. When I changed to encrypting, I forgot to change that number so the entire encrypted value was not stored. Once I corrected this it returned normal characters :)
Related
I have this function to encrypt strings:
public function encriptar($string) {
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC),
MCRYPT_DEV_URANDOM);
$encrypted = base64_encode($iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_128,
hash('sha256', getKey(), true),
$string, MCRYPT_MODE_CBC, $iv));
return $encrypted;
}
The problem is that I always return a different value even adding the same string.
Example:
I introduce: StackOverflow
Result: InT3g0AUXXTrmCAxrlht5ZVe8GBmlgGDMotXuVu11hI =
If I rerun the script:
I introduce: StackOverflow
Result: ImhWn5vPA / A2NY2wpUwg7VLWAiGBls80Z84fGU303Ws =
If I re-run the script:
I introduce: StackOverflow
Result: FqvxSsblSwz5riaDnnq7h20PzZTPdk / K + dikLHbLHTY =
How can I make it always the same value?
You are creating a different $iv using MCRYPT_DEV_URANDOM as the pseudo-random-number-generator, use the same $iv, and the result will be the same.
You can either store it in you database, in the class instance, or store it as a prefix/suffix of the final hash.
Albeit you shouldn't be reusing the $iv for security purposes...
A more insightful topic of the security implications of reusing the key, or even the IV can be found here: https://crypto.stackexchange.com/questions/10505/reusing-keys-with-aes-cbc
The result is dependent on the $iv variable which you keep regenerating. You need to generate it only once, save it in the database and then re-use it.
function getIv($database) {
// fictive database abstraction layer
$iv = $database->fetchIv();
if (!$iv) {
$iv = mcrypt_create_iv(
mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC),
MCRYPT_DEV_URANDOM
);
$database->saveIv($iv);
}
return $iv;
}
// in your class
public function encriptar($string) {
$encrypted = base64_encode($iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_128,
hash('sha256', getKey(), true),
$string, MCRYPT_MODE_CBC, getIv()));
return $encrypted;
}
However, for best practices, this should be kept in a configuration file.
I'm trying to send encrypted data over the url to another site (using file_get_contents("anotherUrl.php?hash=$encryptedString"). The problem is, sometimes, the encryption contains some special characters, like +, and this causes the decryption to fail.
Here are my encryption / decryption methods:
public function encrypt($string, $key)
{
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $string, MCRYPT_MODE_CBC, md5(md5($key))));
}
public function decrypt($encrypted, $key)
{
return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode($encrypted), MCRYPT_MODE_CBC, md5(md5($key))), "\0");
}
Here's an example encrypted string which contains a +, and I'm guessing that this causes the decryption to fail.
oWCrVPaS+5GbxcQFc0fulUk/zRAkDD60av4zlPiWskE=
Any ideas how I should solve this? I've tried to do urlencode() and urldecode() on the hash, however that also seems to cause the encryption to break. Is there a way to change the encryption algorithm to get it to only return url safe characters?
Take a look at this thread:
Passing base64 encoded strings in URL
Essentially you DO want to urlencode() before sending the string, however you do NOT want to urldecode() at the other end.
In order to solve this problem I now use the following (after 3 hours of pain), and it works great.
Feel free to copy and paste
function encrypt($pure_string) {
$dirty = array("+", "/", "=");
$clean = array("_PLUS_", "_SLASH_", "_EQUALS_");
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$_SESSION['iv'] = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $_SESSION['encryption-key'], utf8_encode($pure_string), MCRYPT_MODE_ECB, $_SESSION['iv']);
$encrypted_string = base64_encode($encrypted_string);
return str_replace($dirty, $clean, $encrypted_string);
}
function decrypt($encrypted_string) {
$dirty = array("+", "/", "=");
$clean = array("_PLUS_", "_SLASH_", "_EQUALS_");
$string = base64_decode(str_replace($clean, $dirty, $encrypted_string));
$decrypted_string = mcrypt_decrypt(MCRYPT_BLOWFISH, $_SESSION['encryption-key'],$string, MCRYPT_MODE_ECB, $_SESSION['iv']);
return $decrypted_string;
}
Instead of using Base64 for encoding your data you can also use Base32 (RFC 4648) which is URL-safe because it only uses letters A–Z (case-insensitive) and the digits 2–7. There is already a PHP library for encoding/decoding. Note that Base32 takes ~20% more space than Base64.
You can also use URLcrypt which is a handy library helping you with encryption and Base32 encoding.
class Encryption {
var $skey = "SuPerEncKey2010"; // you can change it
public function safe_b64encode($string) {
$data = base64_encode($string);
$data = str_replace(array('+','/','='),array('-','_',''),$data);
return $data;
}
public function safe_b64decode($string) {
$data = str_replace(array('-','_'),array('+','/'),$string);
$mod4 = strlen($data) % 4;
if ($mod4) {
$data .= substr('====', $mod4);
}
return base64_decode($data);
}
public function encode($value){
if(!$value){return false;}
$text = $value;
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->skey, $text, MCRYPT_MODE_ECB, $iv);
return trim($this->safe_b64encode($crypttext));
}
public function decode($value){
if(!$value){return false;}
$crypttext = $this->safe_b64decode($value);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$decrypttext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->skey, $crypttext, MCRYPT_MODE_ECB, $iv);
return trim($decrypttext);
}
}
i use such f-n to encrypt\decrypt
<?
//Encrypt Function
function mc_encrypt($encrypt, $mc_key) {
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND);
$passcrypt = trim(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $mc_key, trim($encrypt), MCRYPT_MODE_ECB, $iv));
$encode = base64_encode($passcrypt);
return $encode;
}
// Decrypt Function
function mc_decrypt($decrypt, $mc_key) {
$decoded = base64_decode($decrypt);
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND);
$decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $mc_key, trim($decoded), MCRYPT_MODE_ECB, $iv));
return $decrypted;
}
?>
if i call mc_encrypt('test', 'pass') all decrypts ok, but if i call mc_encrypt('test=value', 'pass') i can't decrypt. why? and what must i do?
You should tell us what happens, i.e. what code you call, what you expect, and what comes out. We cannot guess what "I can't decrypt" means.
I can give you one suggestion already though:
$passcrypt = trim(mcrypt_encrypt(
MCRYPT_RIJNDAEL_256, $mc_key, trim($encrypt), MCRYPT_MODE_ECB, $iv));
Don't mess with the input data [trim($encrypt)]. If the caller wants to trim the string, leave it to them to do it. Otherwise, if your input string has whitespace to trim, you will end up encrypting a different string than was passed in. That can only end in tears.
i'v got such code
function EnDeCrypt($text, $key, $s = 1){
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND);
switch ($s) {
case '0':
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($text), MCRYPT_MODE_ECB, $iv));
break;
case '1':
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_ECB, $iv));
break;
default:
return FALSE;
break;
}
}
if i call EnDeCrypt in one script, all works, if i try to pass encrypted data to different server in get param-i can't decrypt(get such string ŸTe³qëêyÀÝ)
key equals, result put throw urlencode\urldecode-don't decrypt
try to pass vector mcrypt_create_iv -nothing
To decypher, you need to have the same initialization vector ($iv) that was used to cypher.
Pass it as a parameter to your function and all should be fine.
I use the following function to decrypt data on my server:
function decrypt($key, $text) {
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($text), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)));
}
I have read a lot about NOT using ECB however (and know it is deprecated so wanted to switch to CBC. Simply switching the mode to:
function decrypt($key, $text) {
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($text), MCRYPT_MODE_CBC, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND)));
}
does not work however. No errors are generated but the data returned is still encrypted.
What am I missing?
Updated code - still with errors:
$key = "hello";
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_DEV_RANDOM);
function encrypt($key, $text) {
return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv)));
}
function decrypt($key, $text) {
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($text), MCRYPT_MODE_CBC, $iv));
}
$text = 12345;
echo "Plain Number : " . $text . "<br><br>";
$encrypted = encrypt($key, $text);
echo "AES Number : " . $encrypted . "<br><br>";
echo "Plain Number : ". decrypt($key, $encrypted) . "<br><br>";
this should work - but it returns the error:
blocksize in
blocksize in> Warning: mcrypt_encrypt()
[function.mcrypt-encrypt]: The IV
parameter must be as long as the
blocksize inblocksize in
blocksize in
When you decrypt you need to use the same IV as when you encrypted. It looks like you're generating a new, random IV during decryption.
It's OK to append or prepend the IV to the ciphertext. IVs are not secret but they should be unique for each encrypted message and only used once.
Your updated code has an issue with $iv being a global variable that's not available in the respective en-/decoding functions:
$key = "hello";
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_DEV_RANDOM);
function encrypt($key, $text, $iv) {
return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv)));
}
function decrypt($key, $text, $iv) {
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($text), MCRYPT_MODE_CBC, $iv));
}
$text = 12345;
echo "Plain Number : " . $text . "<br><br>";
$encrypted = encrypt($key, $text, $iv);
echo "AES Number : " . $encrypted . "<br><br>";
echo "Plain Number : ". decrypt($key, $encrypted, $iv) . "<br><br>";
Or you can still rely on the global $iv by importing it into the local function scope:
function encrypt($key, $text) {
global $iv; // or use $GLOBALS['iv] instead of $iv in the call below
return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv)));
}
function decrypt($key, $text) {
global $iv; // or use $GLOBALS['iv] instead of $iv in the call below
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($text), MCRYPT_MODE_CBC, $iv));
}
but this is surely not a recommended practice as it couples your code to global variables.
Did you change the mode when encrypting this text as well?
Also, when using MCRYPT_MODE_CBC, you need to use the same key and IV during encryption and decryption. Randomized IV does not work with CBC.