2016-11-26 1 views
1

Ich habe eine Python-Anwendung und PHP-Website, die über eine bestimmte Netzwerkschicht kommunizieren, die Nachrichten sendet. Meine Aufgabe ist es, alle Nachrichten AES-verschlüsselt und Base64-codiert mit diesem Kanal zu senden. Der Verschlüsselungsschlüssel wird für beide Parteien manuell freigegeben.Eine Python-zu-PHP-kompatible AES-Verschlüsselung mit openssl_encrypt AES-CBC

In meinem PHP, habe ich diesen Code letzte Nachrichtentext $payload genannt zu erstellen:

$key = substr('abdsbfuibewuiuizasbfeuiwhfashgfhj56urfgh56rt7856rh', 0, 32); 
$magic = 'THISISANENCRYPTEDMESSAGE'; 

function crypted($data) { 
     global $key, $magic; 

     // serialize 
     $payload = json_encode($data); 

     // encrypt and get base64 string with padding (==): 
     $payload = @openssl_encrypt($payload, 'AES-192-CBC', $key); 

     // prepend with magic 
     $payload = $magic.$payload; 
     return $payload; 
    } 

Und ich erhält eine solche Nachricht in meinem Python-Anwendung, die Magie Strippen, Base64-Byte-Daten zu bekommen. Das Problem, dass ich keine Probe finden kann, um kompatible AES-Chiffre zu machen, um diese Nachricht zu entschlüsseln.

Schlüssel und "Magic" sind nur Werte, die auf beiden Seiten geteilt und bekannt sind, ist das korrekt? Brauche ich eine IV?

Hier ist Python-Lösung von SO, die nicht für meine verschlüsselten Nachrichten funktioniert.

Es scheitert auf der letzten Zeile mit Dekodierungsproblem. Der Decodiermodus "Ignorieren" gibt eine leere Zeichenfolge zurück.

# with magic: "THISISANENCRYPTEDMESSAGE8wZVLZpm7UNyUf26Kds9Gwl2TBsPRo3zYDFQ59405wI=" 
# contains: {'test': 'hello world'} 
payload = '8wZVLZpm7UNyUf26Kds9Gwl2TBsPRo3zYDFQ59405wI=' 

aes = AESCipher('abdsbfuibewuiuizasbfeuiwhfashgfh') 
print(aes.decrypt(payload)) 

Löst:

Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "../test.py", line 36, in decrypt 
    return self.__unpad(cipher.decrypt(enc).decode("utf-8")) 
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x9e in position 0: invalid start byte 

Was bin ich?

+1

Warum verwenden Sie 'text [-1]' (ein 'x02' Byte, so dass Sie die letzten 2 Bytes ignorieren) um festzustellen, wie lang die verschlüsselte Datenfolge ist? –

+0

Verwenden Sie den Schlüssel als IV ist eine wirklich nicht intelligente Idee. Wie wirklich nicht schlau. Und ein Schlüssel, der vollständig aus ASCII-Buchstaben und Zahlen besteht, reduziert den möglichen Schlüsselraum signifikant. –

Antwort

2

Sie verwenden Cipher Block Chaining, haben aber kein IV an openssl_encrypt() übergeben; das bedeutet, dass die IV dann das 16-fache des NUL-Bytes ist. Aber Ihr Python-Code verwendet stattdessen den -Schlüssel als IV, so dass ein anderes Entschlüsselungsergebnis insgesamt erzeugt wird.

Als nächstes haben Sie AES-192-CBC, nicht AES-256-CBC ausgewählt, so dass nur 192 Bits für den Schlüssel verwendet werden. 192 Bits == 24 Bytes und nicht 32 wie Sie dachten.

Sie müssen auch den Anruf __unpad() vollständig löschen, gibt es keine Auffüllung in Ihren verschlüsselten Daten, Entfernen von Daten vom Ende vor der Entschlüsselung wird nur dazu führen, dass die Entschlüsselung fehlschlägt.

Also auf der Python Seite zu entschlüsseln, verwenden 24 Zeichen für den Schlüssel, eine IV geben, die 16-mal \x00 ist, und übergeben Sie in alle Daten, die Sie von Base64 decodiert:

>>> from Crypto.Cipher import AES 
>>> from base64 import b64decode 
>>> key = 'abdsbfuibewuiuizasbfeuiwhfashgfh'[:24] 
>>> key 
'abdsbfuibewuiuizasbfeuiw' 
>>> payload = '8wZVLZpm7UNyUf26Kds9Gwl2TBsPRo3zYDFQ59405wI=' 
>>> enc = b64decode(payload) 
>>> cipher = AES.new(key, AES.MODE_CBC, '\x00' * 16) 
>>> cipher.decrypt(enc) 
b'{"test":"hello world"}\n\n\n\n\n\n\n\n\n\n' 

Wenn Sie wollten Um die vollen 32 Zeichen des Schlüssels zu verwenden, verwenden Sie stattdessen AES-256-CBC.

Sie möchten wirklich eine zufällige IV erzeugen, so dass jemand, der den Datenverkehr überwacht, keine Muster ermitteln kann (wobei die gleiche Nutzlast jedes Mal dieselbe verschlüsselte Nachricht erzeugt). Generieren Sie die IV, fügen Sie sie in die gesendeten Daten ein und extrahieren Sie sie auf der Python-Seite, um sie an die Funktion AES.new() zu übergeben.

+0

Großartig, sehr klar und informativ. – Johny99