I am trying to come up with a secure algorithm to encrypt and decrypt specific strings in my project I am working on. I am using the mcrypt_encrypt with the MCRYPT_RIJNDAEL_256 block cipher variation.
I have tested many and found this one to seem quite secure.
I am making the encrypt and decrypt into functions so I can call upon them for multiple instances in the future of my project. So far this is what I have come up with. My question here is if there is any way to make this more secure, harder to decrypt or if there are any newer formulas/methods that are known to be better.
function encrypt($privatekey, $stringe)
{
$var = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $privatekey, $stringe,
MCRYPT_MODE_CBC, $privatekey);
return base64_encode($var);
}
function decrypt($privatekey, $stringd)
{
$stringd = str_replace("~", "+", $stringd);
$var = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $privatekey,
base64_decode($stringd), MCRYPT_MODE_CBC, $privatekey);
$var = rtrim($var, "\0\4");
return $var;
}
I have tested many and found this one to seem quite secure.
What tests did you conduct, exactly?
Rijndael256 is a 256-bit block variant of Rijndael (for which the 128-bit block size variant is known as AES). However, when implemented in pure software (like mcrypt is implemented), it's vulnerable to cache-timing attacks.
What is the most secure mcrpyt_encrypt algorithm?
Mcrypt's implementations are not secure. That's why it was deprecated in PHP 7.1, and removed in PHP 7.2.
See this answer for safe-to-use example code backed by libsodium. For PHP 7.1 and below, you want to install the Sodium extension from PECL or install sodium_compat.
Related
I have an application that was build on CakePHP 1.2, and stored some encrypted data. I am rebuilding the application and need to decrypt the data in the new app to update the encryption on it. The ciphers and methods used to encrypt the data in CakePHP 1.2 are not available in PHP 7.1+. Does anyone know of a way that I can decrypt the data in a PHP 7.1+ environment so that it can be encrypted with newer technologies?
Current method that encrypts/decrypts data
function _cryptData(&$data, $direction) {
$ivSize = mcrypt_get_iv_size(MCRYPT_TRIPLEDES, MCRYPT_MODE_CBC);
switch ($direction) {
case 'encrypt':
$iv = mcrypt_create_iv($ivSize, MCRYPT_RAND);
$data = base64_encode($iv) . '|' . base64_encode(mcrypt_encrypt(MCRYPT_TRIPLEDES, Configure::read('CakeMix.cryptKey'), $data, MCRYPT_MODE_CBC, $iv));
break;
case 'decrypt':
list($iv, $encoded) = explode('|', $data);
$data = mcrypt_decrypt(MCRYPT_TRIPLEDES, Configure::read('CakeMix.cryptKey'), base64_decode($encoded), MCRYPT_MODE_CBC, base64_decode($iv));
break;
}
}
The shown code in your question seems to be custom, ie non-CakePHP core code, so this seem more just PHP related.
Mcrypt is deprecated, but still available in PHP 7.1, it has only been removed as of PHP 7.2. Mcrypt can also still be used with PHP 7.2+, you'd just have to install it manually, as it's been moved to PECL, see for example Issue in installing php7.2-mcrypt. You could also use a polyfill like phpseclib/mcrypt_compat. So you should be able to continue using Mcrypt for decryption, and port the data to whatever encryption you like.
Furthermore it should generally also be possible to decrypt the data using OpenSSL, though there seem to be pitfalls around null padding, see for example Decrypt mcrypt with openssl. Here's a basic example:
$data = openssl_decrypt(
base64_decode($encoded),
'des-ede3-cbc',
Configure::read('CakeMix.cryptKey'),
OPENSSL_RAW_DATA | OPENSSL_NO_PADDING,
base64_decode($iv)
);
There's quite a lot of topics on replacing Mcrypt with OpenSSL, which you may want to have a look at for further options.
As php has stopped support for Mcrypt from 7.2 and onwards. I do not know enough to convert Mcrypt to Openssl.
I was wondering if someone could provide the OpenSSL equivalent for this? For the record, I am not looking to support Mcrypt so I have to decrypt my mcrypt encrypted strings(passwords) via openSSL.
To Encode via mcrypt->
static function encode($value= NULL, $key= NULL){
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, $key, $text, MCRYPT_MODE_ECB, $iv);
return trim(self::safe_b64encode($crypttext));
}
private function safe_b64encode($string= NULL) {
$data = base64_encode($string);
$data = str_replace(array('+','/','='),array('-','_',''),$data);
return $data;
}
Updated
Unfortunately it looks like there is not a way your going to be able to do what you want. Had you used the MCRYPT_RIJNDAEL_128 mode with a 256 byte key there may have been hope.
AES-256 and MCRYPT_RIJNDAEL_256 encryption are not the same thing, even though AES is basically Rijndael. It all has to do with the block size. What you want to do just is not compatible.
Your options are this:
Use a version of PHP that still has the MCRYPT libraries available and decrypt the passwords to a file and then encrypt them with your new encryption method.
A PECL option looks available that would allow you to install a pseudo version of MCRYPT with your latest version of PHP.
For just encrypting and decrypting your passwords OpenSSL should be fine, but
OpenSSL has limitation especially when you want to encrypt large amounts of data. It requires you to write additional code to break apart your data into smaller chunks before you encrypt and then put it back together after you decrypt.
I highly recommend that you skip OpenSSL and learn the LibSodium library which is now supported on the latest PHP versions.
http://php.net/manual/en/book.sodium.php
Here is a good page to read to get you started.
https://paragonie.com/blog/2015/05/using-encryption-and-authentication-correctly
Some more Libsodium resources.
https://github.com/paragonie/pecl-libsodium-doc/blob/v1/chapters/01-quick-start.md
Good Luck~
You have so many choices when it comes to encrypting data, so that's why you should implement it yourself. I recommend you the library diffuse/php-encryption, see this link for a detailed tutorial.
i have to replace deprecated function mcrypt_encrypt using openssl_encrypt.
My old mcrypt function use 'des' cipher and 'ecb' mode.
I tried all cipher options (openssl_get_cipher_methods) and i cant find same result. Help please
$key = '04647132';
$message = hex2bin('046471324B3680');
$mcrypt = base64_encode(mcrypt_encrypt('des', $key, $message, 'ecb'));
foreach (openssl_get_cipher_methods(true) as $cipher) {
$openSsl = base64_encode(#openssl_encrypt($message, $cipher, $key, OPENSSL_RAW_DATA));
if ($openSsl == $mcrypt) {
echo 'FOUND - ' . $cipher . ' = ' . $openSsl;
exit;
}
}
This is because of the different data padding - PKCS#5 for MCrypt and PKCS#7 for OpenSSL.
You can pre-pad $message yourself (either standard would work, but PKCS#7 is better) and use the OPENSSL_ZERO_PADDING flag together with OPENSSL_RAW_DATA. That also means you have to manually strip the padding after decryption - this is the case with all block cipher modes.
But this is the least of your problems ...
Nobody should be using using ECB, or DES today; you should move away from both as soon as possible. It's understandable if you maintain a legacy system, but you don't have to encrypt new data that way.
When you eventually move to another mode, don't ignore the IV requirement - the reason why ECB is bad is exactly because it doesn't utilize an IV.
Also, I know this is just sample code, but $key in your example isn't a proper key ... use random_bytes() to generate one.
All of this, and more issues that you don't even know about, could be resolved if you simply used a popular, well-vetted cryptography library - it would do all the work for you in one easy step.
Please do seriously consider this - even professional cryptographers prefer third-party libraries instead of writing their own code, and there's good reasons for that.
I have to store some information (Text) in an MySQL Column (MediumBLOB). It works but I am not sure if this way is secure enough.
Please don't wonder that the encryption key is randomized. It works as designed :)
$encryptionKeyRandom = str_random(12);
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND);
$encrypted_string = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $encryptionKeyRandom, $input['item'], MCRYPT_MODE_ECB, $iv);
$input['item'] = bin2hex($encrypted_string);
// Save to DB
Suggestions for better security/encryption are welcome.
mcrypt is outdated and hasn't been touched in quite a few years.
I'm not saying that it isn't useable, just that there are faster alternatives available cause quite frankly, mcrypt is slow.
openssl is a better alternative and works much like mcrypt, but the best library is in my opinion sodium. However sodium is not yet available in php 7 and maybe bringing it to 7.1. but should be for other versions.
https://www.virendrachandak.com/techtalk/encryption-using-php-openssl/ helped me migrating from mcrypt to openssl, take a look.
I'm in the process of rebuilding a PHP web app in Ruby on Rails, and would dearly love to avoid forcing all existing users to reset their encrypted passwords. The PHP site uses mcrypt_encrypt with AES-256-ECB, and I can't for the life of me get the same cipher text using ruby's OpenSSL. I can't decrypt them either (which is good in principle) since what's actually stored in the user DB is an MD5 hash of the AES cipher text.
I've read these previous, closely related questions and the very helpful answers:
How to make Ruby AES-256-CBC and PHP MCRYPT_RIJNDAEL_128 play well together
Part II: How to make Ruby AES-256-CBC and PHP MCRYPT_RIJNDAEL_128 play well together
including the pages referenced there, and if I understand correctly, the PHP and ruby implementations use different padding methods. Since I have to live with how things work on the PHP side, is there any way to force the same padding method on ruby/OpenSSL somehow? I'm using ruby 1.9.2-p180.
Here's the sample code in PHP:
$salt = "12345678901234567890123456789012";
$plain = "password";
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$cipher = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $salt, $plain, MCRYPT_MODE_ECB, $iv);
echo md5($cipher);
Output: 6337137fd88148250fd135a43dbeb84a
and in ruby:
require 'openssl'
salt = "12345678901234567890123456789012"
plain = "password";
c = OpenSSL::Cipher.new("AES-256-ECB")
c.encrypt
c.key = salt
cipher = c.update(plain)
cipher << c.final
puts Digest::MD5.hexdigest(cipher)
Output: 18dee36145c07ab83452aefe2590c391
Actually not in general an openssl solution but maybe it is ok for you to have a working example.
require 'mcrypt'
require 'openssl'
plaintext = 'password'
puts plaintext
key = '12345678901234567890123456789012'
enc = Mcrypt.new(:rijndael_256, :ecb, key, nil, :zeros)
encrypted = enc.encrypt(plaintext)
puts Digest::MD5.hexdigest(encrypted)
I used an additional gem(ruby-mcrypt). Seems to be an issue with openssl. Actually the issue seems to be that Openssl does not support zero padding and uses either no-padding or default-openssl-padding. Due to the fact that you use zero padding in php you must use zero padding also in ruby.
Output on my machine for the php script:
[~/test] ➔ php5 t.php
6337137fd88148250fd135a43dbeb84a
and for the ruby script:
[~/test] ➔ ruby t2.rb
password
6337137fd88148250fd135a43dbeb84a
and my ruby version:
[~/test] ➔ ruby -version
ruby 1.9.2p0 (2010-08-18 revision 29036) [i686-linux]
Hope this helps.
if key size is not standard on php side, you need to fill the key with zeros to next valid key size, in order to make ruby side works like this:
php_encrypted = string_encoded_with_php_mcrypt
key = "longerthan16butnot24".to_a.pack('a24')
enc = Mcrypt.new(:rijndael_256, :ecb, key, nil, :zeros)
enc.decrypt(php_encrypted)
In this case next valid key length is 24.
For :rijndael_256 valid key lengths are: 16, 24, 32
You can get more info on algorithms:
Mcrypt.algorithm_info(:rijndael_256
if you can use other encrypt methods, you can try TEA Block Encryption. I have adopted the method across Ruby, JS, ActionScript. It should work with PHP as well. github repo is here