Ersetzen Sie Mcrypt durch OpenSSL

Lesezeit: 7 Minuten

Ersetzen Sie Mcrypt durch OpenSSL
maTu

Derzeit haben wir eine Mcrypt-Implementierung auf unseren Systemen, um einige sensible Daten in unserer PHP-Anwendung zu verschlüsseln. Jetzt haben wir eine neue Anforderung, dass wir das Crypt-Modul in openssl ändern müssen. Eine andere wichtige Sache ist, dass wir die Chiffre Blowfish und den Modus ecb verwenden. Also fing ich an zu testen, was Unterschiede sind und wie ich mcrypt verschlüsselte Strings mit openssl entschlüsseln kann.

Ich habe die Standard-PHP-Funktion verwendet:

  • mcrypt_encrypt vs. openssl_encrypt
  • mcrypt_decrypt vs. openssl_decrypt

Beide Methoden liefern unterschiedliche Ergebnisse. Zweitens sind in der angegebenen Chiffre (Blowfish) und im Modus (ECB) in beiden Typen unterschiedliche IV-Längen erforderlich (openssl=0 und mcrypt=56).

Weiß jemand, wie ich ohne großen Migrationsaufwand die Module einfach wechseln kann?

Vielen Dank im Voraus!

AKTUALISIEREN:

Hier ist der Code, den ich getestet habe:

<?php 

function say($message){
    if(!is_string($message)){
        if(!isset($_SERVER["HTTP_USER_AGENT"])) echo "<pre>";
        echo var_export($message, true) . ((!isset($_SERVER["HTTP_USER_AGENT"]) ? "\n" : "<br />"));
        if(!isset($_SERVER["HTTP_USER_AGENT"])) echo "</pre>";
    }else{
        echo $message . ((!isset($_SERVER["HTTP_USER_AGENT"]) ? "\n" : "<br />"));
    }
}

say("= Begin raw encryption");
$key    = "anotherpass";
$str    = "does it work";

say("  Params:");
say("  - String to encrypt '".$str."'");
say("  - Key: ".$key);
say("");


$params = array(
    "openssl"  => array(
        "cipher"    => "BF",
        "mode"      => "ECB",
    ),
    "mcrypt" => array(
        "cipher"    => "blowfish", 
        "mode"      => "ecb",
    ),
);

say("= Mcrypt");
$handler = mcrypt_module_open($params['mcrypt']['cipher'], '', $params['mcrypt']['mode'], '');
$iv      = mcrypt_create_iv (mcrypt_enc_get_iv_size($handler), MCRYPT_RAND);
$keysize = mcrypt_enc_get_key_size($handler);
mcrypt_generic_init($handler,$key,"\0\0\0\0\0\0\0\0");
say("  Params:");
say("  - InitVector   ".bin2hex($iv)." (bin2hex)");
say("  - Max keysize  ".$keysize);
say("  - Cipher       ".$params['mcrypt']['cipher']);
say("  - Mode         ".$params['mcrypt']['mode']);
say("");
say("  Encryption:");
$m_encrypted = mcrypt_generic($handler, $str);
$m_decrypted = mdecrypt_generic($handler, $m_encrypted);
say("  - Encrypted   ".bin2hex($m_encrypted)." (bin2hex)");
say("  - Descrypted  ".$m_decrypted);
say("");


say("= Openssl");
say("  Params:");
say("  - InitVector   not needed");
say("  - Max keysize  ".openssl_cipher_iv_length($params['openssl']['cipher']."-".$params['openssl']['mode']));
say("  - Cipher       ".$params['openssl']['cipher']);
say("  - Mode         ".$params['openssl']['mode']);
say("");
say("  Encryption:");
$o_encrypted = openssl_encrypt($str,$params['openssl']['cipher']."-".$params['openssl']['mode'],$key,true);
$o_decrypted = openssl_decrypt($o_encrypted,$params['openssl']['cipher']."-".$params['openssl']['mode'],$key,true);
say("  - Encrypted   ".bin2hex($o_encrypted)." (bin2hex)");
say("  - Descrypted  ".$o_decrypted);

Und das ist mein Ergebnis:

= Begin raw encryption
  Params:
  - String to encrypt 'does it work'
  - Key: anotherpass

= Mcrypt
  Params:
  - InitVector   06a184909d7bf863 (bin2hex)
  - Max keysize  56
  - Cipher       blowfish
  - Mode         ecb

  Encryption:
  - Encrypted   0e93dce9a6a88e343fe5f90d1307684c (bin2hex)
  - Descrypted  does it work

= Openssl
  Params:
  - InitVector   not needed
  - Max keysize  0
  - Cipher       BF
  - Mode         ECB

  Encryption:
  - Encrypted   213460aade8f9c14d8d51947b8231439 (bin2hex)
  - Descrypted  does it work

Vielleicht jetzt schon Ideen?

Danke!

  • Sie müssen entweder ein Migrationsskript ausführen, das die aktuellen Daten mit mcrypt entschlüsselt und sie dann erneut mit openssl verschlüsselt, oder Sie müssen eine Methode implementieren, mit der Sie wissen, welche Verschlüsselungs-/Entschlüsselungsfunktionen für jedes Element von verwendet werden müssen Daten, und ändern Sie sie nach Bedarf von mcrypt in openssl, wenn Sie das nächste Mal auf einige mit mcrypt verschlüsselte Daten zugreifen.

    – Jon

    22. August 2012 um 14:04 Uhr

  • So wie ich es verstehe, verwenden mcrypt und open_ssl unterschiedliche Schlüsselableitungsmethoden, und Jon hat also Recht, Sie müssen entweder migrieren, indem Sie entschlüsseln und dann verschlüsseln oder Daten markieren, damit sie beim nächsten Zugriff migriert werden.

    – Reid Johnson

    31. Oktober 2012 um 17:13 Uhr

  • Ich frage mich, warum IB im ECB-Modus erforderlich ist. Siehe die Beschreibung des ECB-Modus unter en.wikipedia.org/wiki/Block_cipher_modes_of_operation.

    – doptimusprime

    6. April 2013 um 3:39 Uhr

  • Siehe auch Upgrade meiner Verschlüsselungsbibliothek von Mcrypt auf OpenSSL und Vorbereitung auf das Entfernen von Mcrypt in PHP 7.2

    – jww

    21. April 2017 um 17:49 Uhr

Blowfish ist die Blockchiffre. Es erfordert, dass die Daten vor der Verschlüsselung aufgefüllt werden. OpenSSL verwendet PKCS#7 und mcrypt verwendet PKCS#5. Verschiedene Füllalgorithmen für Daten. Die minimale PKCS#5-Auffülllänge ist 0, für PKCS#7 ist sie 1 (Wikipedia). Schauen Sie sich dieses Beispiel an (ich habe Eingabedaten manuell aufgefüllt für mcrypt_encrypt() im PKCS#7-Stil):

<?php 

$key = "anotherpassword1";
$str = "does it work 12";

$enc = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $str."\1", MCRYPT_MODE_ECB);
$dec = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $enc, MCRYPT_MODE_ECB);
echo(bin2hex($enc).PHP_EOL);
var_dump($dec);

$enc = openssl_encrypt($str, 'bf-ecb', $key, true);
$dec = openssl_decrypt($enc, 'bf-ecb', $key, true);
echo(bin2hex($enc).PHP_EOL);
var_dump($dec);

?>

Es ist unmöglich, mit mcrypt_encrypt() verschlüsselte openssl_decrypt()-Daten zu öffnen, es sei denn, es wurde zuvor manuelles Datenauffüllen mit PKCS#7 vorgenommen mcrypt_encrypt() hieß.

In Ihrem Fall gibt es nur eine Möglichkeit – die Daten neu zu verschlüsseln.

PS: Es gibt einen Fehler in Ihrer Quelle – der ECB-Modus verwendet IV überhaupt nicht (Wikipedia)

  • Danke, dieser Hinweis hat mir geholfen, Rijndael-128/AES-128 zwischen MCrypt und OpenSSL kompatibel zu machen. Leider funktioniert es jedoch nicht für Blowfish –

    – Narf

    30. Januar 2014 um 13:08 Uhr

  • Es stellt sich heraus, dass es für Blowfish funktioniert, ABER die Schlüsselgröße muss mindestens 16 Bytes betragen (Wikipedia-Artikel für Blowfish sagt, dass es weniger unterstützt).

    – Narf

    5. Februar 2014 um 12:14 Uhr

  • Das liegt am Padding in PKCS#7

    – Kleeblatt

    9. Februar 2014 um 18:41 Uhr

  • @clover PKCS # 7 und PKCS # 5 sind im Wesentlichen gleich und in der Implementierung gleich, es ist nur so, dass faule Entwickler die wiederverwendet haben PKCS#5 Bezeichner, anstatt einen PKCS#7-Bezeichner hinzuzufügen. Bitte korrigieren Sie die Antwort und kommentieren Sie. Sehen PKCS#7-Auffüllung: PKCS#5-Padding ist identisch mit PKCS#7-Padding, außer dass es nur für Blockchiffren definiert wurde, die eine Blockgröße von 64 Bit (8 Byte) verwenden. In der Praxis können die beiden austauschbar verwendet werden.

    – zaph

    9. März 2018 um 22:51 Uhr


  • @clover Siehe auch: Was ist der Unterschied zwischen PKCS#5-Padding und PKCS#7-Padding?: Viele kryptografische Bibliotheken verwenden eine Kennung, die PKCS#5 oder PKCS#7 angibt, um denselben Auffüllmechanismus zu definieren.

    – zaph

    9. März 2018 um 22:55 Uhr


Falls Sie mit openssl verschlüsseln möchten und beim Entschlüsseln mit mcrypt immer noch das gleiche Ergebnis erhalten, als ob Sie es mit mcrypt verschlüsselt hätten, müssen Sie die Eingabezeichenfolge manuell mit Nullen auffüllen, bevor Sie sie mit openssl_encrypt verschlüsseln, und übergeben Sie die OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING Optionen.

$str="encrypt me";
$cipher="AES-256-CBC";
$key = '01234567890123456789012345678901';
$opts = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING;
$iv_len = 16;
$str_len = mb_strlen($str, '8bit');
$pad_len = $iv_len - ($str_len % $iv_len);
$str .= str_repeat(chr(0), $pad_len);
$iv = openssl_random_pseudo_bytes($iv_len);


$encrypted = openssl_encrypt($str, $cipher, $key, $opts, $iv);

Das Entschlüsseln mit mcrypt_decrypt funktioniert dann genauso, als ob Sie auch mcrypt zum Verschlüsseln verwendet hätten.

mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $encrypted, MCRYPT_MODE_CBC, $iv)

1641992713 907 Sollte ich fur jeden Thread eine separate ScriptEngine und CompiledScript Instanz
Shawn

Für kürzere Schlüssel sollten Sie zyklische Schlüssel für Openssl erstellen, wenn Sie Blowfish von mcrypt migrieren.

function make_openssl_blowfish_key($key)
{
    if("$key" === '')
        return $key;

    $len = (16+2) * 4;
    while(strlen($key) < $len) {
        $key .= $key;
    }
    $key = substr($key, 0, $len);
    return $key;
}

Sehen: https://bugs.php.net/bug.php?id=72362

Siehe: Wechsel von mcrypt mit Blowfish & ECB zu OpenSSL

@clover hat recht, dass die Standardauffüllung für Blowfish zwischen mcrypt und Openssl unterschiedlich ist, ist aber falsch, dass dies nicht möglich ist. Wenn Sie die verwenden OPENSSL_ZERO_PADDING Option für die Entschlüsselung sind die beiden tatsächlich kompatibel:

openssl_decrypt($data, 'bf-ecb', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);

1002070cookie-checkErsetzen Sie Mcrypt durch OpenSSL

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy