webentwicklung-frage-antwort-db.com.de

Mit PHP verschlüsseln, mit Javascript entschlüsseln (cryptojs)

Ich habe Probleme mit der grundlegenden Verschlüsselung/Entschlüsselung. Ich habe überall nach einem Arbeitsbeispiel gesucht, aber noch kein Arbeitsbeispiel gefunden.

-Ich werde in PHP verschlüsseln und mit Cryptojs entschlüsseln

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js">
<?
$text = "this is the text here";
$key = "encryptionkey";

$msgEncrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_Rand));
$msgBase64 = trim(base64_encode($msgEncrypted));

echo "<h2>PHP</h2>";
echo "<p>Encrypted:</p>";
echo $msgEncrypted;
echo "<p>Base64:</p>";
echo $msgBase64;
 ?>

<p>AES Decrypt</p>
<script> 
    var key = 'encryptionkey';
    var encrypted = "<?php echo $msgBase64 ?>";
    //tried  var base64decode = CryptoJS.enc.Base64.parse(encrypted); 
    var decrypted = CryptoJS.AES.decrypt(encrypted, key);
    console.log( decrypted.toString(CryptoJS.enc.Utf8) );
</script>

Welchen Schritt vermisse ich?

28
user2769

Ich habe das gleiche verlangt und eine kurze Bibliothek geschrieben, die für CryptoJS 3.x und PHP mit OpenSL-Unterstützung funktioniert. Hoffe, das hilft, Quelle plus Beispieldateien hier https://github.com/brainfoolong/cryptojs-aes-php

PHP Lib

/**
* Decrypt data from a CryptoJS json encoding string
*
* @param mixed $passphrase
* @param mixed $jsonString
* @return mixed
*/
function cryptoJsAesDecrypt($passphrase, $jsonString){
    $jsondata = json_decode($jsonString, true);
    $salt = hex2bin($jsondata["s"]);
    $ct = base64_decode($jsondata["ct"]);
    $iv  = hex2bin($jsondata["iv"]);
    $concatedPassphrase = $passphrase.$salt;
    $md5 = array();
    $md5[0] = md5($concatedPassphrase, true);
    $result = $md5[0];
    for ($i = 1; $i < 3; $i++) {
        $md5[$i] = md5($md5[$i - 1].$concatedPassphrase, true);
        $result .= $md5[$i];
    }
    $key = substr($result, 0, 32);
    $data = openssl_decrypt($ct, 'aes-256-cbc', $key, true, $iv);
    return json_decode($data, true);
}

/**
* Encrypt value to a cryptojs compatiable json encoding string
*
* @param mixed $passphrase
* @param mixed $value
* @return string
*/
function cryptoJsAesEncrypt($passphrase, $value){
    $salt = openssl_random_pseudo_bytes(8);
    $salted = '';
    $dx = '';
    while (strlen($salted) < 48) {
        $dx = md5($dx.$passphrase.$salt, true);
        $salted .= $dx;
    }
    $key = substr($salted, 0, 32);
    $iv  = substr($salted, 32,16);
    $encrypted_data = openssl_encrypt(json_encode($value), 'aes-256-cbc', $key, true, $iv);
    $data = array("ct" => base64_encode($encrypted_data), "iv" => bin2hex($iv), "s" => bin2hex($salt));
    return json_encode($data);
}

Javascript Lib

var CryptoJSAesJson = {
    stringify: function (cipherParams) {
        var j = {ct: cipherParams.ciphertext.toString(CryptoJS.enc.Base64)};
        if (cipherParams.iv) j.iv = cipherParams.iv.toString();
        if (cipherParams.salt) j.s = cipherParams.salt.toString();
        return JSON.stringify(j);
    },
    parse: function (jsonStr) {
        var j = JSON.parse(jsonStr);
        var cipherParams = CryptoJS.lib.CipherParams.create({ciphertext: CryptoJS.enc.Base64.parse(j.ct)});
        if (j.iv) cipherParams.iv = CryptoJS.enc.Hex.parse(j.iv)
        if (j.s) cipherParams.salt = CryptoJS.enc.Hex.parse(j.s)
        return cipherParams;
    }
}

Beispiel Javascript

var encrypted = CryptoJS.AES.encrypt(JSON.stringify("value to encrypt"), "my passphrase", {format: CryptoJSAesJson}).toString();
var decrypted = JSON.parse(CryptoJS.AES.decrypt(encrypted, "my passphrase", {format: CryptoJSAesJson}).toString(CryptoJS.enc.Utf8));

Beispiel PHP

$encrypted = cryptoJsAesEncrypt("my passphrase", "value to encrypt");
$decrypted = cryptoJsAesDecrypt("my passphrase", $encrypted);
50
Brain Foo Long

Scott Arciszewski Sicherheitshinweis: Der Code in dieser Antwort ist anfällig für Angriffe durch ausgewählte Geheimtextanwendungen. Siehe stattdessen diese Antwort für sichere Verschlüsselung .

Hier ist ein funktionierendes Beispiel, wie Sie Ihre Zeichenfolge mit PHP verschlüsseln und mit CryptoJS entschlüsseln.

Auf der PHP Seite:

Verwenden Sie MCRYPT_RIJNDAEL_128 (nicht 256), um mit AES zu koppeln. Die 128 ist hier die Blockgröße, nicht die Schlüsselgröße.

Senden Sie auch das IV. Sie benötigen die IV zum Entschlüsseln.

$text = "this is the text here";
$key = "encryptionkey";

// Note: MCRYPT_RIJNDAEL_128 is compatible with AES (all key sizes)
$iv = random_bytes(16);

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

echo "iv:".base64_encode($iv)."\n";
echo "ciphertext:".base64_encode($ciphertext)."\n";

Hier ist eine Beispielausgabe eines Testlaufs:

iv:BMcOODpuQurUYGICmOqqbQ==
ciphertext:ZJAab8YtkRq5TL7uyIR7frM2b3krftJzn1pTqRTAda4=

Scott Arciszewski IMPORTANT: Da wir unseren Chiffretext nicht authentifizieren, wird die Entschlüsselung anfällig für das Auffüllen von Oracle-Angriffen . Siehe auch: authentifizierte Verschlüsselung in PHP .

Auf der CryptoJS-Seite:

Ihr Schlüssel besteht nur aus 13 ASCII druckbaren Zeichen, was sehr schwach ist. Mcrypt padded den Schlüssel für eine gültige Schlüsselgröße mit ZERO Bytes.

Konvertieren Sie den key und IV in Word-Arrays.

Ich hatte nicht viel Glück mit ciphertext als Word-Array zu entschlüsseln, also habe ich es im Base64 -Format gelassen.

CryptoJS = require("crypto-js")

// Mcrypt pads a short key with zero bytes
key = CryptoJS.enc.Utf8.parse('encryptionkey\u0000\u0000\u0000')

iv = CryptoJS.enc.Base64.parse('BMcOODpuQurUYGICmOqqbQ==')

// Keep the ciphertext in Base64 form
ciphertext = 'ZJAab8YtkRq5TL7uyIR7frM2b3krftJzn1pTqRTAda4='

/**
 * Scott Arciszewski DANGER DANGER WILL ROBINSON!
 *
 * This example code doesn't demonstrate AUTHENTICATED ENCRYPTION
 * and is therefore vulnerable to chosen-ciphertext attacks.
 *
 * NEVER USE THIS CODE TO PROTECT SENSITIVE DATA!
 */

// Mcrypt uses ZERO padding
plaintext = CryptoJS.AES.decrypt(ciphertext, key, { iv: iv, padding: CryptoJS.pad.ZeroPadding })

// I ran this in nodejs
process.stdout.write(CryptoJS.enc.Utf8.stringify(plaintext))
13
Jim Flood

Sie verwenden zwei Bibliotheken, die versuchen, Eingaben zu berücksichtigen, die - streng genommen - nicht gültig sind. Rijndael benötigt Schlüssel mit einer Länge von 16, 24 oder 32 Bytes mit zufälligen Bytes. Sie geben eine 13-stellige Zeichenfolge an. Mcrypt, die Bibliothek PHP, verwendet den String (vermutlich utf8-codiert) direkt als Binäreingang und zero füllt ihn mit den erforderlichen 32 Byte für MCRYPT_RIJNDAEL_256 auf. CryptoJS dagegen entscheidet, dass Sie etwas wie eine Passphrase eingegeben haben, und verwendet stattdessen eine Schlüsselableitungsfunktion, um einen 32-Byte-Schlüssel zu generieren.

Außerdem stimmen die verwendeten Verschlüsselungsalgorithmen nicht überein. Mcrypt verwendet eine selten implementierte Variante des ursprünglichen Rijndael für die 256-Bit-Version, während CryptoJS die weithin bekannte Variante AES256 des Rijndael-Vorschlags implementiert. Die 128-Bit-Version von (MCRYPT_RIJNDAEL_128 und AES128) ist jedoch identisch.

Das dritte Problem, dem Sie später gegenüberstehen, besteht darin, dass Mcrypt auch ein verrücktes Auffüllschema für die zu verschlüsselnden Daten verwendet. Da Rijndael eine Blockchiffre ist, kann es nur Blöcke mit 16, 24 oder 32 Byte verschlüsseln (je nach Variante - AES verwendet immer 16-Byte-Blöcke). Da solche Daten aufgefüllt werden müssen. Mcrypt tut dies auf eine nicht-injektive Weise, indem nur Nullen angehängt werden. Wenn Sie nur Strings codieren, ist dies für Sie kein so großes Problem, da utf8-codierte Strings niemals null Bytes enthalten. Sie können sie also einfach entfernen ( CryptoJS unterstützt sogar das native ).

Die einfachste Lösung für alle diese Probleme besteht darin, zu vermeiden, dass Sie selbst Kryptographie implementieren müssen (es wird ohnehin dringend davon abgeraten, ohne ein breites Wissen über das Thema zu besitzen). Können Sie stattdessen Ihre vertraulichen Informationen über https übertragen, wodurch TLS (früher als SSL bezeichnet) zum Verschlüsseln und Authentifizieren des Kanals verwendet wird?

3
Perseids

Gehen Sie nicht zu sehr auf die Codierung, verwenden Sie einfach den base64-Decoder

auf PHP-Code:

$encrypt_val=base64_encode("value");

und auf js nur:

var my_orignal_val = window.atob(passed_val);

Das reicht für Ihre Anforderung.

0
Kashif Anwar