mcrypt is deprecated, what is the alternative?

2019-01-02 18:20发布

The mcrypt-extension is deprecated will be removed in PHP 7.2 according to the comment posted here. So I am looking for an alternative way to encrypt passwords.

Right now I am using something like

mcrypt_encrypt(MCRYPT_RIJNDAEL_128, md5($key, true), $string, MCRYPT_MODE_CBC, $iv)

I need your opinion for the best/strongest way to encrypt passwords, the encrypted password should of course supported by PHP 7.xx and should also be decryptable because my customers do want to have an option to 'recover' their passwords without generating a new one.

9条回答
萌妹纸的霸气范
2楼-- · 2019-01-02 18:40

As pointed out, you should not be storing your users' passwords in a format that is decryptable. Reversable encryption provides an easy route for hackers to find out your users' passwords, which extends to putting your users' accounts at other sites at risk should they use the same password there.

PHP provides a pair of powerful functions for random-salted, one-way hash encryption — password_hash() and password_verify(). Because the hash is automatically random-salted, there is no way for hackers to utilize precompiled tables of password hashes to reverse-engineer the password. Set the PASSWORD_DEFAULT option and future versions of PHP will automatically use stronger algorithms to generate password hashes without you having to update your code.

查看更多
深知你不懂我心
3楼-- · 2019-01-02 18:43

Pure-PHP implementation of Rijndael exists with phpseclib available as composer package and works on PHP 7.3 (tested by me).

There's a page on the phpseclib docs, which generates sample code after you input the basic variables (cipher, mode, key size, bit size). It outputs the following for Rijndael, ECB, 256, 256:

a code with mycrypt

$decoded = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, ENCRYPT_KEY, $term, MCRYPT_MODE_ECB);

works like this with the library

$rijndael = new \phpseclib\Crypt\Rijndael(\phpseclib\Crypt\Rijndael::MODE_ECB);
$rijndael->setKey(ENCRYPT_KEY);
$rijndael->setKeyLength(256);
$rijndael->disablePadding();
$rijndael->setBlockLength(256);

$decoded = $rijndael->decrypt($term);

* $term was base64_decoded

查看更多
浅入江南
4楼-- · 2019-01-02 18:44

It's best practice to hash passwords so they are not decryptable. This makes things slightly more difficult for attackers that may have gained access to your database or files.

If you must encrypt your data and have it decryptable, a guide to secure encryption/decryption is available at https://paragonie.com/white-paper/2015-secure-php-data-encryption. To summarize that link:

  • Use Libsodium - A PHP extension
  • If you can't use Libsodium, use defuse/php-encryption - Straight PHP code
  • If you can't use Libsodium or defuse/php-encryption, use OpenSSL - A lot of servers will already have this installed. If not, it can be compiled with --with-openssl[=DIR]
查看更多
墨雨无痕
5楼-- · 2019-01-02 18:47

I was able to translate my Crypto object

  • Get a copy of php with mcrypt to decrypt the old data. I went to http://php.net/get/php-7.1.12.tar.gz/from/a/mirror, compiled it, then added the ext/mcrypt extension (configure;make;make install). I think I had to add the extenstion=mcrypt.so line to the php.ini as well. A series of scripts to build intermediate versions of the data with all data unencrypted.

  • Build a public and private key for openssl

    openssl genrsa -des3 -out pkey.pem 2048
    (set a password)
    openssl rsa -in pkey.pem -out pkey-pub.pem -outform PEM -pubout
    
  • To Encrypt (using public key) use openssl_seal. From what I've read, openssl_encrypt using an RSA key is limited to 11 bytes less than the key length (See http://php.net/manual/en/function.openssl-public-encrypt.php comment by Thomas Horsten)

    $pubKey = openssl_get_publickey(file_get_contents('./pkey-pub.pem'));
    openssl_seal($pwd, $sealed, $ekeys, [ $pubKey ]);
    $encryptedPassword = base64_encode($sealed);
    $key = base64_encode($ekeys[0]);
    

You could probably store the raw binary.

  • To Decrypt (using private key)

    $passphrase="passphrase here";
    $privKey = openssl_get_privatekey(file_get_contents('./pkey.pem'), $passphrase);
    // I base64_decode() from my db columns
    openssl_open($encryptedPassword, $plain, $key, $privKey);
    echo "<h3>Password=$plain</h3>";
    

P.S. You can't encrypt the empty string ("")

P.P.S. This is for a password database not for user validation.

查看更多
琉璃瓶的回忆
6楼-- · 2019-01-02 18:54

Just use @ before each mcrypt for example:

@mcrypt_module_open,
@mcrypt_get_block_size,
@mcrypt_generic_init
@mcrypt_generic
@mcrypt_generic_deinit

It will remove function mcrypt_module_open depriciated error and will work.

查看更多
人气声优
7楼-- · 2019-01-02 18:58

You can use phpseclib pollyfill package. You can not use open ssl or libsodium for encrypt/decrypt with rijndael 256. Another issue, you don't need replacement any code.

查看更多
登录 后发表回答