Wie entschlüsselt OpenSSL AES-verschlüsselte Dateien in Python?

OpenSSL bietet eine beliebte (aber unsichere – siehe unten!) Befehlszeilenschnittstelle für die AES-Verschlüsselung:

openssl aes-256-cbc -salt -in filename -out filename.enc 

Python unterstützt AES in Form des PyCrypto-Pakets, stellt jedoch nur die Tools zur Verfügung. Wie benutze ich Python / PyCrypto, um Dateien zu entschlüsseln, die mit OpenSSL verschlüsselt wurden?

Beachten

Diese Frage betraf auch die Verschlüsselung in Python mit dem gleichen Schema. Seitdem habe ich diesen Teil entfernt, um jeden davon abzuhalten, ihn zu benutzen. Verschlüsseln Sie KEINE weiteren Daten auf diese Weise, da sie nach den heutigen Standards NICHT sicher sind. Sie sollten die Entschlüsselung NUR aus anderen Gründen als der Rückwärtskompatibilität verwenden, dh wenn Sie keine andere Wahl haben. Möchten Sie verschlüsseln? Verwenden Sie NaCl / lib Natrium, wenn Sie können.

Solutions Collecting From Web of "Wie entschlüsselt OpenSSL AES-verschlüsselte Dateien in Python?"

Angesichts der Popularität von Python war ich anfangs enttäuscht, dass es keine vollständige Antwort auf diese Frage gab. Es hat mich ziemlich viel Zeit gekostet, verschiedene Antworten auf diesem Board zu lesen, sowie andere Ressourcen, um es richtig zu machen. Ich dachte, ich könnte das Ergebnis für zukünftige Referenz und vielleicht Überprüfung teilen; Ich bin keineswegs ein Kryptographieexperte! Der folgende Code scheint jedoch nahtlos zu funktionieren:

 from hashlib import md5 from Crypto.Cipher import AES from Crypto import Random def derive_key_and_iv(password, salt, key_length, iv_length): d = d_i = '' while len(d) < key_length + iv_length: d_i = md5(d_i + password + salt).digest() d += d_i return d[:key_length], d[key_length:key_length+iv_length] def decrypt(in_file, out_file, password, key_length=32): bs = AES.block_size salt = in_file.read(bs)[len('Salted__'):] key, iv = derive_key_and_iv(password, salt, key_length, bs) cipher = AES.new(key, AES.MODE_CBC, iv) next_chunk = '' finished = False while not finished: chunk, next_chunk = next_chunk, cipher.decrypt(in_file.read(1024 * bs)) if len(next_chunk) == 0: padding_length = ord(chunk[-1]) chunk = chunk[:-padding_length] finished = True out_file.write(chunk) 

Verwendung:

 with open(in_filename, 'rb') as in_file, open(out_filename, 'wb') as out_file: decrypt(in_file, out_file, password) 

Wenn Sie die Möglichkeit sehen, dies zu verbessern oder es flexibler zu gestalten (z. B. ohne Salz oder Python 3-Kompatibilität), tun Sie dies bitte.

Beachten

Diese Antwort bezog sich früher auch auf die Verschlüsselung in Python mit demselben Schema. Seitdem habe ich diesen Teil entfernt, um jeden davon abzuhalten, ihn zu benutzen. Verschlüsseln Sie KEINE weiteren Daten auf diese Weise, da sie nach den heutigen Standards NICHT sicher sind. Sie sollten die Entschlüsselung NUR aus anderen Gründen als der Rückwärtskompatibilität verwenden, dh wenn Sie keine andere Wahl haben. Möchten Sie verschlüsseln? Verwenden Sie NaCl / lib Natrium, wenn Sie können.

Ich poste deinen Code mit ein paar Korrekturen neu (ich wollte deine Version nicht verdecken). Während der Code funktioniert, werden einige Fehler beim Auffüllen nicht erkannt. Insbesondere, wenn der Entschlüsselungsschlüssel falsch ist, kann Ihre Auffülllogik etwas seltsam tun. Wenn Sie mit meiner Änderung einverstanden sind, können Sie Ihre Lösung aktualisieren.

 from hashlib import md5 from Crypto.Cipher import AES from Crypto import Random def derive_key_and_iv(password, salt, key_length, iv_length): d = d_i = '' while len(d) < key_length + iv_length: d_i = md5(d_i + password + salt).digest() d += d_i return d[:key_length], d[key_length:key_length+iv_length] # This encryption mode is no longer secure by today's standards. # See note in original question above. def obsolete_encrypt(in_file, out_file, password, key_length=32): bs = AES.block_size salt = Random.new().read(bs - len('Salted__')) key, iv = derive_key_and_iv(password, salt, key_length, bs) cipher = AES.new(key, AES.MODE_CBC, iv) out_file.write('Salted__' + salt) finished = False while not finished: chunk = in_file.read(1024 * bs) if len(chunk) == 0 or len(chunk) % bs != 0: padding_length = bs - (len(chunk) % bs) chunk += padding_length * chr(padding_length) finished = True out_file.write(cipher.encrypt(chunk)) def decrypt(in_file, out_file, password, key_length=32): bs = AES.block_size salt = in_file.read(bs)[len('Salted__'):] key, iv = derive_key_and_iv(password, salt, key_length, bs) cipher = AES.new(key, AES.MODE_CBC, iv) next_chunk = '' finished = False while not finished: chunk, next_chunk = next_chunk, cipher.decrypt(in_file.read(1024 * bs)) if len(next_chunk) == 0: padding_length = ord(chunk[-1]) if padding_length < 1 or padding_length > bs: raise ValueError("bad decrypt pad (%d)" % padding_length) # all the pad-bytes must be the same if chunk[-padding_length:] != (padding_length * chr(padding_length)): # this is similar to the bad decrypt:evp_enc.c from openssl program raise ValueError("bad decrypt") chunk = chunk[:-padding_length] finished = True out_file.write(chunk) 

Der folgende Code sollte Python 3-kompatibel mit den kleinen Änderungen sein, die im Code dokumentiert sind. Wollte auch os.urandom anstelle von Crypto.Random verwenden. ‘Salted__’ wird durch salt_header ersetzt, das angepasst oder bei Bedarf leer gelassen werden kann.

 from os import urandom from hashlib import md5 from Crypto.Cipher import AES def derive_key_and_iv(password, salt, key_length, iv_length): d = d_i = b'' # changed '' to b'' while len(d) < key_length + iv_length: # changed password to str.encode(password) d_i = md5(d_i + str.encode(password) + salt).digest() d += d_i return d[:key_length], d[key_length:key_length+iv_length] def encrypt(in_file, out_file, password, salt_header='', key_length=32): # added salt_header='' bs = AES.block_size # replaced Crypt.Random with os.urandom salt = urandom(bs - len(salt_header)) key, iv = derive_key_and_iv(password, salt, key_length, bs) cipher = AES.new(key, AES.MODE_CBC, iv) # changed 'Salted__' to str.encode(salt_header) out_file.write(str.encode(salt_header) + salt) finished = False while not finished: chunk = in_file.read(1024 * bs) if len(chunk) == 0 or len(chunk) % bs != 0: padding_length = (bs - len(chunk) % bs) or bs # changed right side to str.encode(...) chunk += str.encode( padding_length * chr(padding_length)) finished = True out_file.write(cipher.encrypt(chunk)) def decrypt(in_file, out_file, password, salt_header='', key_length=32): # added salt_header='' bs = AES.block_size # changed 'Salted__' to salt_header salt = in_file.read(bs)[len(salt_header):] key, iv = derive_key_and_iv(password, salt, key_length, bs) cipher = AES.new(key, AES.MODE_CBC, iv) next_chunk = '' finished = False while not finished: chunk, next_chunk = next_chunk, cipher.decrypt( in_file.read(1024 * bs)) if len(next_chunk) == 0: padding_length = chunk[-1] # removed ord(...) as unnecessary chunk = chunk[:-padding_length] finished = True out_file.write(bytes(x for x in chunk)) # changed chunk to bytes(...) 

Ich weiß, das ist ein bisschen spät, aber hier ist eine Lösung, die ich im Jahr 2013 gebloggt habe, wie man das python pycrypto-Paket verwendet, um in einer openssl-kompatiblen Weise zu verschlüsseln / entschlüsseln. Es wurde auf Python2.7 und Python3.x getestet. Der Quellcode und ein Testskript finden Sie hier .

Einer der Hauptunterschiede zwischen dieser Lösung und den vorgestellten exzellenten Lösungen besteht darin, dass sie zwischen Pipe und Datei-E / A unterscheidet, was in einigen Anwendungen Probleme verursachen kann.

Die wichtigsten functionen aus diesem Blog sind unten aufgeführt.

 # ================================================================ # get_key_and_iv # ================================================================ def get_key_and_iv(password, salt, klen=32, ilen=16, msgdgst='md5'): ''' Derive the key and the IV from the given password and salt. This is a niftier implementation than my direct transliteration of the C++ code although I modified to support different digests. CITATION: http://stackoverflow.com/questions/13907841/implement-openssl-aes-encryption-in-python @param password The password to use as the seed. @param salt The salt. @param klen The key length. @param ilen The initialization vector length. @param msgdgst The message digest algorithm to use. ''' # equivalent to: # from hashlib import  as mdf # from hashlib import md5 as mdf # from hashlib import sha512 as mdf mdf = getattr(__import__('hashlib', fromlist=[msgdgst]), msgdgst) password = password.encode('ascii', 'ignore') # convert to ASCII try: maxlen = klen + ilen keyiv = mdf(password + salt).digest() tmp = [keyiv] while len(tmp) < maxlen: tmp.append( mdf(tmp[-1] + password + salt).digest() ) keyiv += tmp[-1] # append the last byte key = keyiv[:klen] iv = keyiv[klen:klen+ilen] return key, iv except UnicodeDecodeError: return None, None # ================================================================ # encrypt # ================================================================ def encrypt(password, plaintext, chunkit=True, msgdgst='md5'): ''' Encrypt the plaintext using the password using an openssl compatible encryption algorithm. It is the same as creating a file with plaintext contents and running openssl like this: $ cat plaintext  $ openssl enc -e -aes-256-cbc -base64 -salt \\ -pass pass:<password> -n plaintext @param password The password. @param plaintext The plaintext to encrypt. @param chunkit Flag that tells encrypt to split the ciphertext into 64 character (MIME encoded) lines. This does not affect the decrypt operation. @param msgdgst The message digest algorithm. ''' salt = os.urandom(8) key, iv = get_key_and_iv(password, salt, msgdgst=msgdgst) if key is None: return None # PKCS#7 padding padding_len = 16 - (len(plaintext) % 16) if isinstance(plaintext, str): padded_plaintext = plaintext + (chr(padding_len) * padding_len) else: # assume bytes padded_plaintext = plaintext + (bytearray([padding_len] * padding_len)) # Encrypt cipher = AES.new(key, AES.MODE_CBC, iv) ciphertext = cipher.encrypt(padded_plaintext) # Make openssl compatible. # I first discovered this when I wrote the C++ Cipher class. # CITATION: http://projects.joelinoff.com/cipher-1.1/doxydocs/html/ openssl_ciphertext = b'Salted__' + salt + ciphertext b64 = base64.b64encode(openssl_ciphertext) if not chunkit: return b64 LINELEN = 64 chunk = lambda s: b'\n'.join(s[i:min(i+LINELEN, len(s))] for i in range(0, len(s), LINELEN)) return chunk(b64) # ================================================================ # decrypt # ================================================================ def decrypt(password, ciphertext, msgdgst='md5'): ''' Decrypt the ciphertext using the password using an openssl compatible decryption algorithm. It is the same as creating a file with ciphertext contents and running openssl like this: $ cat ciphertext # ENCRYPTED <ciphertext> $ egrep -v '^#|^$' | \\ openssl enc -d -aes-256-cbc -base64 -salt -pass pass:<password> -in ciphertext @param password The password. @param ciphertext The ciphertext to decrypt. @param msgdgst The message digest algorithm. @returns the decrypted data. ''' # unfilter -- ignore blank lines and comments if isinstance(ciphertext, str): filtered = '' nl = '\n' re1 = r'^\s*$' re2 = r'^\s*#' else: filtered = b'' nl = b'\n' re1 = b'^\\s*$' re2 = b'^\\s*#' for line in ciphertext.split(nl): line = line.strip() if re.search(re1,line) or re.search(re2, line): continue filtered += line + nl # Base64 decode raw = base64.b64decode(filtered) assert(raw[:8] == b'Salted__' ) salt = raw[8:16] # get the salt # Now create the key and iv. key, iv = get_key_and_iv(password, salt, msgdgst=msgdgst) if key is None: return None # The original ciphertext ciphertext = raw[16:] # Decrypt cipher = AES.new(key, AES.MODE_CBC, iv) padded_plaintext = cipher.decrypt(ciphertext) if isinstance(padded_plaintext, str): padding_len = ord(padded_plaintext[-1]) else: padding_len = padded_plaintext[-1] plaintext = padded_plaintext[:-padding_len] return plaintext</password></ciphertext></password></mdi></code> </pre>
</div>
</li><!-- #comment-## -->
<div class="list-group-item list-group-item-action flex-column align-items-start">
		      	<h1>  Hinweis: Diese Methode ist nicht OpenSSL-kompatibel </h1>
<p>  Aber es ist geeignet, wenn Sie nur Dateien verschlüsseln und entschlüsseln wollen. </p>
<p>  Eine Selbstantwort habe ich von hier kopiert.  Ich denke, das ist vielleicht eine einfachere und sicherere Option.  Obwohl ich an einer Expertenmeinung interessiert wäre, wie sicher es ist. </p>
<p>  Ich habe Python 3.6 und SimpleCrypt benutzt , um die Datei zu verschlüsseln und dann hochgeladen. </p>
<p>  Ich <em>denke,</em> das ist der Code, mit dem ich die Datei verschlüsselt habe: </p>
<pre> <code>from simplecrypt import encrypt, decrypt f = open('file.csv','r').read() ciphertext = encrypt('USERPASSWORD',f.encode('utf8')) # I am not certain of whether I used the .encode('utf8') e = open('file.enc','wb') # file.enc doesn't need to exist, python will create it e.write(ciphertext) e.close</code> </pre>
<p>  Dies ist der Code, den ich benutze, um zur Laufzeit zu entschlüsseln, ich <code>getpass("password: ")</code> als Argument, so dass ich keine <code>password</code> Variable im Speicher speichern muss </p>
<pre> <code>from simplecrypt import encrypt, decrypt from getpass import getpass # opens the file f = open('file.enc','rb').read() print('Please enter the password and press the enter key \n Decryption may take some time') # Decrypts the data, requires a user-input password plaintext = decrypt(getpass("password: "), f).decode('utf8') print('Data have been Decrypted')</code> </pre>
<p>  Beachten Sie, dass das UTF-8-Codierungsverhalten in Python 2.7 anders ist, daher wird der Code etwas anders sein. </p>
</div>
</li><!-- #comment-## -->

 	</div>
		
        </div>
<ul>
  <li><a href="https://www.dasow.com/14103" rel="bookmark">
    Android Dialer-Anwendung  </a></li>
  <li><a href="https://www.dasow.com/10894" rel="bookmark">
    Was ist ein classnliteral in Java?  </a></li>
  <li><a href="https://www.dasow.com/6464" rel="bookmark">
    MySQL String ersetzen  </a></li>
  <li><a href="https://www.dasow.com/7514" rel="bookmark">
    Warum ist Mehrfachvererbung in Java oder C # nicht zulässig?  </a></li>
  <li><a href="https://www.dasow.com/7787" rel="bookmark">
    Wählen Sie in ASP.NET Core MVC Tag Helper aus  </a></li>
  <li><a href="https://www.dasow.com/2498" rel="bookmark">
    Wie schicke ich JSON-Daten mit Curl von Terminal / Commandline an Spring REST testen?  </a></li>
  <li><a href="https://www.dasow.com/6466" rel="bookmark">
    Ausführen / Installieren / Debuggen von Android-Anwendungen über WLAN?  </a></li>
  <li><a href="https://www.dasow.com/5666" rel="bookmark">
    Java Generics: Liste, Liste , Liste  </a></li>
  <li><a href="https://www.dasow.com/17675" rel="bookmark">
    JDK tools.jar als maven-Abhängigkeit  </a></li>
  <li><a href="https://www.dasow.com/5010" rel="bookmark">
    Erstellen Sie ein stark typisiertes c # -Objekt aus dem json-Objekt mit der ID als Namen  </a></li>
  <li><a href="https://www.dasow.com/6523" rel="bookmark">
    Ein Leitfaden für convert_imageset.cpp  </a></li>
  <li><a href="https://www.dasow.com/8022" rel="bookmark">
    Große ganze Zahlen in C #  </a></li>
  <li><a href="https://www.dasow.com/19223" rel="bookmark">
    Schützt mysql_real_escape_string () VOLLSTÄNDIG vor SQL-Injection?  </a></li>
  <li><a href="https://www.dasow.com/10736" rel="bookmark">
    Wie man einer Annotation aus einem Constant Java einen Wert liefert  </a></li>
  <li><a href="https://www.dasow.com/8027" rel="bookmark">
    Wie man Dateien von einem Git Repo zu einem anderen (kein Klon) verschiebt, Geschichte erhalten  </a></li>
</ul>    
    </div>
    
</div>

   <div class="clearfix mt-5"></div>
    <hr />
<footer>
        <ul class="list-inline text-center">
        <li class="list-inline-item">© 2017 Dasow</li>
        <li class="list-inline-item"><a href="/topics">Topics</a></li>
        <li class="list-inline-item"><a href="#">Terms</a></li>
        <li class="list-inline-item"><a href="#">Privacy Policy</a></li>
        </ul>
</footer>

</div>     
    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js" integrity="sha384-vFJXuSJphROIrBnz7yo7oB41mKfc8JzQZiCq4NCceLEaO4IHwicKwpJf9c9IpFgh" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js" integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ" crossorigin="anonymous"></script>
  </body>
<script type="text/javascript">
var sc_project=11853072; 
var sc_invisible=1; 
var sc_security="2ce3f32b"; 
</script>
<script type="text/javascript"
src="https://www.statcounter.com/counter/counter.js"
async></script>
<noscript><div class="statcounter"><a title="Web Analytics"
href="http://statcounter.com/" target="_blank"><img
class="statcounter"
src="//c.statcounter.com/11853072/0/2ce3f32b/1/" alt="Web
Analytics"></a></div></noscript>
</html>