PyCrypto Problem mit AES + CTR

Ich schreibe ein Stück Code, um einen Text mit symmetrischer Verschlüsselung zu verschlüsseln. Aber es kommt nicht mit dem richtigen Ergebnis zurück …

from Crypto.Cipher import AES import os crypto = AES.new(os.urandom(32), AES.MODE_CTR, counter = lambda : os.urandom(16)) encrypted = crypto.encrypt("aaaaaaaaaaaaaaaa") print crypto.decrypt(encrypted) 

Hier unterscheidet sich der entschlüsselte Text vom Original.

Ich verstehe nicht viel über Kryptographie, also bitte bei mir. Ich verstehe den CTR-Modus erfordert eine "Counter" -Funktion, um einen zufälligen Zähler jedes Mal zu liefern, aber warum braucht es es um 16 Bytes, wenn mein Schlüssel 32 Bytes ist und es besteht darauf, dass meine Nachricht in Vielfachen von 16 Bytes ist? Ist das normal?

Ich vermute, dass es nicht wieder auf die ursprüngliche Nachricht, weil der Zähler zwischen verschlüsseln und entschlüsseln geändert. Aber wie soll es dann eigentlich theoretisch arbeiten? Was mache ich falsch? Jedenfalls bin ich gezwungen, zurück zu EZB zurückzukehren, bis ich das herausfindet 🙁

    4 Solutions collect form web for “PyCrypto Problem mit AES + CTR”

    Der counter muss das gleiche auf Entschlüsselung zurückgeben wie bei der Verschlüsselung, wie du intuitest, also eine Möglichkeit, es zu tun ist:

     >>> secret = os.urandom(16) >>> crypto = AES.new(os.urandom(32), AES.MODE_CTR, counter=lambda: secret) >>> encrypted = crypto.encrypt("aaaaaaaaaaaaaaaa") >>> print crypto.decrypt(encrypted) aaaaaaaaaaaaaaaa 

    CTR ist eine Blockchiffre, also ist die "16-at-time" Einschränkung, die dich zu überraschen scheint, eine ziemlich natürliche.

    Natürlich wird ein so genannter "Counter", der bei jedem Aufruf denselben Wert zurückgibt, nicht besonders sicher. Dauert nicht viel besser, zB …:

     import array class Secret(object): def __init__(self, secret=None): if secret is None: secret = os.urandom(16) self.secret = secret self.reset() def counter(self): for i, c in enumerate(self.current): self.current[i] = c + 1 if self.current: break return self.current.tostring() def reset(self): self.current = array.array('B', self.secret) secret = Secret() crypto = AES.new(os.urandom(32), AES.MODE_CTR, counter=secret.counter) encrypted = crypto.encrypt(16*'a' + 16*'b' + 16*'c') secret.reset() print crypto.decrypt(encrypted) 

    Der Initialisierungsvektor ("Counter") muss gleich bleiben, genau wie der Schlüssel, zwischen Verschlüsselung und Entschlüsselung. Es wird so verwendet, dass man denselben Text eine Million Mal verschlüsseln kann und jedes Mal einen anderen Chiffretext bekommt (Verhinderung einiger bekannter Klartextangriffe und Musterabstimmung / Angriffe). Du musst immer noch das gleiche IV verwenden, wenn du mich entschlüsselt wie beim Verschlüsseln. Normalerweise, wenn Sie beginnen, einen Stream zu entschlüsseln, initialisieren Sie die IV auf denselben Wert, den Sie begonnen haben, als Sie begannen, diesen Stream zu verschlüsseln.

    Siehe http://de.wikipedia.org/wiki/Initialisierung_vector für Info über Initialisierungsvektoren.

    Beachten Sie, dass os.urandom (16) nicht "deterministisch" ist, was eine Voraussetzung für Gegenfunktionen ist. Ich schlage vor, Sie verwenden die Inkrement-Funktion, wie ist, wie CTR-Modus entworfen ist. Der Anfangszählerwert sollte zufällig sein, aber die sukzessiven Werte sollten aus dem Anfangswert (deterministisch) vollständig vorhersehbar sein. Der Anfangswert kann sogar für dich gesorgt werden (ich kenne die Details nicht)

    Über den Schlüssel, IV und Eingabegrößen klingt es wie die Chiffre, die du gewählt hast, hat eine Blockgröße von 16 Bytes. Alles, was du beschreibst, passt dazu und scheint mir normal zu sein.

    Warum braucht es es, um 16 Bytes zu sein, wenn mein Schlüssel 32 Bytes ist

    Es muss die gleiche Länge wie die Blockgröße der Chiffre sein. CTR-Modus verschlüsselt nur den Zähler und XORs den Klartext mit dem verschlüsselten Zählerblock.

    Notizen:

    1. Der Zählerwert muss eindeutig sein – wenn du jemals den gleichen Zählerwert benutzt, um zwei verschiedene Klartexte unter demselben Schlüssel zu verschlüsseln, hast du einfach deinen Schlüssel weggegeben.
    2. Wie ein IV, der Zähler ist nicht geheim – schick es einfach zusammen mit dem Chiffretext. Wenn du den Code komplizierter machst, indem du versuchst, ihn geheim zu halten, wirst du dich wahrscheinlich in den Fuß schießen.
    3. Der Zählerwert muss nicht unvorhersehbar sein – beginnend mit Null und Hinzufügen einer für jeden Block ist ganz gut (und am besten wegen seiner Einfachheit).
    4. Der Klartext kann beliebig sein – CTR-Modus wendet eine Blockchiffre in eine Stromchiffre um.

    Standard-Haftungsausschluss: Crypto ist schwer. Wenn du nicht verstehst, was du tust, wirst du es falsch machen

    Ich möchte nur einige Passwörter über Sessions speichern.

    Verwenden Sie scrypt. Scrypt schließt encrypt und decrypt die AES-CTR mit einem Passwort-Schlüssel verwendet.

     $ pip install scrypt $ python >>> import scrypt >>> import getpass >>> pw = getpass.getpass("enter password:") enter password: >>> encrypted = scrypt.encrypt("Guido is a space alien.",pw) >>> out = scrypt.decrypt(encrypted,pw) >>> out 'Guido is a space alien.' 

    Ich kann definitiv spät sein und ich kann die vorherigen Antworten übersehen haben, aber ich fand keine klare Aussage darüber, wie dies (zumindest IMHO) nach den PyCrypto-Paketen durchgeführt werden sollte.

    Das Crypto.Util.Counter-Paket bietet aufrufbare Stateful Counters, die sehr nützlich sind, aber es war zumindest für mich einfach, sie falsch zu benutzen.

    Sie müssen einen Zähler erstellen, zB mit ctr = Counter.new('parameters here') . Jedes Mal, wenn Ihr Zähler von Ihrem Counter-Modus Chiffre Objekt aufgerufen wird, um die Nachricht zu verschlüsseln, wird es inkrementiert. Dies ist für gute Kryptographie-Praktiken erforderlich, sonst können Informationen über gleiche Blöcke aus dem Chiffretext austreten.

    Nun können Sie die Entschlüsselungsfunktion nicht auf demselben Chiffre-Objekt aufrufen, denn es würde wieder den gleichen Zähler aufrufen, der inzwischen inkrementiert wurde, möglicherweise mehrmals. Was Sie tun müssen, ist, ein neues Chiffre-Objekt mit einem anderen Zähler zu erstellen, der mit denselben Parametern initialisiert wurde. Auf diese Weise funktioniert die Entschlüsselung ordnungsgemäß und startet den Zähler aus demselben Punkt wie die Verschlüsselung.

    Arbeitsbeispiel unten:

     # Import modules from Crypto.Cipher import AES from Crypto import Random from Crypto.Util import Counter # Pad for short keys pad = '# constant pad for short keys ##' # Generate a random initialization vector, to be used by both encryptor and decryptor # This may be sent in clear in a real communication random_generator = Random.new() IV = random_generator.read(8) # Encryption steps # Ask user for input and pad or truncate to a 32 bytes (256 bits) key prompt = 'Input your key. It will padded or truncated at 32 bytes (256 bits).\n-: ' user_keye = raw_input(prompt) keye = (user_keye + pad)[:32] # Create counter for encryptor ctr_e = Counter.new(64, prefix=IV) # Create encryptor, ask for plaintext to encrypt, then encrypt and print ciphertext encryptor = AES.new(keye, AES.MODE_CTR, counter=ctr_e) plaintext = raw_input('Enter message to cipher: ') ciphertext = encryptor.encrypt(plaintext) print ciphertext print # Decryption steps # Ask user for key: it must be equal to that used for encryption prompt = 'Input your key. It will padded or truncated at 32 bytes (256 bits).\n-: ' user_keyd = raw_input(prompt) keyd = (user_keyd + pad)[:32] # Create counter for decryptor: it is equal to the encryptor, but restarts from the beginning ctr_d = Counter.new(64, prefix=IV) # Create decryptor, then decrypt and print decoded text decryptor = AES.new(keyd, AES.MODE_CTR, counter=ctr_d) decoded_text = decryptor.decrypt(ciphertext) print decoded_text 
    Python ist die beste Programmiersprache der Welt.