I almost lost my mind trying to reverse this function, a friend of mine suggested to ask "the pros" so I am here.
<?php
$data = "Data to be encrypted";
$ceva = $data;
$textHos = 'MCRYPT_RIJNDAEL_128';
function encrypt($plaintext,$textHos) {
$textLen=str_pad(dechex(strlen($plaintext)),8, '0', STR_PAD_LEFT);
$salt='WSj2g7jTvc8ISmL60Akn';
$textHosHash=hash('sha256',$salt.$textHos);
$textHos= md5($textHos,true);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $textHos,
$plaintext, MCRYPT_MODE_CBC,$iv);
$ciphertext = $iv . $textHosHash . $textLen . $ciphertext;
$ciphertext_base64 = base64_encode($ciphertext);
return $ciphertext_base64;
}
$data = encrypt($ceva,$textHos);
echo $data;
?>
The output is:
P8avDeviXdd7bKfNMP0gwmZmZjg1OWMzOWFlNzRiMzU2Y2JiMTQ5OTY4MTI3MWNiYjQzYjBkMTAyNDUzM2ZhNGJjZmZhNzQ4M2QxN2M0ZGYwMDAwMDAxNN2xStdw/bhxIxSOevRp37HiXJeVXz7Ge31KEvq9dZjT
any help with resolving the encrypted text into a readable one again?
Thanks.
Your encrypt function makes a lot of nonsense and I hope it doesn't run in any production environment.
function encrypt($plaintext,$textHos) {
// not needed..
//$textLen=str_pad(dechex(strlen($plaintext)),8, '0', STR_PAD_LEFT);
//$salt='WSj2g7jTvc8ISmL60Akn';
//$textHosHash=hash('sha256',$salt.$textHos);
$textHos = md5($textHos,true);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $textHos,
$plaintext, MCRYPT_MODE_CBC,$iv);
// i commented out the unneccessary parts..
$ciphertext = $iv /* . $textHosHash . $textLen . */ $ciphertext;
$ciphertext_base64 = base64_encode($ciphertext);
return $ciphertext_base64;
}
So whats left in the encrypted data is the iv vector (and 72 chars of some unneccessary data) and the encrypted data itself - encoded in base64
Reversing this is quite easy
function decrypt($ciphertext, $textHos) {
$text = base64_decode($ciphertext);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = substr($text, 0, $iv_size);
$textHos = md5($textHos, true);
// the +72 is neccessary for your original code - the code above doesn't need this part
$ciphertext = substr($text, $iv_size + 72);
$encrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $textHos, $ciphertext, MCRYPT_MODE_CBC, $iv);
return rtrim($encrypted, chr(0));
}
Note: DON'T USE THIS CODE IN PRODUCTION! Nowdays AES128 isn't safe
Related
I am trying to encrypt/decrypt files in PHP. So far I am successful with .txt files but when it comes to .pdf and .doc or .docx my code fails, i.e. it gives absurd results. Can anyone suggest modification/alternative in my code? Thanks in advance!
Here's the encryption function
function encryptData($value)
{
$key = "Mary has one cat";
$text = $value;
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_ECB, $iv);
return $crypttext;
}
Here's the decryption function
function decryptData($value)
{
$key = "Mary has one cat";
$crypttext = $value;
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$decrypttext = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $crypttext, MCRYPT_MODE_ECB, $iv);
return trim($decrypttext);
}
I used this blog to help me encrypt/decrypt pdf files on my local machine using openssl_encrypt because mcrypt is deprecated in php7.
First, you get the file contents of the pdf:
$msg = file_get_contents('example.pdf');
Then I called the encryption function written in the blog post:
$msg_encrypted = my_encrypt($msg, $key);
Then I open the file I want to write to and write the new encrypted msg:
$file = fopen('example.pdf', 'wb');
fwrite($file, $msg_encrypted);
fclose($file);
For reference, in case that blog goes down, here are the encryption and decryption functions from the blog:
$key = 'bRuD5WYw5wd0rdHR9yLlM6wt2vteuiniQBqE70nAuhU=';
function my_encrypt($data, $key) {
// Remove the base64 encoding from our key
$encryption_key = base64_decode($key);
// Generate an initialization vector
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
// Encrypt the data using AES 256 encryption in CBC mode using our encryption key and initialization vector.
$encrypted = openssl_encrypt($data, 'aes-256-cbc', $encryption_key, 0, $iv);
// The $iv is just as important as the key for decrypting, so save it with our encrypted data using a unique separator (::)
return base64_encode($encrypted . '::' . $iv);
}
function my_decrypt($data, $key) {
// Remove the base64 encoding from our key
$encryption_key = base64_decode($key);
// To decrypt, split the encrypted data from our IV - our unique separator used was "::"
list($encrypted_data, $iv) = explode('::', base64_decode($data), 2);
return openssl_decrypt($encrypted_data, 'aes-256-cbc', $encryption_key, 0, $iv);
}
m using
public function encrypt($plain_str,$key)
{
$str= mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plain_str, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND));
$str = urlencode(base64_encode($str));
return $str ;
}
public function decrypt($cipher_str,$key)
{
$str = urldecode(base64_decode($cipher_str));
return mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $str, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND));
}
on crypting :201433~58~g#fds.com~20140820142427
i get : %2BAihYMLwpwrsmL4lSGGzwFTfonvdCyOb%2BCGEUJ%2F%2BE%2F7ZnvgwFRYFtlazQeSrVjUjyaaGZADK8%2BZyynIGxyt4VQ%3D%3D
on decrypting : %2BAihYMLwpwrsmL4lSGGzwFTfonvdCyOb%2BCGEUJ%2F%2BE%2F7ZnvgwFRYFtlazQeSrVjUjyaaGZADK8%2BZyynIGxyt4VQ%3D%3D
i get :201433~58~g#fds.com~20140820142427 back but
when string is malformed like some character removed
like this : %2BAihYMLwpwrsmL4lSGGzwFTfonvdCyOb%2BCGEUJ%2F%2BE%2F7Z
on decrypting i get : 201433~58~g#fds.com~201408201424O#¿W«Gݽˋ¯ È#'oP´ŸØw\Â⦑
How can i detect this anomoly ?
First of all, I'd like to list some flaws in your code:
Don't use ECB mode.
You are encrypting using MCRYPT_RIJNDAEL_128, but you're getting the IV size for MCRYPT_RIJNDAEL_256. (btw, IV is ignored in ECB mode, which is one of the reasons why not to use it)
You are also using MCRYPT_RAND as your randomness source, which is not secure. You should use MCRYPT_DEV_URANDOM (that is also the new default in PHP 5.6).
You don't have to urlencode() the resulting ciphertext, Base64 encoding is URL-safe.
Now, to answer your question ... this is done via a HMAC. The easiest way to use a HMAC is to prepend the cipher-text with it (which you should do with the IV as well; don't worry, it's not a secret):
public function encrypt($plainText, $encKey, $hmacKey)
{
$ivSize = mcrypt_get_iv_size('rijndael-128', 'ctr');
$iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM);
$cipherText = mcrypt_encrypt('rijndael-128', $encKey, $plainText, 'ctr', $iv);
$cipherText = $iv.$cipherText;
$hmac = hash_hmac('sha256', $cipherText, $hmacKey, true);
return base64_encode($hmac.$cipherText);
}
public function decrypt($cipherText, $encKey, $hmacKey)
{
$cipherText = base64_decode($cipherText);
if (strlen($cipherText) <= 32)
{
throw new Exception('Authentication failed!');
}
$recvHmac = substr($cipherText, 0, 32);
$cipherText = substr($cipherText, 32);
$calcHmac = hash_hmac('sha256', $cipherText, $hmacKey, true);
if ( ! hash_equals($recvHmac, $calcHmac))
{
throw new Exception('Authentication failed!');
}
$ivSize = mcrypt_get_iv_size('rijndael-128', 'ctr');
$iv = substr($cipherText, $ivSize);
$cipherText = substr($cipherText, $ivSize);
return mcrypt_decrypt('rijndael-128', $encKey, $cipherText, 'ctr', $iv);
}
Please note that the encryption key and HMAC key are different - they most NOT be the same key. Also, for Rijndael-128, you should create a 128-bit (or 16-byte) random key, it is not something that you can just type in with your keyboard. Here's how to generate one:
$encKey = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
Trying to achieve encrypting and decryption using following strategy, but ending up with random characters mostly.
class Crypt {
public static function encrypt($string, $account) {
// create a random initialization vector to use with CBC encoding
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = pack('H*', $account . $account);
$output = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $string, MCRYPT_MODE_CBC, $iv);
$output = $iv . $output;
$output = base64_encode($output);
$output = urlencode($output);
return $output;
}
public static function decrypt($token, $account) {
$ciphertext_dec = base64_decode($token);
// retrieves the IV, iv_size should be created using mcrypt_get_iv_size()
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv_dec = substr($ciphertext_dec, 0, $iv_size);
// retrieves the cipher text (everything except the $iv_size in the front)
$ciphertext_dec = substr($ciphertext_dec, $iv_size);
$key = pack('H*', $account . $account);
$token = urldecode($token);
$output = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);
$output = rtrim($output, "");
return $output;
}
}
Can't get exact values back, sometimes it decrypts but I see some garbage values, but mostly just random characters.
$a = \Crypt::encrypt("MyPassword", "1974246e");
echo \Crypt::decrypt($a, "1974246e");
Edits after the discussion
class Crypt {
public static function encrypt($data, $passphrase) {
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC); //create a random initialization vector to use with CBC encoding
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = pack('H*', $passphrase . $passphrase);
return base64_encode($iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $data, MCRYPT_MODE_CBC, $iv));
}
public static function decrypt($data, $passphrase) {
$data = base64_decode($data);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC); //retrieves the IV, iv_size should be created using mcrypt_get_iv_size()
$iv = substr($data, 0, $iv_size);
$data = substr($data, $iv_size); //retrieves the cipher text (everything except the $iv_size in the front)
$key = pack('H*', $passphrase . $passphrase);
return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $data, MCRYPT_MODE_CBC, $iv), chr(0));
}
}
Usage:
$pass = "MyPassword*&^*&^(*&^(";
$token = \Crypt::encrypt($pass, "1974246e8e8a479bb0233495e8a3ed12");
$answer = \Crypt::decrypt($token, "1974246e8e8a479bb0233495e8a3ed12");
echo $answer == $pass ? "yes" : "no";
Don't urlencode. Unnecessary.
trim for NULL bytes, not empty strings: rtrim($str, chr(0)); (Instead, you might want to save the source string length in the encrypted result too, so you won't rtrim() too much.)
Why pack('H*', $account) for $key? Also unnecessary.
Rijndael 128 uses 16 byte keys (128 bits), so make sure your key is at least that long:
$key = $account . $account
will do, but it obviously imperfect. (mcrypt will do something like that if it's too short.) If every account had its own passphrase, that would be good. (Even more so in combination with an app secret, but details.)
rtrim() with chr(0) is fine, very probably, because your source string won't have trailing NUL bytes.
I usually use these en/decrypt functions, or alike, but these have a static secret/key, so yours is better.
To send an encrypted token to the client:
$enc_token = Crypt::encrypt($token, $key);
// $enc_token might contain `/` and `+` and `=`
$url = 'page.php?token=' . urlencode($enc_token);
I am encrypting a string with PHP's mcrypt_encrypt function. This is my code:
$ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$this->iv = mcrypt_create_iv($ivSize, MCRYPT_RAND);
$encryptionKey = pack('H*', $key);
$stringToEncryptUTF8 = utf8_encode($stringToEncrypt);
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $encryptionKey, $stringToEncryptUTF8, MCRYPT_MODE_CBC, $this->iv);
$ciphertext = $this->iv . $ciphertext;
$ciphertextBase64 = base64_encode($ciphertext);
$cipherTextURLEncoded = rawurlencode($ciphertextBase64);
return $cipherTextURLEncoded;
Now I send the encrypted string to a client which later sends it back through an URL. Then I want to decrypt it using:
$stringToDecrypt = base64_decode($stringToDecrypt);
$ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = substr($stringToDecrypt, 0, $ivSize);
$stringToDecrypt = substr($stringToDecrypt, $ivSize);
$encryptionKey = pack('H*', $key);
$decodedText = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $encryptionKey, $stringToDecrypt, MCRYPT_MODE_CBC, $iv);
return $decodedText;
This is giving me garbage though and not the original string. The variable $key has the same value in both cases. What is wrong?
I had to trim the decrypted string to remove \0 characters at the end of it. Now it works.
You don't reverese the rawurlencode step:
$cipherTextURLEncoded = rawurlencode($ciphertextBase64);
Try to add this:
$stringToDecrypt = rawurldecode($stringToDecrypt);
I'm writing an encryption to my application and website, but I don't know how to correctly encrypt the string in php. Decryption is already done by this code:
function decrypt_blowfish($data,$key){
$iv=pack("H*" , substr($data,0,16));
$key=pack("H*" , $key);
$x =pack("H*" , substr($data,16));
$res = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $x , MCRYPT_MODE_CBC, $iv);
return $res;
}
I tried with simple:
function encrypt_blowfish($data,$key){
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$crypttext = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $data, MCRYPT_MODE_CBC, $iv);
return $crypttext;
}
But it returns strang ASCI chars instead of correct blowfish code. Could somebody explain me why, and what am I doing wrong?
Thanks in advance
C.H.
function decrypt_blowfish($data,$key){
$iv=pack("H*" , substr($data,0,16));
$x =pack("H*" , substr($data,16));
$res = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $x , MCRYPT_MODE_CBC, $iv);
return $res;
}
function encrypt_blowfish($data,$key){
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$crypttext = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $data, MCRYPT_MODE_CBC, $iv);
return bin2hex($iv . $crypttext);
}
$string = encrypt_blowfish('hello world', 'abc123');
echo 'ENCRYPTED: ' . $string . "\n";
echo 'DECRYPTED: ' . decrypt_blowfish($string, 'abc123');
Try that. In the decryption function you are converting from hex to binary, so it is expecting a hex value to be passed. Your encryption function is outputting binary, so you need to convert it to hex with the above change.