it-swarm.com.de

openssl: Schlüssel und IV durch Passphrase wiederherstellen

Eine große Anzahl von Dateien wurde von verschlüsselt

    openssl enc -aes-256-cbc -pass pass:MYPASSWORD

Openssl sollte Schlüssel + IV aus der Passphrase ableiten. Ich würde gerne Schlüssel + IV-Äquivalent zu diesem MYPASSWORT wissen. Ist das möglich?

Ich kenne MYPASSWORD. Ich könnte mit neuem bekannten Schlüssel + IV entschlüsseln und dann erneut verschlüsseln mit:

    openssl enc -d -aes-256-cbc -pass pass:MYPASSWORD
    openssl enc -aes-256-cbc -K MYKEY -IV MYIV

Das Problem ist jedoch, dass die Datenmenge ziemlich groß ist.

42

Die Verwendung der Befehlszeilenoption openssl enc Wird beschrieben dort . Im Folgenden werde ich Ihre Frage beantworten, aber vergessen Sie nicht, den letzten Teil meines Textes zu lesen, in dem ich mir anschaue, was unter der Haube passiert. Es ist lehrreich.


OpenSSL verwendet einen Schlüsselableitungsalgorithmus salted. Das Salt ist ein Stück zufälliger Bytes, die beim Verschlüsseln generiert werden und im Dateikopf gespeichert sind. Bei der Entschlüsselung wird das Salz aus dem Header abgerufen und der Schlüssel und IV werden aus dem angegebenen Kennwort neu berechnet und salt.

In der Befehlszeile können Sie die Option -P (Großbuchstabe P) verwenden, um Salt, Key und IV zu drucken und dann zu beenden. Sie können auch das -p (Kleinbuchstaben P) verwenden, um das Salz, den Schlüssel und die IV zu drucken und dann mit der Verschlüsselung fortzufahren. Versuchen Sie zuerst Folgendes:

openssl enc -aes-256-cbc -pass pass:MYPASSWORD -P

Wenn Sie diesen Befehl mehrmals ausführen, werden Sie feststellen, dass jeder Aufruf unterschiedliche Werte zurückgibt! Dies liegt daran, dass -d In Abwesenheit des Flags openssl enc Verschlüsselung Durchführt und jedes Mal ein zufälliges Salz generiert. Da das Salz variiert, variieren auch der Schlüssel und IV. Daher ist das Flag -P Beim Verschlüsseln nicht sehr nützlich. Das Flag -p kann jedoch verwendet werden. Lass es uns erneut versuchen; Dieses Mal haben wir die Datei foo_clear, die wir in foo_enc verschlüsseln möchten. Lassen Sie uns dies ausführen:

openssl enc -aes-256-cbc -pass pass:MYPASSWORD -p -in foo_clear -out foo_enc

Dieser Befehl verschlüsselt die Datei (wodurch foo_enc Erstellt wird) und drucken Sie Folgendes aus:

salt=A68D6E406A087F05
key=E7C8836AD32C688444E3928F69F046715F8B33AF2E52A6E67A626B586DE8024E
iv=B9F128D827203729BE52A834CC0890B7

Diese Werte sind Salt, Key und IV, die tatsächlich zum Verschlüsseln der Datei verwendet werden.

Wenn ich sie später zurückbekommen möchte, kann ich das Flag -P In Verbindung mit dem Flag -d Verwenden:

openssl enc -aes-256-cbc -pass pass:MYPASSWORD -d -P -in foo_enc

dadurch wird jedes Mal dasselbe Salz, Schlüssel und IV wie oben gedruckt. Wie das? Das liegt daran, dass wir diesmal entschlüsseln, also wird der Header von foo_enc Gelesen und das Salz abgerufen. Für einen bestimmten Salzwert ist die Ableitung des Passworts in Schlüssel und IV deterministisch.

Darüber hinaus ist dieser Schlüssel-und-IV-Abruf schnell, selbst wenn die Datei sehr lang ist, da das Flag -P Die tatsächliche Entschlüsselung verhindert. es liest den Header, hört aber dort auf.

Alternativ können Sie den Salzwert mit dem Flag -S Angeben oder das Salz insgesamt mit -nosalt Deaktivieren. . Die ungesalzene Verschlüsselung ist überhaupt nicht empfohlen, da sie möglicherweise das Knacken von Passwörtern mit vorberechneten Tabellen beschleunigt (dasselbe Passwort liefert immer den gleichen Schlüssel und die gleiche IV). Wenn Sie den Salzwert angeben, werden Sie dafür verantwortlich, geeignete Salze zu erzeugen, d. H. Zu versuchen, sie so einzigartig wie möglich zu machen (in der Praxis müssen Sie sie zufällig produzieren). Es ist vorzuziehen, openssl damit umgehen zu lassen, da ausreichend Platz für stille Fehler vorhanden ist ("stumm" bedeutet "schwach und knackbar, aber der Code funktioniert weiterhin, sodass Sie das Problem während Ihrer Tests nicht erkennen").


Das von OpenSSL verwendete Verschlüsselungsformat ist kein Standard: Es ist "das, was OpenSSL tut", und wenn alle Versionen von OpenSSL miteinander übereinstimmen, gibt es außer OpenSSL-Quellcode noch kein Referenzdokument, das dieses Format beschreibt. Das Header-Format ist ziemlich einfach:

magic value (8 bytes): the bytes 53 61 6c 74 65 64 5f 5f
salt value (8 bytes)

Daher ein fester 16-Byte-Header, beginnend mit der ASCII-Codierung der Zeichenfolge Salted__, Gefolgt vom Salt selbst. Das ist alles! Kein Hinweis auf den Verschlüsselungsalgorithmus; Sie sind es soll das selbst verfolgen.

Der Prozess, durch den das Passwort und Salt in den Schlüssel und IV umgewandelt werden, ist nicht dokumentiert, aber der Quellcode zeigt, dass er die OpenSSL-spezifische EVP_BytesToKey() -Funktion aufruft, die verwendet eine benutzerdefinierte Schlüsselableitungsfunktion (KDF) mit einigen wiederholten Hashing. Dies ist ein nicht standardmäßiges und nicht gut geprüftes Konstrukt (!), Das auf der MD5-Hash-Funktion von zweifelhaftem Ruf (!!) beruht. Diese Funktion kann in der Befehlszeile mit dem Flag undokumentiert-md (!!!) geändert werden. Die "Iterationszahl" wird mit dem Befehl enc auf 1 gesetzt und kann nicht geändert werden (!!!!). Dies bedeutet, dass die ersten 16 Bytes des Schlüssels gleich MD5 (Passwort || Salt) sind, und das war's.

Das ist ziemlich schwach! Jeder, der weiß, wie man Code auf einem PC schreibt, kann versuchen, ein solches Schema zu knacken, und kann mehrere Dutzend "versuchen" von Millionen potenzieller Passwörter pro Sekunde (Hunderte von Millionen sind mit einer GPU erreichbar). Wenn Sie openssl enc Verwenden, stellen Sie sicher, dass Ihr Passwort eine sehr hohe Entropie aufweist! (dh höher als normalerweise empfohlen; streben Sie 80 Bit an am wenigsten). Oder verwenden Sie es vorzugsweise überhaupt nicht. Entscheiden Sie sich stattdessen für etwas Robusteres ( GnuPG Wenn Sie eine symmetrische Verschlüsselung für ein Kennwort durchführen, wird ein stärkeres KDF mit vielen Iterationen der zugrunde liegenden Hash-Funktion verwendet).

91
Thomas Pornin

Haben Sie versucht, die -P Möglichkeit?

openssl enc -aes-256-cbc -pass pass:MYPASSWORD -P

salt=28C5AD65428E4FD2
key=215202893B8CFEE68E733F69C55AE4C7BED7B2A06533774F3EA0894880E585E6
iv =186DE986FC69F8E47ED692B24D940BED
9
jdigital

Ich würde gerne Schlüssel + IV-Äquivalent zu diesem MYPASSWORT kennen

Sie müssen nur die Schlüsselableitungsfunktion in EVP_BytesToKey replizieren, was ziemlich einfach ist.

Wenn Sie nicht -md (Oder -md md5) Angeben, basiert das verwendete KDF auf MD5, aber die ersten 16 Bytes werden mit PKCS # 5 PBKDF1 mit einer Iterationszahl von 1. Dies wird dann unter Verwendung des in EVP_BytesToKey Angegebenen Schlüsselableitungsalgorithmus erweitert, um die Größenanforderungen des Schlüssels und von IV zu erfüllen

Wenn Sie die zugrunde liegende Hash-Funktion mit -md Angeben und eine andere Hash-Funktion als MD5 auswählen (z. B. -md sha256), Wird OpenSSL nur KDF in EVP_BytesToKey (Und nicht PBKDF1).

Implementierung in Python 3 (benötigt passlib ):

import hashlib, binascii
from passlib.utils.pbkdf2 import pbkdf1

def hasher(algo, data):
    hashes = {'md5': hashlib.md5, 'sha256': hashlib.sha256,
    'sha512': hashlib.sha512}
    h = hashes[algo]()
    h.update(data)

    return h.digest()

# pwd and salt must be bytes objects
def openssl_kdf(algo, pwd, salt, key_size, iv_size):
    if algo == 'md5':
        temp = pbkdf1(pwd, salt, 1, 16, 'md5')
    else:
        temp = b''

    fd = temp    
    while len(fd) < key_size + iv_size:
        temp = hasher(algo, temp + pwd + salt)
        fd += temp

    key = fd[0:key_size]
    iv = fd[key_size:key_size+iv_size]

    print('salt=' + binascii.hexlify(salt).decode('ascii').upper())
    print('key=' + binascii.hexlify(key).decode('ascii').upper())
    print('iv=' + binascii.hexlify(iv).decode('ascii').upper())

    return key, iv

Beispiele (getestet mit OpenSSL 0.9.8 und 1.0.1):

openssl_kdf('md5', b'test', b'\xF6\x81\x8C\xAE\x13\x18\x72\xBD', 32, 16)
# generates the same output as:
openssl enc -aes-256-cbc -P -pass pass:test -S F6818CAE131872BD 

openssl_kdf('sha256', b'test', b'\xF6\x81\x8C\xAE\x13\x18\x72\xBD', 32, 16)
# generates the same output as:
openssl enc -aes-256-cbc -P -pass pass:test -S F6818CAE131872BD -md SHA256
5
Null

In der letzten Version von openssl (ebenfalls mit OpenSSL 1.1.0h, 27. März 2018 getestet) scheint es einfach und unkompliziert zu sein, Folgendes zu überprüfen:

    openssl version
OpenSSL 1.0.2k-fips  26 Jan 2017

    echo -n salt1234 | od -A n -t x1 | Perl -lpe's,\s+,,g'
73616c7431323334

    openssl enc -e -aes-128-cbc -pass pass:123 -S 73616c7431323334 -P -md sha256
salt=73616C7431323334
key=5A7C52236BAEAE1A92A6B2D1E50C43ED
iv =9F629A34588A4006FE1C7E8FC664B5EC

    echo -n 123salt1234 | openssl dgst -sha256 -binary | hexdump -Cv
00000000  5a 7c 52 23 6b ae ae 1a  92 a6 b2 d1 e5 0c 43 ed  |Z|R#k.........C.|
00000010  9f 62 9a 34 58 8a 40 06  fe 1c 7e 8f c6 64 b5 ec  |[email protected]~..d..|
00000020

Wenn Sie genau hinschauen, wird die -P Ausgabe entspricht der Hexdump-Ausgabe.

Fazit: Verwenden Sie enc nur zum Studieren und Erkunden, es ist nur ein schönes Spielzeug (falls Sie es noch nicht wussten).

1
alexgirao