I am encrypting and decrypting a string using:
$key = 'my key';
$data = 'my string';
$ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM);
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $data, MCRYPT_MODE_CBC, $iv);
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_CBC, $iv);
$data = trim($decrypted, chr(0));
http://codepad.viper-7.com/1JgCRs
Is it safe to just trim off the padding added by the encryption algorithm, or is it necessary to store the length of the data before encrypting?
You are trimming the value after you decrypt so you won't run into ay issues with the current code.
If you try to re-encrypt the different, trimmed data, you will get a different encrypted value.
Padding is added on the right normally, so consider rtrim():
$data = rtrim($decrypted, chr(0));
However this is still not yet perfectly safe because in PHP strings can contain NUL-bytes. If for some reason the plain did had NUL-bytes at the end, the rtrim will remove the padding and those previous NUL-bytes.
Related
I am doing encryption which is working good but with same method I am doing decryption I am getting blank string not getting decryption string. I am using method AES-256-ECB and key is hexadecimal so I pass as
$key = pack('H*','xxxxxxxxxxxx');
Encryption is going correct but decryption is not working. Please help me what I am doing wrong.
function encrypt(string $data, string $key, string $method): string
{
$ivSize = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($ivSize);
$encrypted = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv);
$encrypted = strtoupper(implode(null, unpack('H*', $encrypted)));
return $encrypted;
}
function decrypt(string $data, string $key, string $method): string
{
$data = pack('H*', $data);
$ivSize = openssl_cipher_iv_length($method);
$iv = $iv = openssl_random_pseudo_bytes($ivSize);
$decrypted = openssl_decrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv);
return trim($decrypted);
}
Your functions are working perfectly for me with the following code:
$key = pack('H*','aaaaaaaaaaaaa');
$method = 'aes-256-ecb';
$encrypted = encrypt('test string', $key, $method);
$decrypted = decrypt($encrypted, $key.'a', $method);
echo $decrypted; // Output: 'test string'
Since you're getting an empty string for decryption, this means that you've either got the wrong key or cipher text when decrypting. Make sure the key you are using for decryption is exactly the same as the key you're using for encryption, including any manipulations done on it, such as the pack() function you've done here. Even one byte difference and you're not going to be able to decrypt.
Also make sure neither the key nor the cipher text are being truncated when they are stored. If using a database and the column type is too small for what you are trying to store, it will truncate the values.
$secretKey = "MYSECRETKEY";
$plaintext = 'Plain Text Will Be here';
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$ivDecode = base64_encode(mcrypt_create_iv($iv_size, MCRYPT_RAND));
$encrypted = trim(mcrypt_encrypt(MCRYPT_RIJNDAEL_128,
substr(sha1($secretKey), 0, 32),
$plaintext,
MCRYPT_MODE_CBC,
$iv), "\0..\32");
$encrypted = $iv . $encrypted;
$ciphertext_base64 = base64_encode($encrypted);
#echo $ciphertext_base64 . "\n";
$decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128,
substr(sha1($secretKey), 0, 32),
base64_decode($ciphertext_base64),
MCRYPT_MODE_CBC,
base64_decode($ivDecode)), "\0..\32");
echo $decrypted;
when I run above code I got this output.
»_w>ø9â„6ÅkžPlain Text Will Be here
I can't edit $decrypted string because I can't access it. I just can edit $encrypted only. So how can remove extra special characters(»_w>ø9â„6Åkž) from out put by editing $encrypted string. I want to send encrypted text using JSON to the different server to decrypt it.
It is not possible to split the iv and encrypted data prior to Base64 decoding, first Base64 decode and then split them.
MCRYPT_RIJNDAEL_128 which is also AES has a block size of 128-bits or 16-bytes. The iv must be that size. Instead of including base64_decode($iv) as a parameter actually create a 16-byte iv. Base64 decoding the iv will not work if it is is not Base64 encoded, it isn't in this case.
The key should be 128, 192 or 256 bits (16, 24 or 32 bytes), exactly the correct size for interoperability, do not rely on padding by the encryption algorithms.
Similarly, for the input to be encrypted and the key prepare it in a separate statement so that debugging is easier.
Do not trim the output, the mcrypt_decrypt is correct. Padding may add an additional block, that is required.
Do not Base64 decode the result of the decryption, the plaintext was not Base64 encoded. – zaph just now edit
"text like this ïÕ[pI¤;Køv" probably occurs when attempting to print data as a string, not all binary bytes have a print representation and many have special characters as their print representation in the 0x80-0xff range.
Here is the concept, not tested, I have not used php in 20 years so fix any errors:
$secretKey = "1234567890123456"; # Note the length is 16-bytes, a full key
$plaintext = 'XXXXXXXXX';
echo $plaintext . "\n";
# --- ENCRYPTION ---
$key = substr(sha1($secretKey), 0, 32)
$iv = mcrypt_create_iv(16, MCRYPT_RAND);
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128,
$key,
$plaintext,
MCRYPT_MODE_CBC,
$iv);
# prepend the IV for it to be available for decryption
$ciphertext = $iv . $ciphertext;
$ciphertext_base64 = base64_encode($ciphertext);
echo $ciphertext_base64 . "\n";
# --- DECRYPTION ---
$key = substr(sha1($secretKey), 0, 32)
$cipher_text_iv = base64_decode($ciphertext_base64)
# split the iv and encrypted text
$iv = substr($cipher_text_iv, 0, 16)
$ciphertext = substr($cipher_text_iv, 16)
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128,
$key,
$ciphertext,
MCRYPT_MODE_CBC,
$iv);
echo $decrypted;
I have 2 encrypt & decrypt functions using PHP mcrypt library.
public function encrypt_string($input, $key) {
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$cipher = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $input, MCRYPT_MODE_CBC, $iv);
return base64_encode($iv . $cipher);
}
public function decrypt_string($input, $key) {
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$ciphertext = base64_decode($input);
$iv = substr($ciphertext, 0, $iv_size);
$cipher = substr($ciphertext, $iv_size);
return mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $cipher, MCRYPT_MODE_CBC, $iv);
}
Given that the key is generated by:
$key = pack('H*', 'dfgsdighsdfksdhfosdfasdjldsfsdfgdfkgdl'); // a random key
I can successfully obtain back the input after encryption & decryption.
Here is the code:
$pass = '123456';
echo sha1($pass) . PHP_EOL; // prints 7c4a8d09ca3762af61e59520943dc26494f8941b
$pass_cipher = encrypt_string($pass, $key);
$pass_decrypt = decrypt_string($pass_cipher, $key);
echo $pass_decrypt . PHP_EOL; // prints 123456
echo sha1($pass_decrypt) . PHP_EOL; // prints f41b44dbecccaccfbb4ccf6a7fc4921c03878c6d
However, the SHA1 result is different:
7c4a8d09ca3762af61e59520943dc26494f8941b // before encrypt & decrypt
f41b44dbecccaccfbb4ccf6a7fc4921c03878c6d // after encrypt & decrypt
Why is it different ? What did I miss ?
UPDATE:
The accepted answer is useful. For people who wants additional information, here it is:
echo bin2hex($pass) . PHP_EOL; // prints 313233343536
echo bin2hex($pass_decrypt) . PHP_EOL; // prints 31323334353600000000000000000000
and after trim(), the SHA1 result works as expected, as empty hidden 0 are removed.
Problem is that your decrypt_string returns 16 bytes string, that is filled with 0 bytes at the right side. It's a problem known for about 2 years.
Remove null bytes from the right with line similar to this one:
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $cipher, MCRYPT_MODE_CBC, $iv), "\0");
Be careful not to encrypt things with null character at the end, as cryptology functions in PHP works as if all strings were null-terminated and are not shy to cut string at first \0 or to return a bit of \0s glued to the end of their output.
in post encrypted data + sign will be replaced with whitespace. thats why decryption was not done .
What is the best encryption / decryption class / functions that can encrypt an array of data or objects and return it as a hash serialized string?
Then, on decryption, the serialized strings can be decrypted back to its original form of values containing objects or array values.
Thanks
Preface: You seem to have a notion that hashing some data would be the same thing as encrypting it. Hashing is NOT encryption and cannot be reversed with a password or keyfile, like encryption can.
PHP comes with several hashing protocols like md5 (md5_file), SHA1 (SHA1_file). It all really depends on what you're doing with this hash and what you're hashing in the first place.
The mcrypt library has a lot of functions to do encryption in as many ways as you can dream. Here's an example using AES:
$secretKey = 'the longer, the better';
$originalString = 'some text here';
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $secretKey, $originalString,
MCRYPT_MODE_CBC, $iv);
printf( "Original string: %s\n", $originalString );
// Returns "Original string: some text here"
printf( "Encrypted string: %s\n", $crypttext );
// Returns "Encrypted string: <gibberish>"
$decrypttext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $secretKey, $crypttext,
MCRYPT_MODE_CBC, $iv);
// Drop nulls from end of string
$decrypttext = rtrim($decrypttext, "\0");
printf( "Decrypted string: %s\n", $decrypttext );
// Returns "Decrypted string: some text here"
I have a class that takes a string in this format:
000067000000000012620060324b38e2cab3353
, encrypts the string then appends it as a get variable in a URL.
The class that does the encryption has a function that looks like this:
private function _code_encryption($enc_type,$a_string){
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
if($enc_type == self::ENCRYPT_STRING){
//encrypt then return base64 encoded
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, self::AUTH_ENCRYPTION_KEY, $a_string, MCRYPT_MODE_CBC, $iv);
return base64_encode($encrypted);
}elseif($enc_type == self::DECRYPT_STRING){
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, self::AUTH_ENCRYPTION_KEY, base64_decode($a_string), MCRYPT_MODE_CBC, $iv);
return trim($decrypted);
}
}
When the string is encrypted I urlencode the value and add it to the url like the url looks like "https://secure.mysite.com/index.php?action=someaction&transfer_code=XXXXX where XXXX is the urlencoded encrypted string.
Now, when the url is parsed and processed the value of $_GET['transfer_code'] is getting passed into the above _code_encryption function but is not returning the correctly decrypted value and instead returns garbled characters my browser doesn't render. Is there a requirement for the length of the key I use for encryption/decryption? I tried something like
$key = hash('sha256',self::AUTH_ENCRYPTION_KEY,true);
but that didn't work either...
Also, I am not urldecoding the $_GET['transfer_code'] variable because the php man pages state that get vars are already urlencoded...
Should I be UTF-8 encoding the alphanumeric string BEFORE encryption/base64_encoding, or will that even make any difference?
You use a random IV to encrypt, and the a different random IV to decrypt. The decrypted string will never ever match the original. To properly decrypt the original string you must use the same IV that was used during encryption. Usually this is achieved by prepending the IV used to the encrypted string. At decryption time you must first extract the IV from the value, initialize the key with this value, then decrypt the rest usign the properly initialized key.
I don't have a parser to validate this but it should be something like:
private function _code_encryption($enc_type,$a_string){
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
if($enc_type == self::ENCRYPT_STRING){
//encrypt then return base64 encoded
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, self::AUTH_ENCRYPTION_KEY, $a_string, MCRYPT_MODE_CBC, $iv);
return base64_encode($iv.$encrypted);
} elseif ($enc_type == self::DECRYPT_STRING){
$decoded = base64_decode($a_string);
$iv = substr($decoded,0,$iv_size);
$cipher = substr($decoded,$iv_size);
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, self::AUTH_ENCRYPTION_KEY, $cipher, MCRYPT_MODE_CBC, $iv);
return trim($decrypted);
}
}