it-swarm.com.de

mcrypt ist veraltet, was ist die Alternative?

Die mcrypt-Erweiterung ist veraltet wird in PHP= 7.2 laut Kommentar entfernt hier . Also suche ich nach einer Alternative Passwörter zu verschlüsseln.

Im Moment benutze ich so etwas

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

Ich benötige Ihre Meinung für die beste/sicherste Art, Passwörter zu verschlüsseln. Das verschlüsselte Passwort sollte natürlich von PHP= 7.xx unterstützt werden und sollte auch entschlüsselbar sein, da meine Kunden eine Option dazu haben möchten "Wiederherstellen" ihrer Passwörter, ohne ein neues zu generieren.

84
Piet

Es wird empfohlen, Kennwörter zu hashen, damit sie nicht entschlüsselt werden können. Dies erschwert Angreifern den Zugriff auf Ihre Datenbank oder Dateien.

Wenn Sie Ihre Daten verschlüsseln und entschlüsseln müssen, finden Sie eine Anleitung zur sicheren Ver-/Entschlüsselung unter https://paragonie.com/white-paper/2015-secure-php-data-encryption . Um diesen Link zusammenzufassen:

  • Verwenden Sie Libsodium - A PHP Erweiterung
  • Wenn Sie Libsodium nicht verwenden können, verwenden Sie defuse/php-encryption - Straight PHP code
  • Wenn Sie Libsodium oder Defuse/PHP-Verschlüsselung nicht verwenden können, verwenden Sie OpenSSL - Auf vielen Servern ist dies bereits installiert. Wenn nicht, kann es mit --with-openssl [= DIR] kompiliert werden
38
Phil

Wie von @ rqLizard vorgeschlagen, können Sie openssl_encrypt / openssl_decrypt PHP Funktionen stattdessen, die eine viel bessere Alternative zum Implementieren von AES (The Advanced Encryption Standard), auch bekannt als Rijndael-Verschlüsselung, bieten.

Gemäß dem folgenden Scotts Kommentar bei php.net :

Wenn Sie 2015 Code zum Verschlüsseln/Verschlüsseln von Daten schreiben, sollten Sie openssl_encrypt() und openssl_decrypt() verwenden. Die zugrunde liegende Bibliothek (libmcrypt) wurde seit 2007 aufgegeben und ist weitaus schlechter als OpenSSL (das auf modernen Prozessoren AES-NI Nutzt und Cache-Timing-sicher ist).

Außerdem ist MCRYPT_RIJNDAEL_256 Nicht AES-256, Sondern eine andere Variante der Rijndael-Blockverschlüsselung. Wenn Sie AES-256 In mcrypt verwenden möchten, müssen Sie MCRYPT_RIJNDAEL_128 Mit einem 32-Byte-Schlüssel verwenden. OpenSSL macht klarer, welchen Modus Sie verwenden (d. H. aes-128-cbc Vs. aes-256-ctr).

OpenSSL verwendet außerdem PKCS7-Padding mit CBC-Modus anstelle des NULL-Byte-Paddings von mcrypt. Daher macht mcrypt Ihren Code mit höherer Wahrscheinlichkeit anfälliger für das Auffüllen von Oracle-Angriffen als OpenSSL.

Wenn Sie Ihre Chiffretexte nicht authentifizieren (Encrypt Then MAC), machen Sie es schließlich falsch.

Weitere Lektüre:

Codebeispiele

Beispiel 1

Beispiel für AES-authentifizierte Verschlüsselung im GCM-Modus für PHP 7.1+

<?php
//$key should have been previously generated in a cryptographically safe way, like openssl_random_pseudo_bytes
$plaintext = "message to be encrypted";
$cipher = "aes-128-gcm";
if (in_array($cipher, openssl_get_cipher_methods()))
{
    $ivlen = openssl_cipher_iv_length($cipher);
    $iv = openssl_random_pseudo_bytes($ivlen);
    $ciphertext = openssl_encrypt($plaintext, $cipher, $key, $options=0, $iv, $tag);
    //store $cipher, $iv, and $tag for decryption later
    $original_plaintext = openssl_decrypt($ciphertext, $cipher, $key, $options=0, $iv, $tag);
    echo $original_plaintext."\n";
}
?>

Beispiel # 2

Beispiel für AES-authentifizierte Verschlüsselung für PHP 5.6+

<?php
//$key previously generated safely, ie: openssl_random_pseudo_bytes
$plaintext = "message to be encrypted";
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
$iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext_raw = openssl_encrypt($plaintext, $cipher, $key, $options=OPENSSL_RAW_DATA, $iv);
$hmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary=true);
$ciphertext = base64_encode( $iv.$hmac.$ciphertext_raw );

//decrypt later....
$c = base64_decode($ciphertext);
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
$iv = substr($c, 0, $ivlen);
$hmac = substr($c, $ivlen, $sha2len=32);
$ciphertext_raw = substr($c, $ivlen+$sha2len);
$original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $key, $options=OPENSSL_RAW_DATA, $iv);
$calcmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary=true);
if (hash_equals($hmac, $calcmac))//PHP 5.6+ timing attack safe comparison
{
    echo $original_plaintext."\n";
}
?>

Beispiel # 3

Basierend auf den obigen Beispielen habe ich den folgenden Code geändert, der darauf abzielt, die Sitzungs-ID des Benutzers zu verschlüsseln:

class Session {

  /**
   * Encrypts the session ID and returns it as a base 64 encoded string.
   *
   * @param $session_id
   * @return string
   */
  public function encrypt($session_id) {
    // Get the MD5 hash salt as a key.
    $key = $this->_getSalt();
    // For an easy iv, MD5 the salt again.
    $iv = $this->_getIv();
    // Encrypt the session ID.
    $encrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $session_id, MCRYPT_MODE_CBC, $iv);
    // Base 64 encode the encrypted session ID.
    $encryptedSessionId = base64_encode($encrypt);
    // Return it.
    return $encryptedSessionId;
  }

  /**
   * Decrypts a base 64 encoded encrypted session ID back to its original form.
   *
   * @param $encryptedSessionId
   * @return string
   */
  public function decrypt($encryptedSessionId) {
    // Get the MD5 hash salt as a key.
    $key = $this->_getSalt();
    // For an easy iv, MD5 the salt again.
    $iv = $this->_getIv();
    // Decode the encrypted session ID from base 64.
    $decoded = base64_decode($encryptedSessionId);
    // Decrypt the string.
    $decryptedSessionId = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $decoded, MCRYPT_MODE_CBC, $iv);
    // Trim the whitespace from the end.
    $session_id = rtrim($decryptedSessionId, "\0");
    // Return it.
    return $session_id;
  }

  public function _getIv() {
    return md5($this->_getSalt());
  }

  public function _getSalt() {
    return md5($this->drupal->drupalGetHashSalt());
  }

}

in:

class Session {

  const SESS_CIPHER = 'aes-128-cbc';

  /**
   * Encrypts the session ID and returns it as a base 64 encoded string.
   *
   * @param $session_id
   * @return string
   */
  public function encrypt($session_id) {
    // Get the MD5 hash salt as a key.
    $key = $this->_getSalt();
    // For an easy iv, MD5 the salt again.
    $iv = $this->_getIv();
    // Encrypt the session ID.
    $ciphertext = openssl_encrypt($session_id, self::SESS_CIPHER, $key, $options=OPENSSL_RAW_DATA, $iv);
    // Base 64 encode the encrypted session ID.
    $encryptedSessionId = base64_encode($ciphertext);
    // Return it.
    return $encryptedSessionId;
  }

  /**
   * Decrypts a base 64 encoded encrypted session ID back to its original form.
   *
   * @param $encryptedSessionId
   * @return string
   */
  public function decrypt($encryptedSessionId) {
    // Get the Drupal hash salt as a key.
    $key = $this->_getSalt();
    // Get the iv.
    $iv = $this->_getIv();
    // Decode the encrypted session ID from base 64.
    $decoded = base64_decode($encryptedSessionId, TRUE);
    // Decrypt the string.
    $decryptedSessionId = openssl_decrypt($decoded, self::SESS_CIPHER, $key, $options=OPENSSL_RAW_DATA, $iv);
    // Trim the whitespace from the end.
    $session_id = rtrim($decryptedSessionId, '\0');
    // Return it.
    return $session_id;
  }

  public function _getIv() {
    $ivlen = openssl_cipher_iv_length(self::SESS_CIPHER);
    return substr(md5($this->_getSalt()), 0, $ivlen);
  }

  public function _getSalt() {
    return $this->drupal->drupalGetHashSalt();
  }

}

Um dies zu verdeutlichen, handelt es sich bei der obigen Änderung nicht um eine echte Konvertierung, da die beiden Verschlüsselungen eine unterschiedliche Blockgröße und unterschiedliche verschlüsselte Daten verwenden. Darüber hinaus unterscheidet sich die Standardauffüllung, MCRYPT_RIJNDAEL Unterstützt nur nicht standardmäßige Nullauffüllung. @ zaph


Zusätzliche Anmerkungen (aus den Kommentaren von @ zaph):

  • Rijndael 128 (MCRYPT_RIJNDAEL_128) entspricht [~ # ~] aes [~ # ~] ist jedoch Rijndael 256 (MCRYPT_RIJNDAEL_256) not AES-256 als 256 gibt eine Blockgröße von 256 Bit an, wohingegen [~ # ~] aes [~ # ~] hat nur eine Blockgröße: 128 Bit. Grundsätzlich wurde Rijndael mit einer Blockgröße von 256 Bit (MCRYPT_RIJNDAEL_256) Aufgrund der Auswahl der mcrypt -Entwickler fälschlicherweise benannt. @zaph
  • Rijndael mit einer Blockgröße von 256 ist möglicherweise weniger sicher als mit einer Blockgröße von 128 Bit, da letztere viel mehr Überprüfungen und Verwendungen erfahren hat. Zweitens wird die Interoperabilität dadurch beeinträchtigt, dass AES im Allgemeinen verfügbar ist, Rijndael mit einer Blockgröße von 256 Bit dagegen nicht.
  • Die Verschlüsselung mit unterschiedlichen Blockgrößen für Rijndael erzeugt unterschiedliche verschlüsselte Daten.

    Zum Beispiel definiert MCRYPT_RIJNDAEL_256 (Nicht äquivalent zu AES-256) Eine andere Variante der Rijndael-Blockchiffre mit einer Größe von 256 Bit und einer Schlüsselgröße basierend auf dem übergebenen Schlüssel, wobei aes-256-cbc Ist Rijndael mit einer Blockgröße von 128 Bit und einer Schlüsselgröße von 256 Bit. Daher verwenden sie unterschiedliche Blockgrößen, die völlig unterschiedliche verschlüsselte Daten erzeugen, da mcrypt die Nummer zur Angabe der Blockgröße verwendet, wobei OpenSSL die Nummer zur Angabe der Schlüsselgröße verwendet (AES hat nur eine Blockgröße von 128 Bit). AES ist also im Grunde Rijndael mit einer Blockgröße von 128 Bit und Schlüsselgrößen von 128, 192 und 256 Bit. Daher ist es besser, AES zu verwenden, das in OpenSSL Rijndael 128 heißt.

23
kenorb

Die reine PHP-Implementierung von Rijndael ist mit phpseclib als composer package verfügbar und funktioniert mit PHP 7.3 (von mir getestet)).

Es gibt eine Seite in den phpseclib-Dokumenten, die generiert Beispielcode nachdem Sie die Basisvariablen (Chiffre, Modus, Schlüsselgröße, Bitgröße) eingegeben haben. Es gibt Folgendes für Rijndael, ECB, 256, 256 aus:

ein code mit mycrypt

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

funktioniert so mit der bibliothek

$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 war base64_decoded

7
Pentium10

Sie können phpseclib pollyfill package verwenden. Sie können open ssl oder libsodium nicht zum Ver-/Entschlüsseln mit rijndael 256 verwenden. Ein weiteres Problem ist, dass Sie keinen Code ersetzen müssen.

5

Sie sollten OpenSSL über mcrypt verwenden, da es aktiv entwickelt und gewartet wird. Es bietet eine bessere Sicherheit, Wartbarkeit und Portabilität. Zweitens führt es die AES-Verschlüsselung/-Entschlüsselung viel schneller durch. Standardmäßig wird PKCS7-Padding verwendet, Sie können jedoch OPENSSL_ZERO_PADDING wenn du es brauchst. Zur Verwendung mit einem 32-Byte-Binärschlüssel können Sie aes-256-cbc was viel offensichtlicher ist als MCRYPT_RIJNDAEL_128.

Hier ist das Codebeispiel mit Mcrypt:

Nicht authentifizierte AES-256-CBC-Verschlüsselungsbibliothek in Mcrypt mit PKCS7-Auffüllung.

/**
 * This library is unsafe because it does not MAC after encrypting
 */
class UnsafeMcryptAES
{
    const CIPHER = MCRYPT_RIJNDAEL_128;

    public static function encrypt($message, $key)
    {
        if (mb_strlen($key, '8bit') !== 32) {
            throw new Exception("Needs a 256-bit key!");
        }
        $ivsize = mcrypt_get_iv_size(self::CIPHER);
        $iv = mcrypt_create_iv($ivsize, MCRYPT_DEV_URANDOM);

        // Add PKCS7 Padding
        $block = mcrypt_get_block_size(self::CIPHER);
        $pad = $block - (mb_strlen($message, '8bit') % $block, '8bit');
        $message .= str_repeat(chr($pad), $pad);

        $ciphertext = mcrypt_encrypt(
            MCRYPT_RIJNDAEL_128,
            $key,
            $message,
            MCRYPT_MODE_CBC,
            $iv
        );

        return $iv . $ciphertext;
    }

    public static function decrypt($message, $key)
    {
        if (mb_strlen($key, '8bit') !== 32) {
            throw new Exception("Needs a 256-bit key!");
        }
        $ivsize = mcrypt_get_iv_size(self::CIPHER);
        $iv = mb_substr($message, 0, $ivsize, '8bit');
        $ciphertext = mb_substr($message, $ivsize, null, '8bit');

        $plaintext = mcrypt_decrypt(
            MCRYPT_RIJNDAEL_128,
            $key,
            $ciphertext,
            MCRYPT_MODE_CBC,
            $iv
        );

        $len = mb_strlen($plaintext, '8bit');
        $pad = ord($plaintext[$len - 1]);
        if ($pad <= 0 || $pad > $block) {
            // Padding error!
            return false;
        }
        return mb_substr($plaintext, 0, $len - $pad, '8bit');
    }
}

Und hier ist die Version, die mit OpenSSL geschrieben wurde:

/**
 * This library is unsafe because it does not MAC after encrypting
 */
class UnsafeOpensslAES
{
    const METHOD = 'aes-256-cbc';

    public static function encrypt($message, $key)
    {
        if (mb_strlen($key, '8bit') !== 32) {
            throw new Exception("Needs a 256-bit key!");
        }
        $ivsize = openssl_cipher_iv_length(self::METHOD);
        $iv = openssl_random_pseudo_bytes($ivsize);

        $ciphertext = openssl_encrypt(
            $message,
            self::METHOD,
            $key,
            OPENSSL_RAW_DATA,
            $iv
        );

        return $iv . $ciphertext;
    }

    public static function decrypt($message, $key)
    {
        if (mb_strlen($key, '8bit') !== 32) {
            throw new Exception("Needs a 256-bit key!");
        }
        $ivsize = openssl_cipher_iv_length(self::METHOD);
        $iv = mb_substr($message, 0, $ivsize, '8bit');
        $ciphertext = mb_substr($message, $ivsize, null, '8bit');

        return openssl_decrypt(
            $ciphertext,
            self::METHOD,
            $key,
            OPENSSL_RAW_DATA,
            $iv
        );
    }
}

Quelle: Wenn Sie das Wort MCRYPT in Ihren PHP Code eingeben, tun Sie es falsch .

3
kenorb

Wie bereits erwähnt, sollten Sie die Kennwörter Ihrer Benutzer nicht in einem entschlüsselbaren Format speichern. Die umkehrbare Verschlüsselung bietet Hackern eine einfache Möglichkeit, die Kennwörter ihrer Benutzer herauszufinden. Sie kann auch dazu führen, dass die Konten ihrer Benutzer an anderen Standorten gefährdet werden, wenn sie dort dasselbe Kennwort verwenden.

PHP bietet ein paar leistungsstarke Funktionen für zufällige, einseitige Hash-Verschlüsselung - password_hash() und password_verify(). Da der Hash automatisch zufällig gesalzen wird, besteht für Hacker keine Möglichkeit, vorkompilierte Tabellen mit Passwort-Hashes zu verwenden, um das Passwort rückzuentwickeln. Setze das PASSWORD_DEFAULT Option und zukünftige Versionen von PHP verwendet automatisch stärkere Algorithmen, um Passwort-Hashes zu generieren, ohne dass Sie Ihren Code aktualisieren müssen.

1

Sie sollten openssl_encrypt() function verwenden.

1
rqLizard

Wie in den anderen Antworten beschrieben, ist die beste Lösung, die ich gefunden habe, die Verwendung von OpenSSL. Es ist in PHP eingebaut und Sie benötigen keine externe Bibliothek. Hier einige einfache Beispiele:

So verschlüsseln Sie:

function encrypt($key, $payload) {
  $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
  $encrypted = openssl_encrypt($payload, 'aes-256-cbc', $key, 0, $iv);
  return base64_encode($encrypted . '::' . $iv);
}

Zum Entschlüsseln:

function decrypt($key, $garble) {
    list($encrypted_data, $iv) = explode('::', base64_decode($garble), 2);
    return openssl_decrypt($encrypted_data, 'aes-256-cbc', $key, 0, $iv);
}

Referenzlink: https://www.shift8web.ca/2017/04/how-to-encrypt-and-execute-your-php-code-with-mcrypt/

1

Ich konnte mein Crypto-Objekt übersetzen

  • Holen Sie sich eine Kopie von PHP mit mcrypt, um die alten Daten zu entschlüsseln. Ich ging zu http://php.net/get/php-7.1.12.tar.gz/from/a/mirror , kompilierte es und fügte dann die Erweiterung ext/mcrypt hinzu (configure; make) ; make install). Ich glaube, ich musste auch die Zeile extenstion = mcrypt.so zur php.ini hinzufügen. Eine Reihe von Skripten zum Erstellen von Zwischenversionen der Daten, wobei alle Daten unverschlüsselt sind.

  • Erstellen Sie einen öffentlichen und einen privaten Schlüssel für openssl

    openssl genrsa -des3 -out pkey.pem 2048
    (set a password)
    openssl rsa -in pkey.pem -out pkey-pub.pem -outform PEM -pubout
    
  • Verwenden Sie zum Verschlüsseln (mit öffentlichem Schlüssel) openssl_seal. Nach dem, was ich gelesen habe, ist openssl_encrypt mit einem RSA-Schlüssel auf 11 Bytes kürzer als die Schlüssellänge begrenzt. (Siehe http://php.net/manual/en/function.openssl-public-encrypt.php Kommentar von 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]);
    

Sie könnten wahrscheinlich die rohe Binärdatei speichern.

  • Entschlüsseln (mit privatem Schlüssel)

    $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. Sie können die leere Zeichenfolge ("") nicht verschlüsseln

P.P.S. Dies gilt für eine Kennwortdatenbank, nicht für die Benutzerüberprüfung.

0