HdRs Blog

yet another blog

RSA mit JAVA und PHP – Teil 2 (PHP -> JAVA)

In dem Artikel RSA mit JAVA und PHP – Teil 1 (JAVA -> PHP) habe ich bereits die RSA Verschlüsselung in JAVA und die dazugehörige Entschlüsselung in PHP dargestellt. In diesem Artikel geht es nun um die andere Richtung, also der Verschlüsselung in PHP und dem Entschlüsseln in JAVA. Für die folgenden Codebeispiele benötigen wir die Schlüsel die wir bereits in dem anderen Blogeintrag angelegt haben:

  • clientPublicKey.pem
  • clientPrivateKey.der
  1. Öffentlichen Schlüssel des Clients in PHP importieren, Daten verschlüsseln und in Datei abspeichern:
    PHP
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?php
    $publicKey = openssl_get_publickey(file_get_contents('keys/clientPublicKey.pem'));
    $data = "Geheimer Text....";
    $encrypted = '';
    openssl_public_encrypt($data, $encrypted, $publicKey, OPENSSL_PKCS1_PADDING);
    file_put_contents('/tmp/encrypted', $encrypted);

  2. Privaten Schlüssel in Java importieren:

    Java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    File privKeyFile = new File("keys/clientPrivateKey.der");
    byte[] buffer = new byte[(int) privKeyFile.length()];
    DataInputStream in = new DataInputStream(new FileInputStream(privKeyFile));
    in.readFully(buffer);
    in.close();
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory.generatePrivate(new PKCS8EncodedKeySpec(buffer));

  3. Verschlüsselte Datei lesen:

    Java
    1
    2
    3
    4
    5
    6
    File cryptedData = new File("/tmp/encrypted");
    buffer = new byte[(int) cryptedData.length()];
            
    in = new DataInputStream(new FileInputStream(cryptedData));
    in.readFully(buffer);
    in.close();

  4. Entschlüsseln:

    Java
    1
    2
    3
    4
    5
    6
    7
    8
    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
    cipher.init(Cipher.DECRYPT_MODE, privateKey);
    byte[] decrypted = cipher.doFinal(buffer);
    String data = new String(decrypted);
    System.out.println(data);

  5. Sich über die Ausgabe “Geheimer Text….” freuen.

Eine kleine Anmerkung zur RSA Verschlüsselung allgemein, RSA ist im Vergleich zu symmetrischen Verschlüsselungen wie z.B. AES um ca. Faktor 1000 langsamer. Daher eignet sich RSA nur zum verschlüsseln kleiner Daten, für größere Datein verwendet man daher in der Regel ein “Hybrides Verfahren” indem man die Daten mit z.B. AES verschlüsselt und nur den Schlüssel dann mit RSA. So kann der Empfänger dann mit RSA den AES-Schlüssel entschlüsseln und mit diesem dann die Daten an sich. So ein hybrides Verfahren im Zusammenhang mit JAVA,PHP und RSA werde ich in einem meiner nächsten Posts vorstellen.

CakePHP 2 und PHPUnit

Beim Updaten auf CakePHP 2.0.5 und PHPUnit 3.6.7 ist mir beim Schreiben von Tests aufgefallen dass ich keine debug-Meldungen mehr angezeigt bekomme. Außer debug() funktioniert auch kein print_r() oder echo() mehr. Nach einiger Suche bin ich schließlich auf diesen Blogeintrag gestoßen: Unit-Testing Tips for 2.0 and PHPUnit

Kurz zusammengefaßt lässt sich sagen, dass PHPUnit ab 3.6 alle Ausgaben schluckt, für die CLI Veriante schlagen die CakePHP-Entwickler vor –debug zu verwenden. Da ich aber meine Tests lieber im Browser anschaue war das natürlich auch keine Option.
Die Lösung für mein Problem war dann schließlich eine eigene debug-Methode zu schreiben:

debug
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
public function debug($data, $pre = true) {
$data = print_r($data, true);
if ($pre)
$data = "<pre>" . $data . "</pre>";
echo $data;
if (empty($_SERVER['HTTP_HOST'])) // for cli mode use: --debug
return;
ob_flush();
}

Rufe ich nun im TestCase diese Methode mit $this->debug() statt debug() auf erhalte ich (fast) wie gewohnt meine Debug-Ausgaben.

UPDATE:
Alternativ kann man auch &debug=1 an die URL anhängen um die Ausgaben von debug(), print_r() und Co zu erhalten.

RSA mit JAVA und PHP – Teil 1 (JAVA -> PHP)

Daten zwischen PHP und JAVA mit RSA verschlüsselt auszutauschen gestaltet sich doch etwas schwieriger als anfangs gedacht. Nach etwas längerer Suche nach der Lösung habe ich mich entschlossen meinen Lösungsansatz hier zu veröffentlichen:

  1. Zuerst benötigen wir für den Server (PHP) und für den Client (JAVA) jeweils einen privaten und einen öffentlichen Schlüssel, diese erzeugen wir mit dem Kommandozeilentool openssl:
    1
    2
    openssl genrsa -out serverPrivateKey.pem 2048
    openssl rsa -in serverPrivateKey.pem -pubout -outform DER -out serverPublicKey.der

    Mit dem ersten Befehl wird der private Schlüssel für den Server erzeugt und im openssl Standardformat PEM abgespeichert. Der zweite Befehl speichert dann den dazugehörigen öffentlichen Schlüssel im DER Format ab. (Das DER Format ist das Standardformat für JAVA’s RSA.) Umgekehrt benötigen wir dann noch noch den privatenSchlüssel des JAVA Client (im DER Format) sowie den öffentlichen Schlüssel des Clients im PEM Format:

    1
    2
    3
    openssl genrsa -out clientPrivateKey.pem 2048
    openssl pkcs8 -topk8 -nocrypt -in clientPrivateKey.pem -outform der -out clientPrivateKey.der
    openssl rsa -in clientPrivateKey.pem -pubout -outform PEM -out clientPublicKey.pem

    Die Zahl 2048 gibt die Größe des Schlüssels in Bit an. Weniger als 2048 sollte man heutzutage nicht verwenden. Wer auf Nummer sicher gehen will nimmt hier 4096.

  2. Im nächsten Schritt importieren wir den öffentlichen Schlüssel des Servers in unserem JAVA Client:

    Java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    File pubKeyFile = new File("keys/serverPublicKey.der");
    byte[] buffer = new byte[(int) pubKeyFile.length()];
    DataInputStream in = new DataInputStream(new FileInputStream(pubKeyFile));
    in.readFully(buffer);
    in.close();
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(new X509EncodedKeySpec(buffer));

  3. Nach dem importieren des publicKey können wir nun Daten verschlüsseln:

    Java
    1
    2
    3
    4
    5
    String text = "Geheimer Text!";
    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    byte[] encrypted = cipher.doFinal(text.getBytes());

    Um mit den verschlüsselten Daten weiter arbeiten zu können, speichern wir diese ab:

    Java
    1
    2
    3
    4
    FileOutputStream fos = new FileOutputStream("/tmp/encrypted");
    fos.write(encrypted);
    fos.flush();
    fos.close();
  4. Verschlüsselte Daten mit PHP entschlüsseln.
    PHP
    1
    2
    3
    4
    5
    6
    7
    8
    <?php
    $encryptedData = file_get_contents('/tmp/encrypted');
    $privKeyFile = file_get_contents('keys/serverPrivateKey.pem');
    $privKey = openssl_get_privatekey($privKeyFile);
    openssl_private_decrypt($encryptedData, $decrypted, $privKey, OPENSSL_PKCS1_PADDING);
    print "$decrypted\n";

    Und als Ausgabe erhalten wir (wie erwartet):
    Geheimer Text!

So das wars mit dem ersten Teil, der zweite Teil, mit der Verschlüsselung in der anderen Richtung folgt hoffentlich bald.

UPDATE:
2. Teil veröffentlich: RSA mit JAVA und PHP – Teil 2 (PHP -> JAVA)