Verwendung des Initialisierungsvektors in openssl_encrypt

74

Ich habe mir diese Frage angesehen und wollte es für mich tun. Als ich diesen Code ausgeführt habe (direkt aus dieser Antwort entnommen ):

$textToEncrypt = "My super secret information.";
$encryptionMethod = "AES-256-CBC";  // AES is used by the U.S. gov't to encrypt top secret documents.
$secretHash = "25c6c7ff35b9979b151f2136cd13b0ff";

//To encrypt
$encryptedMessage = openssl_encrypt($textToEncrypt, $encryptionMethod, $secretHash, '1234567812345678');

//To Decrypt
$decryptedMessage = openssl_decrypt($encryptedMessage, $encryptionMethod, $secretHash);

//Result
echo "Encrypted: $encryptedMessage <br>Decrypted: $decryptedMessage";

Ich bekomme jedoch die Warnung

openssl_encrypt(): Using an empty Initialization Vector (iv) is potentially insecure and not recommended

Also habe ich mir die Dokumente angesehen , aber es gibt keine Dokumentation. Ich habe diesen Kommentar gefunden , aber immer noch nicht erwähnt, was der Initialisierungsvektor sein sollte und wie ich ihn verwenden sollte. Kann mich jemand aufklären?

Ich weiß, ich hätte noch mehr googeln können, aber Stackoverflow taucht in so vielen Suchergebnissen an erster Stelle auf, dass ich dachte, diese Frage könnte für alle anderen nützlich sein, die dieses Problem hatten.

Alfo
quelle
2
Haben Sie nachgeschlagen, was Initialisierungsvektor bedeutet?
Jared Farrish
Ja, aber ich habe mich gefragt, wie dies am besten in PHP implementiert werden sollte.
Alfo
1
Eine leere Infusion ist schlecht . Dies hat vor einiger Zeit zum gesamten Debian / OpenSSH-Fiasko geführt.
Ignacio Vazquez-Abrams
Versuchen Sie: php.net/manual/en/function.openssl-encrypt.php#99188 Siehe das letzte Argument , $iv.
Jared Farrish
@JaredFarrish ja, wie gesagt ich habe die docs gelesen. Es verrät nichts über das Problem, mit dem ich konfrontiert bin.
Alfo

Antworten:

133

Eine IV ist im Allgemeinen eine Zufallszahl, die garantiert, dass der verschlüsselte Text eindeutig ist.

Um zu erklären, warum es benötigt wird, tun wir so, als hätten wir eine Datenbank mit Namen von Personen, die mit dem Schlüssel 'secret' und ohne IV verschlüsselt sind.

1 John dsfa9p8y098hasdf
2 Paul po43pokdfgpo3k4y
3 John dsfa9p8y098hasdf

Wenn John 1 seinen Chiffretext (dsfa9p8y098hasdf) kennt und Zugriff auf die anderen Chiffretexte hat, kann er leicht andere Personen mit dem Namen John finden.

Tatsächlich wird in einem Verschlüsselungsmodus, für den eine IV erforderlich ist, immer eine verwendet. Wenn Sie keine IV angeben, wird diese automatisch auf eine Reihe von Null-Bytes festgelegt. Stellen Sie sich das erste Beispiel mit einer konstanten IV (00000000) vor.

1 John dsfa9p8y098hasdf 00000000
2 Paul po43pokdfgpo3k4y 00000000
3 John dsfa9p8y098hasdf 00000000

Um wiederholte Chiffretexte zu vermeiden, können wir die Namen mit demselben 'geheimen' Schlüssel und denselben zufälligen IVs verschlüsseln:

1 John sdf875n90mh28458 45gh3546
2 Paul fg9087n5b60987nf 56897ngq
3 John gjhn0m89456vnler 8907345f

Wie Sie sehen können, sind die beiden 'John'-Chiffretexte jetzt unterschiedlich. Jede IV ist einzigartig und hat den Verschlüsselungsprozess beeinflusst, wodurch auch das Endergebnis einzigartig wird. John 1 hat jetzt keine Ahnung, wie der Name von Benutzer 3 lautet.

Die Entschlüsselung erfordert natürlich die Verwendung derselben IV, mit der der Text verschlüsselt wurde, weshalb er in der Datenbank gespeichert werden muss. Die IV ist ohne den Schlüssel nicht von Nutzen, so dass das Übertragen oder Speichern mit dem verschlüsselten Text keine Rolle spielt.

Dies ist ein zu stark vereinfachtes Beispiel, aber die Wahrheit ist, dass die Nichtverwendung von IVs schwerwiegende Sicherheitsfolgen hat.


Jetzt scheint Ihr Code die IV (1234567812345678) einzustellen, verwendet sie jedoch nicht bei der Entschlüsselung. Das wird sicher scheitern.

Möglicherweise möchten Sie auch einige der IV-Generierungsfunktionen von PHP verwenden. Ich denke, das sollte für Sie funktionieren:

$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$encryptedMessage = openssl_encrypt($textToEncrypt, $encryptionMethod, $secretHash, 0, $iv);
$decryptedMessage = openssl_decrypt($encryptedMessage, $encryptionMethod, $secretHash, 0, $iv);

Zum Speichern / Übertragen können Sie einfach den IV- und Chiffretext wie folgt verketten:

$data = $iv.$encryptedMessage;

Ziehen Sie dann beim Abrufen die Infusion zur Entschlüsselung heraus:

$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = substr($data, 0, $iv_size);
$decryptedMessage = openssl_decrypt(substr($data, $iv_size), $encryptionMethod, $secretHash, 0, $iv);

Weitere Informationen finden Sie in der Mcrypt-Bibliothek von PHP. Es ist ziemlich voll ausgestattet und enthält unzählige Beispiele, von denen viele Ihnen bei der Implementierung von OpenSSh-Verschlüsselung helfen können. http://php.net/manual/en/function.mcrypt-encrypt.php

Joel Mellon
quelle
4
Tolle Erklärung. Ich glaube, Sie vermissen den 4. Parameter für openssl_encrypt / decrypt. IV ist der 5.
Thilo Savage
2
Wenn Sie die verschlüsselten Daten über ein HTML-Formular senden möchten, müssen Sie den PHP-Code mit base64_encode / base64_decode buchen und das Formular enctype = "multipart / form-data" festlegen, damit Sie seit dem keine Codierungsprobleme mehr haben IV ist binär.
Beau
2
@kovshenin Nun, eigentlich nicht. Eine IV ist technisch weniger zufällig als einzigartig. Zufällige (insbesondere pseudozufällige) Funktionen können denselben String generieren, und Verschlüsselung kann denselben Chiffretext mit unterschiedlichen Schlüsseln und / oder unterschiedlichen Daten generieren. In Ihrem Fall mag es Ihnen gut gehen, aber wenn Sie wirklich garantieren müssen, dass sie einzigartig sind, ist das Einstellen einer IV (richtig!) Ungefähr so ​​gut wie möglich.
Joel Mellon
2
es muss seinMCRYPT_RIJNDAEL_128
CIRCLE
4
mcrypt ist veraltet
Márcio Rossato