PHP AES 128 bit CBC Encryption gives a size warning - php

i am using the AES ALgo with 128 bit with CBC cipher mode encryption, below is the code:
$cc = 'my secret text';
$key = '3aa22e01c04c7059778c54d122b0273689fba00f4a166a66d15f7ba6a8ba8743';
$iv = '1234567890123456';
$length = strlen($cc);
$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'','cbc','');
mcrypt_generic_init($cipher, $key, $iv);
$encrypted = base64_encode(mcrypt_generic($cipher,$cc));
mcrypt_generic_deinit($cipher);
mcrypt_generic_init($cipher, $key, $iv);
$decrypted = mdecrypt_generic($cipher,base64_decode($encrypted));
mcrypt_generic_deinit($cipher);
echo "encrypted: " . $encrypted;
echo "\n";
echo "decrypted: " . substr($decrypted, 0, $length) . "\n";
But this gives me a warning with output as :
Warning: mcrypt_generic_init(): Key size too large; supplied length:
64, max: 32 in /var/www/cipher.php on line 10 Warning:
mcrypt_generic_init(): Key size too large; supplied length: 64, max:
32 in /var/www/cipher.php on line 14 encrypted:
vM/XVYSjs/QApdCUEQ8bdQ== decrypted: my secret text
Now can someone guide me on why I am facing the size issue and how I can eradicate the issue of size without changing the key...

You are doing 128-bit encryption but your key is 64 hex characters long, which is 265 bits.
Either you need to be doing 256 bit encryption or your key needs to half the size.

I modify your code and it runs fine,
Please, check my changes, ok
$data_to_encrypt = "2~1~000024~0910~20130723092446~T~00002000~USD~F~375019001012120~0~0~00000000000~";
$key128 = "abcdef0123456789abcdef0123456789";
$iv = "0000000000000000";
$cc = $data_to_encrypt;
$key = $key128;
$iv = $iv;
$length = strlen($cc);
$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'','cbc','');
mcrypt_generic_init($cipher, $key, $iv);
$encrypted = base64_encode(mcrypt_generic($cipher,$cc));
mcrypt_generic_deinit($cipher);
mcrypt_generic_init($cipher, $key, $iv);
$decrypted = mdecrypt_generic($cipher,base64_decode($encrypted));
mcrypt_generic_deinit($cipher);
echo "encrypted: " . $encrypted;
echo "<br/>";
echo "length:".strlen($encrypted);
echo "<br/>";
echo "decrypted: " . substr($decrypted, 0, $length);

Related

using enigma on mcrypt

So my goal is to demonstrate an online version of the enigma machine. I'm using PHP to do this and using mcrypt as it seems to be the only way to use the enigma algorithm without writing it out myself.
Trouble is there is no information out there currently on how to set up mcrypt's enigma.
I am also using stream as nothing else seems to work before anyone asks.
I really would be greatful for any help regarding this.
This is my current setup.
$td = mcrypt_module_open('enigma', '', 'stream', '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_DEV_RANDOM);
$ks = mcrypt_enc_get_key_size($td);
$key = substr(md5('very secret key'), 0, $ks);
mcrypt_generic_init($td, $key, $iv);
$encrypted = mcrypt_generic($td, 'This is very important data');
mcrypt_generic_deinit($td);
mcrypt_generic_init($td, $key, $iv);
$decrypted = mdecrypt_generic($td, $encrypted);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
echo trim($decrypted) . "\n";
How do I get it encrypt in the enigma way then display it in ciphertext aswell as the ordinary text?
When running you're code I'm getting this warning:
Warning: mcrypt_create_iv(): Cannot create an IV with a size of less than 1 or greater than 2147483647
The error occurs because
mcrypt_enc_get_iv_size($td)
gives an value of '0':
$ivSize = mcrypt_enc_get_iv_size($td);
echo "ivSize: " . $ivSize;
ivSize: 0
The solution is to use a blank IV:
$iv = "";
and everything works like expected:
echo trim($decrypted) . "\n";
This is very important data

Remove Special character when decrypt by editing encrypt string

$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;

Cannot use a constant IV key and a produced ENCRYPT_KEY in php mcrypt

I know that a constant IV key is wrong and a random key must be generated. I, however need this as I have been assigned to do this. I have searched all over the net on how to deal with this but failed. My code is below, and any advice will be greatly apprecieted.
Here's the whole code together with the functions
define('ENCRYPTION_KEY', 'ITU2NjNhI0tOc2FmZExOTQ=='); //Encryption KEY
// Encrypt Function
function mc_encrypt($encrypt, $key)
{
//Do Not Put ENCRYPTION_KEY here
$encrypt = serialize($encrypt);
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);
//$iv = ('AAAAAAAAAAAAAAAAAAAAAA==');
$key = pack('H*', $key);
$mac = hash_hmac('sha256', $encrypt, substr(bin2hex($key), -32));
$passcrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $encrypt.$mac, MCRYPT_MODE_CBC, $iv);
$encoded = base64_encode($passcrypt).'|'.base64_encode($iv);
return $encoded; //return base64_encode($encoded).':'.$iv;
}
// Decrypt Function
function mc_decrypt($decrypt, $key)
{
$decrypt = explode('|', $decrypt);
$decoded = base64_decode($decrypt[0]);
$iv = base64_decode($decrypt[1]);
if(strlen($iv) !== mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC))
{
return false;
}
$key = pack('H*', $key);
$decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $decoded, MCRYPT_MODE_CBC, $iv));
$mac = substr($decrypted, -64);
$decrypted = substr($decrypted, 0, -64);
$calcmac = hash_hmac('sha256', $decrypted, substr(bin2hex($key), -32));
if($calcmac !== $mac)
{
return false;
}
$decrypted = unserialize($decrypted);
return $decrypted;
}
echo '<h1>Sample Encryption</h1>';
$data = 'Patrick';
$encrypted_data = mc_encrypt($data, ENCRYPTION_KEY);
echo '<h2>Example #1: String Data</h2>';
echo 'Data to be Encrypted: ' . $data . '<br/>';
echo 'Encrypted Data: ' . $encrypted_data . '<br/>';
echo 'Decrypted Data: ' . mc_decrypt($encrypted_data, ENCRYPTION_KEY) . '</br>';
If i use that I get the error
Warning: pack(): Type H: illegal hex digit I in C:\xampp\htdocs\sample1\test.php on line 24
and when I use the
$iv = ('AAAAAAAAAAAAAAAAAAAAAA==');
Instead of this
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);
while they have both
define('ENCRYPTION_KEY', 'd0a7e7997b6d5fcd55f4b5c32611b87cd923e88837b63bf2941ef819dc8ca282'); //Encryption KEY
this is the error
Warning: mcrypt_encrypt(): The IV parameter must be as long as the blocksize in C:\xampp\htdocs\sample1\test.php on line 26
This is working and tested code on PHP 5.3.18. Demonstration at Viper-7
1) It uses the required base64 encoded 'AAAAAAAAAAAAAAAAAAAAAA==', as the IV ('salt'), which when converted back to a string is 16 bytes of binary zeroes. As we need 32 bytes i just concatenate it with itself to make the required length.
2) There are two supplied keys:
1) base64 encoded: 'ITU2NjNhI0tOc2FmZExOTQ==', which is a 'typical' high quality password string that is 16 bytes long. This needs to converted to a hex string for the encryption functions.
2) The hexadecimal literal: 'd0a7e7997b'...
Please note: The supplied keys, as hex strings, are not equal to each other!
This does not affect the routines, just be aware that the same key must be used to encrypt / decrypt.
The routines:
// Encrypt Function - $key must be a Hexadecimal String
function mc_encrypt($encrypt, $key) {
//Do Not Put ENCRYPTION_KEY here
$encrypt = serialize($encrypt);
// $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);
$iv = base64_decode(ENCRYPTION_IV); // convert back to binary string
$actualIV = $iv . $iv; // As it is 16 bytes of binary characters just double it
$key = pack('H*', $key); // convert key back to binary string
$mac = hash_hmac('sha256', $encrypt, substr(bin2hex($key), -32));
$passcrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $encrypt.$mac, MCRYPT_MODE_CBC, $actualIV);
$encoded = base64_encode($passcrypt).'|'.base64_encode($iv);
return $encoded;
}
Note that '$actualIV' is just a 'trick' to get the 32 bytes required. However, it will work if different 16 byte IV's are used.
Caveats: It is important that different (random) IV's are used when encrypting otherwise identical messages encrypt to the same ciphertext when the same key is used. To use 16 byte IV's in the routine i would be tempted to generate a random IV and just use the first 16 bytes of it concatenated to itself as is used currently.
i.e. replace this code:
$iv = base64_decode(ENCRYPTION_IV); // convert back to binary string
with:
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);
$iv = substr($iv, 0, 16);
CBC mode and 'Padding Oracle Attacks'
It looks as though this is not an issue if you use PHP exclusively. There may be issues decrypting on different systems. This link explains the issues: Cryptography/DES-PHP-Block-Padding-in-mcrypt.html
// Decrypt Function - - $key must be a Hexadecimal String
function mc_decrypt($decrypt, $key) {
$decrypt = explode('|', $decrypt);
$decoded = base64_decode($decrypt[0]);
$iv = base64_decode($decrypt[1]);
$actualIV = $iv . $iv; // make it long enough and match the original IV used.
if(strlen($actualIV) !== mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC)){ return false; }
$key = pack('H*', $key);
$decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $decoded, MCRYPT_MODE_CBC, $actualIV));
$mac = substr($decrypted, -64);
$decrypted = substr($decrypted, 0, -64);
$calcmac = hash_hmac('sha256', $decrypted, substr(bin2hex($key), -32));
if($calcmac!==$mac) { return false; }
$decrypted = unserialize($decrypted);
return $decrypted;
}
Note that '$iv' is concatenated with itself to get the 32 bytes required.
Defined keys:
define('ENCRYPTION_B64KEY', 'ITU2NjNhI0tOc2FmZExOTQ=='); //Encryption KEY
define('ENCRYPTION_IV', 'AAAAAAAAAAAAAAAAAAAAAA==');
define('ENCRYPTION_HEXKEY', 'd0a7e7997b6d5fcd55f4b5c32611b87cd923e88837b63bf2941ef819dc8ca282'); //Encryption KEY
Examples using both supplied keys:
echo '<h1>Sample Encryption</h1>';
$data = 'Patrick';
echo '<h2>Example #1: Using base64 encoded key (ENCRYPTION_B64KEY)</h2>';
$b64HexKey = bin2hex(base64_decode(ENCRYPTION_B64KEY));
$encrypted_data = mc_encrypt($data, $b64HexKey);
echo 'Data to be Encrypted: ' . $data . '<br/>';
echo 'Encrypted Data: ' . $encrypted_data . '<br/>';
echo 'Decrypted Data: ' . mc_decrypt($encrypted_data, $b64HexKey) . '</br>';
echo '<h2>Example #2 using Hexadecimal Key (ENCRYPTION_HEXKEY)</h2>';
$hexKey = ENCRYPTION_HEXKEY;
$encrypted_data = mc_encrypt($data, $hexKey);
echo 'Data to be Encrypted: ' . $data . '<br/>';
echo 'Encrypted Data: ' . $encrypted_data . '<br/>';
echo 'Decrypted Data: ' . mc_decrypt($encrypted_data, $hexKey) . '</br>';
Output from the above:
Sample Encryption
Example #1: Using base64 encoded key (ENCRYPTION_B64KEY)
Data to be Encrypted: Patrick
Encrypted Data: /7qKjoPnNiGveTHo0NnkXfSLFIHE72De1q85QWI/d16j4BzLaqIR7jpap0J2wCdHYgK+IS4Zf1OpZorK9iGnPErkh+owjkoEo/dejHxUaVxOS03+Uqti8i13aGeB6wAU|AAAAAAAAAAAAAAAAAAAAAA==
Decrypted Data: Patrick
Example #2 using Hexadecimal Key (ENCRYPTION_HEXKEY)
Data to be Encrypted: Patrick
Encrypted Data: iAyCpfnOHUeHKHT+BIra2TZbRlLJfXKAO5pRGbmKvLyTOlzr9L6IBRI8ZuDsGVdZym26Qd89hKZxnVPbBSsOktCaztF9akZA8iPa3r0jvgISFldRDdHx8CZyd+GfR9BV|AAAAAAAAAAAAAAAAAAAAAA==
Decrypted Data: Patrick

SHA1 the PHP mcrypt_decrypt result

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 .

How to do AES256 decryption in PHP?

I have an encrypted bit of text that I need to decrypt. It's encrypted with AES-256-CBC. I have the encrypted text, key, and iv. However, no matter what I try I just can't seem to get it to work.
The internet has suggested that mcrypt's Rijndael cypher should be able to do this, so here's what I have now:
function decrypt_data($data, $iv, $key) {
$cypher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
// initialize encryption handle
if (mcrypt_generic_init($cypher, $key, $iv) != -1) {
// decrypt
$decrypted = mdecrypt_generic($cypher, $data);
// clean up
mcrypt_generic_deinit($cypher);
mcrypt_module_close($cypher);
return $decrypted;
}
return false;
}
As it stands now I get 2 warnings and the output is gibberish:
Warning: mcrypt_generic_init() [function.mcrypt-generic-init]: Key size too large; supplied length: 64, max: 32 in /var/www/includes/function.decrypt_data.php on line 8
Warning: mcrypt_generic_init() [function.mcrypt-generic-init]: Iv size incorrect; supplied length: 32, needed: 16 in /var/www/includes/function.decrypt_data.php on line 8
Any help would be appreciated.
I'm not terribly familiar with this stuff, but it seems like trying MCRYPT_RIJNDAEL_256 in place of MCRYPT_RIJNDAEL_128 would be an obvious next step...
Edit: You're right -- this isn't what you need. MCRYPT_RIJNDAEL_128 is in fact the right choice. According to the link you provided, your key and IV are twice as long as they should be:
// How do you do 256-bit AES encryption in PHP vs. 128-bit AES encryption???
// The answer is: Give it a key that's 32 bytes long as opposed to 16 bytes long.
// For example:
$key256 = '12345678901234561234567890123456';
$key128 = '1234567890123456';
// Here's our 128-bit IV which is used for both 256-bit and 128-bit keys.
$iv = '1234567890123456';
I send to you one example,
Please, check the code, ok
$data_to_encrypt = "2~1~000024~0910~20130723092446~T~00002000~USD~F~375019001012120~0~0~00000000000~";
$key128 = "abcdef0123456789abcdef0123456789";
$iv = "0000000000000000";
$cc = $data_to_encrypt;
$key = $key128;
$iv = $iv;
$length = strlen($cc);
$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'','cbc','');
mcrypt_generic_init($cipher, $key, $iv);
$encrypted = base64_encode(mcrypt_generic($cipher,$cc));
mcrypt_generic_deinit($cipher);
mcrypt_generic_init($cipher, $key, $iv);
$decrypted = mdecrypt_generic($cipher,base64_decode($encrypted));
mcrypt_generic_deinit($cipher);
echo "encrypted: " . $encrypted;
echo "<br/>";
echo "length:".strlen($encrypted);
echo "<br/>";
echo "decrypted: " . substr($decrypted, 0, $length);

Categories