it-swarm.com.de

Wie verschlüsselt man Text mit einem Passwort in Python?

Es ist überraschend schwierig, eine eindeutige Antwort auf diese Frage bei Google zu finden.

Ich möchte einen Text und eine Nachricht von einem Benutzer wie 1PWP7a6xgoYx81VZocrDr5okEEcnqKkyDchello world abrufen.

Dann möchte ich in der Lage sein, die Nachricht mit dem Text zu verschlüsseln/entschlüsseln, damit ich sie in meiner Datenbank speichern kann und mir keine Sorgen machen muss, dass die Daten angezeigt werden, wenn meine Website gehackt wird. encrypt('1PWP7a6xgoYx81VZocrDr5okEEcnqKkyDc', 'hello world')decrypt('1PWP7a6xgoYx81VZocrDr5okEEcnqKkyDc', <encrypted_text>)

Gibt es einen einfachen Weg, dies mit Python zu erreichen und bitte kann mir jemand ein Beispiel geben/leiten.

Vielleicht ein Beispiel für das Erstellen von öffentlichen/privaten Schlüsselpaaren mit einem Startwert wie '1PWP7a6xgoYx81VZocrDr5okEEcnqKkyDc'?

Vielen Dank im Voraus :)

EDIT: Nur um klar zu sein, ich suche nach einer Möglichkeit, die Daten meiner Benutzer determanistisch zu verschlüsseln, ohne die Nachricht zu verschleiern.

Wenn dies bedeutet, dass ich ein PGP/GPG-Pub/PRI-Schlüsselpaar im Handumdrehen generieren muss, indem ich den Text 1PWP7a6xgoYx81VZocrDr5okEEcnqKkyDc als Startwert verwende, ist das in Ordnung, aber wie ist die Methode dafür?

6
derrend

So machen Sie es richtig im CBC-Modus, einschließlich PKCS # 7-Padding:

import base64
from Crypto.Cipher import AES
from Crypto.Hash import SHA256
from Crypto import Random

def encrypt(key, source, encode=True):
    key = SHA256.new(key).digest()  # use SHA-256 over our key to get a proper-sized AES key
    IV = Random.new().read(AES.block_size)  # generate IV
    encryptor = AES.new(key, AES.MODE_CBC, IV)
    padding = AES.block_size - len(source) % AES.block_size  # calculate needed padding
    source += bytes([padding]) * padding  # Python 2.x: source += chr(padding) * padding
    data = IV + encryptor.encrypt(source)  # store the IV at the beginning and encrypt
    return base64.b64encode(data).decode("latin-1") if encode else data

def decrypt(key, source, decode=True):
    if decode:
        source = base64.b64decode(source.encode("latin-1"))
    key = SHA256.new(key).digest()  # use SHA-256 over our key to get a proper-sized AES key
    IV = source[:AES.block_size]  # extract the IV from the beginning
    decryptor = AES.new(key, AES.MODE_CBC, IV)
    data = decryptor.decrypt(source[AES.block_size:])  # decrypt
    padding = data[-1]  # pick the padding value from the end; Python 2.x: ord(data[-1])
    if data[-padding:] != bytes([padding]) * padding:  # Python 2.x: chr(padding) * padding
        raise ValueError("Invalid padding...")
    return data[:-padding]  # remove the padding

Es ist so eingestellt, dass es mit bytes-Daten arbeitet. Wenn Sie also Strings verschlüsseln oder String-Kennwörter verwenden möchten, müssen Sie sie mit einem geeigneten Codec encode() ausfüllen, bevor Sie sie an die Methoden übergeben. Wenn Sie den Parameter encode auf True belassen, wird die Ausgabe von encrypt() in eine Base64-kodierte Zeichenfolge und decrypt() source sollte ebenfalls eine Base64-Zeichenfolge sein.

Wenn Sie es jetzt testen:

my_password = b"secret_AES_key_string_to_encrypt/decrypt_with"
my_data = b"input_string_to_encrypt/decrypt"

print("key:  {}".format(my_password))
print("data: {}".format(my_data))
encrypted = encrypt(my_password, my_data)
print("\nenc:  {}".format(encrypted))
decrypted = decrypt(my_password, encrypted)
print("dec:  {}".format(decrypted))
print("\ndata match: {}".format(my_data == decrypted))
print("\nSecond round....")
encrypted = encrypt(my_password, my_data)
print("\nenc:  {}".format(encrypted))
decrypted = decrypt(my_password, encrypted)
print("dec:  {}".format(decrypted))
print("\ndata match: {}".format(my_data == decrypted))

ihre Ausgabe wäre ähnlich wie:

key:  b'secret_AES_key_string_to_encrypt/decrypt_with'
data: b'input_string_to_encrypt/decrypt'

enc:  7roSO+P/4eYdyhCbZmraVfc305g5P8VhDBOUDGrXmHw8h5ISsS3aPTGfsTSqn9f5
dec:  b'input_string_to_encrypt/decrypt'

data match: True

Second round....

enc:  BQm8FeoPx1H+bztlZJYZH9foI+IKAorCXRsMjbiYQkqLWbGU3NU50OsR+L9Nuqm6
dec:  b'input_string_to_encrypt/decrypt'

data match: True

Das Prüfen des gleichen Schlüssels und der gleichen Daten erzeugt immer noch unterschiedlichen Geheimtext.

Nun, das ist viel besser als die EZB, aber ... wenn Sie dies für die Kommunikation nutzen wollen - nicht! Dies ist mehr zu erklären, wie es aufgebaut sein sollte, nicht wirklich in einer Produktionsumgebung verwendet werden sollte und vor allem nicht für die Kommunikation, da dies ein entscheidender Bestandteil ist - die Nachrichtenauthentifizierung. Fühlen Sie sich frei, damit zu spielen, aber Sie sollten Ihre eigene Krypto nicht rollen, es gibt gut überprüfte Protokolle, mit denen Sie die üblichen Fallstricke vermeiden können, und Sie sollten diese verwenden.

16
zwer

Basierend auf den Antworten von zwer wird jedoch ein kleiner Fehler behoben, wenn die Quelle genau ein Vielfaches von 16 ist.

Code:

from builtins import bytes
import base64
from Crypto.Cipher import AES
from Crypto.Hash import SHA256
from Crypto import Random

def encrypt(string, password):
    """
    It returns an encrypted string which can be decrypted just by the 
    password.
    """
    key = password_to_key(password)
    IV = make_initialization_vector()
    encryptor = AES.new(key, AES.MODE_CBC, IV)

    # store the IV at the beginning and encrypt
    return IV + encryptor.encrypt(pad_string(string))

def decrypt(string, password):
    key = password_to_key(password)   

    # extract the IV from the beginning
    IV = string[:AES.block_size]  
    decryptor = AES.new(key, AES.MODE_CBC, IV)

    string = decryptor.decrypt(string[AES.block_size:])
    return unpad_string(string)

def password_to_key(password):
    """
    Use SHA-256 over our password to get a proper-sized AES key.
    This hashes our password into a 256 bit string. 
    """
    return SHA256.new(password).digest()

def make_initialization_vector():
    """
    An initialization vector (IV) is a fixed-size input to a cryptographic
    primitive that is typically required to be random or pseudorandom.
    Randomization is crucial for encryption schemes to achieve semantic 
    security, a property whereby repeated usage of the scheme under the 
    same key does not allow an attacker to infer relationships 
    between segments of the encrypted message.
    """
    return Random.new().read(AES.block_size)

def pad_string(string, chunk_size=AES.block_size):
    """
    Pad string the peculirarity that uses the first byte
    is used to store how much padding is applied
    """
    assert chunk_size  <= 256, 'We are using one byte to represent padding'
    to_pad = (chunk_size - (len(string) + 1)) % chunk_size
    return bytes([to_pad]) + string + bytes([0] * to_pad)
def unpad_string(string):
    to_pad = string[0]
    return string[1:-to_pad]

def encode(string):
    """
    Base64 encoding schemes are commonly used when there is a need to encode 
    binary data that needs be stored and transferred over media that are 
    designed to deal with textual data.
    This is to ensure that the data remains intact without 
    modification during transport.
    """
    return base64.b64encode(string).decode("latin-1")

def decode(string):
    return base64.b64decode(string.encode("latin-1"))

Tests:

def random_text(length):
    def Rand_lower():
        return chr(randint(ord('a'), ord('z')))
    string = ''.join([Rand_lower() for _ in range(length)])
    return bytes(string, encoding='utf-8')

def test_encoding():
    string = random_text(100)
    assert encode(string) != string
    assert decode(encode(string)) == string

def test_padding():
    assert len(pad_string(random_text(14))) == 16
    assert len(pad_string(random_text(15))) == 16
    assert len(pad_string(random_text(16))) == 32

def test_encryption():
    string = random_text(100)
    password = random_text(20)
    assert encrypt(string, password) != string
    assert decrypt(encrypt(string, password), password) == string
1
  1. Wenn Sie die erwähnte Datenbank verwenden, um Benutzer zu autorisieren, sollten Sie hashes oder Kurznachrichten der Passwörter des Benutzers anstelle von 2-Wege-Verschlüsselungsalgorithmen verwenden. Dies würde die Verwendung Ihrer Daten selbst im Falle eines Datenbankverlusts erschweren.
  2. Die oben beschriebene Methode kann nicht zum Schutz von Daten verwendet werden, die zu einem bestimmten Zeitpunkt entschlüsselt werden müssen. Selbst dann können Sie eine sicherere Methode verwenden, als nur Benutzerkennwörter mit einem festen Schlüssel zu verschlüsseln (was die schlechteste Methode ist). Werfen Sie einen Blick auf OWASP's Password Storage Cheat Sheet .

Als Sie geschrieben haben "Ich möchte die Nachricht verschlüsseln/entschlüsseln können", füge ich eine einfache Python-Quelle (getestet unter 2.7) für das Verschlüsseln/Entschlüsseln mit Blowfish an.

#!/usr/bin/env python2
# -*- coding: utf-8 -*-
import os
from Crypto.Cipher import Blowfish     # pip install pycrypto

BS = 8
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS) 
unpad = lambda s : s[0:-ord(s[-1])]

def doEncrypt(phrase, key):
    c1  = Blowfish.new(key, Blowfish.MODE_ECB)
    return c1.encrypt(pad(phrase))

def doDecrypt(phrase, key):
    c1  = Blowfish.new(key, Blowfish.MODE_ECB)
    return unpad(c1.decrypt(phrase))

def testing123(phrase, key):
    encrypted = doEncrypt(phrase, key)
    decrypted = doDecrypt(encrypted, key)
    assert phrase == decrypted, "Blowfish ECB enc/dec verification failed"
    print ("Blowfish ECB enc/dec verified ok")
    print ('phrase/key(hex)/enc+dec: {}/{}/{}'.format(phrase, key.encode('hex'), decrypted))

if __name__== "__main__":
    phrase= 'Ala ma kota, a kot ma AIDS.'
    key= os.urandom(32)
    testing123(phrase, key)
0
internety

Sie können dies tun, indem Sie zwei der integrierten Funktionen in der Standard-Python-Bibliothek verwenden. Die erste ist die Funktion ord () , die ein Unicode-String-Zeichen als einzigen Eingabeparameter übernimmt und in den entsprechenden Unicode-Code (eine Ganzzahl) konvertiert. Es gibt zwei einfache Beispiele für die Verwendung dieser Funktion:

>>> ord('a')
    97

>>> ord('b')
    98

Dann haben Sie auch die Umkehrfunktion von ord (): chr () . Und wie Sie sich vorstellen können, funktioniert es rundherum: Es hat einen Unicode-Code als Eingabe (Integer) und erhält das entsprechende Unicode-Zeichen (String):

>>> chr(97)
    'a'

>>> chr(98)
    'b'

Dann können Sie eine einfache Enkription durchführen, indem Sie eine beliebige ganze Zahl hinzufügen oder subtrahieren ... in diesem Fall die Zahl 2:

HINWEIS: Achten Sie darauf, dass Sie keine großen Werte angeben. Andernfalls erhalten Sie eine Fehler-ID, bei der Sie eine negative Zahl erreichen.

def encrypt(message):
    newS=''
    for car in message:
        newS=newS+chr(ord(car)+2)
    return newS


print(encrypt('hello world'))

Und als Ergebnis bekommen:

jgnnq"yqtnf

Jetzt können Sie dieselbe Funktion kopieren und an ihr vorbeiziehen und die Entschlüsselungsfunktion generieren. In diesem Fall muss natürlich von 2 abgezogen werden:

def decrypt(message):
    newS=''
    for car in message:
        newS=newS+chr(ord(car)-2)
    return newS


print(decrypt('jgnnq"yqtnf'))

Und das Ergebnis wird wieder die ursprüngliche Nachricht sein:

'hello world'

Dies wäre eine großartige Möglichkeit, Nachrichten an Nicht-Programmierer zu verschlüsseln. Jeder mit wenig Programmierkenntnissen könnte jedoch ein Programm schreiben, das die von uns verwendete ganze Zahl ändert, bis festgestellt wurde, dass wir den Unicode-Zeichen (2) gerade hinzugefügt haben, um den Code zu verschlüsseln ...

Um dies zu vermeiden, würde ich zwei komplexere Alternativen vorschlagen.

1. Die erste ist die einfachste: Sie besteht darin, je nach Position des Zeichens einen anderen Summenwert auf die Funktion chr anzuwenden (z. B. Hinzufügen von 2 zu jedem Unicode-Code, wenn er eine gerade Position in der Zeichenfolge belegt Zeichenfolge und Subtraktion 3, wenn an einer ungeraden Stelle sitzt).

2. Die zweite generiert die maximale Sicherheit. Es besteht darin, jeden Unicode-Code für eine Zahl hinzuzufügen oder zu subtrahieren, die für jedes Zeichen zufällig generiert wird. Es muss ein Array von Werten gespeichert werden, um die Nachricht zurückzuschreiben. Stellen Sie sicher, dass dieses Array von Werten für Dritte nicht verfügbar ist.

Da geht es eine mögliche Lösung für 1 .:

def encryptHard(message):
newS=''
for i in range(len(message)):
  if i%2==0:
    newS=newS+chr(ord(message[i])+2)
  else:
    newS=newS+chr(ord(message[i])-3)
return newS


print(encryptHard('hello world'))

Und das Ergebnis wäre:

jbniqyltif

Mit den hiermit dargestellten Informationen liegt das Entschlüsselungsskript auf der Hand, so dass ich Sie nicht mit dem Bewältigen, Verändern und Ändern von zwei Werten belästigen muss.

Lassen Sie uns schließlich eine eingehende Analyse der zweiten komplexeren Alternative durchführen. Mit diesem können wir sagen, dass die Einschreibung fast unbeschreiblich sein wird. Die Idee ist, den Wert, den wir zu jedem Unicode-Code addieren oder subtrahieren, durch eine Zufallszahl zwischen 0 und 255 zu variieren (dies ist der Zahlenbereich, den die Funktion chr () zulässt). Versuchen Sie also nicht, mit anderen Zahlen zu spielen definitiv einen Fehler bekommen).

In diesem Fall randomisiert mein Vorschlag auch die Operation (Summe oder Subtraktion) und vermeidet, dass die letzte Zahl eine 0 ist (d. H. Wir würden ein Originalzeichen erhalten). Schließlich gibt es auch eine Liste mit den Zahlen zurück, von denen es subtrahiert wurde. Diese Funktion benötigen Sie, um die Nachricht wieder zu entschlüsseln.

Die Wahrscheinlichkeit, dass Sie dieselbe verschlüsselte Nachricht erhalten, wenn Sie diese Funktion zweimal mit derselben Nachricht der Länge n aufrufen, liegt etwas in der Nähe von 255 ^ n ... Also machen Sie sich keine Sorgen (ich sage etwas) Da der erstellte Algorithmus tatsächlich mehr Wiederholungswerte im unteren oder oberen Wertebereich generiert, z. B. für den Fall, dass die häufigsten Zeichen in diesem Distrubution-Unicode-Caracrer-Satz (von 0 bis 255) nicht zentriert waren Ist das nicht der Fall, funktioniert das Programm einwandfrei und schützt die Informationen. 

import random as r
def encryptSuperHard(message):
  newS=''
  l_trans=[]
  for car in message:
    code=ord(car)
    add_subtract=r.choice([True,False])
    if add_subtract:
      transpose=r.randint(0,code-1)
      newS=newS+chr(code-transpose)
      l_trans=l_trans+[-transpose]
    else:
      transpose=r.randint(code+1,255)
      newS=newS+chr(code+transpose)
      l_trans=l_trans+[transpose]
  return newS, l_trans

print(encryptSuperHard('hello world'))

In diesem Fall hat dieses zufällige Verschlüsselungsskript, das ich erstellt habe, diesen Tupel mit zwei Werten zurückgegeben, wobei der erste Wert die verschlüsselte Nachricht ist und der zweite der Wert ist, der jedes Zeichen in der Reihenfolge seines Auftretens "transponiert" hat.

('A0ŤłY\x10řG;,à', [-39, -53, 248, 214, -22, -16,     226, -40, -55, -64, 124])

Entschlüsseln müsste in diesem Fall die verschlüsselte Nachricht und die Liste übernehmen und wie folgt vorgehen:

def decryptSuperHard(encriptedS,l):
  newS=''
  for i in range(len(l)):
    newS=newS+chr(ord(encriptedS[i])-l[i])
  return newS

print(decryptSuperHard('A0ŤłY\x10řG;,à', [-39,-53,248,214,-22,-16,226,-40,-55,-64,124]))

Und das Ergebnis geht zurück auf:

hallo Welt

print(deccryptSuperHard('A0ŤłY\x10řG;,à', [-39, -53, 248, 214, -22, -16,     226, -40, -55, -64, 124])
0
americansanti