Frage

Ich schreibe ein Stück Code, um einen Text mit einem symmetrischen Verschlüsselung zu verschlüsseln. Aber es ist nicht wieder mit dem richtigen Ergebnis kommen ...

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 wird der entschlüsselte Text unterscheidet sich vom Original ab.

Das verstehe ich nicht wirklich viel über Kryptographie so Bär bitte mit mir. Ich verstehe der CTR-Modus eine „Zähler“ -Funktion erfordert ein Zufallszähler jedes Mal zu liefern, aber warum braucht es es 16 Bytes zu sein, wenn meine Schlüssel 32 Bytes ist und es besteht darauf, dass meine Botschaft auch ein Vielfach von 16 Bytes ist? Ist das normal?

Ich vermute, dass es nicht auf die ursprüngliche Nachricht nicht zurück, weil der Zähler zwischen Ver- und Entschlüsselung geändert. Aber wie ist es theoretisch sowieso funktionieren soll? Was mache ich falsch? Wie dem auch sei, ich bin gezwungen, zurück zu EZB zurückgreifen, bis ich diese herausfinden: (

War es hilfreich?

Lösung

Die counter muss auf Entschlüsselung zurück, wie es auf Verschlüsselung tat, als Sie ahnen, so, ein ( haupt nicht sicher ) Art und Weise, es zu tun:

>>> 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 Block Chiffre, so dass die "16-at-a-time" Einschränkung, dass Sie zu überraschen scheint ein ziemlich natürlich ist.

Natürlich ist ein so genannten "Zähler" Rückführen des gleichen Wert bei jedem Aufruf ist grob unsicher . Braucht nicht viel besser zu machen, z ....:

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)

Andere Tipps

AES ist ein Blockchiffre : es ist ein Algorithmus (genauer gesagt, ein Paar von Algorithmen ), der einen Schlüssel und einen Nachrichtenblock, und entweder verschlüsselt oder entschlüsselt den Block annimmt. Die Größe eines Blocks ist immer 16 Bytes, unabhängig von der Schlüsselgröße.

CTR ist ein Betriebsart . Es ist ein Paar von Algorithmen, die auf einem Blockchiffre baut eine Stromchiffre zu erzeugen, die und Entschlüsseln von Nachrichten beliebiger Länge verschlüsseln können.

CTR funktioniert durch die Verschlüsselung von aufeinanderfolgenden Werten eines Zählers aufeinanderfolgende Nachrichtenblöcke zu kombinieren. Die Größe des Zählers Bedarf einen Block so sein, dass es für die Blockchiffre gültige Eingabe ist.

  • Funktionell ist es egal, was die aufeinanderfolgenden Werte des Zählers sind, solange die Verschlüsselung und Entschlüsselung Seite Verwendung der gleichen Reihenfolge. Gewöhnlich wird der Zähler so behandelt, als eine 256-Bit-Zahl und inkrementierte für jeden aufeinanderfolgenden Block, mit einem Anfangswert nach dem Zufallsprinzip ausgewählt. So, in der Regel wird die Inkrementierungsverfahren in den Code gebacken, aber die Entschlüsselungsseite muss wissen, was der Anfangswert ist, so Verschlüsselung Seite sendet oder speichert den Anfangszählerwert zu Beginn der verschlüsselten Nachricht.
  • Aus Sicherheitsgründen ist es wichtig, auf nie den gleichen Zählerwert mit einem bestimmten Schlüssel wiederholen . Also für eine Single-Taste, dann ist es in Ordnung, mit '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' zu starten. Aber wenn der Schlüssel mehrfach verwendet wird, dann die zweite Nachricht nicht der Zählerwerte durch die erste Nachricht verwendet, um Wiederverwendung erlaubt, und der einfachste Weg, um sicherzustellen, das heißt der Anfangszählerwert nach dem Zufallsprinzip zu erzeugen (mit einem 2 ^ 128 Raum, sind die Chancen einer Kollision sind in akzeptabler Weise zu vernachlässigen).

Indem der Anrufer eine Zählerfunktion wählen, die PyCrypto Bibliothek gibt Ihnen genügend Seil selbst zu hängen. Sie sollten Crypto.Util.Counter, nicht nur „für eine bessere Leistung“, wie die Dokumentation puts verwenden, aber, weil es etwas einfacher zu bauen sichern als das, was du bist kommen wahrscheinlich mit auf eigene Faust. Und selbst dann, kümmern sie einen zufälligen Anfangswert zu verwenden, die nicht die Standardeinstellung ist.

import binascii
import os
from Crypto.Cipher import AES
from Crypto.Util import Counter
def int_of_string(s):
    return int(binascii.hexlify(s), 16)
def encrypt_message(key, plaintext):
    iv = os.urandom(16)
    ctr = Counter.new(128, initial_value=int_of_string(iv))
    aes = AES.new(key, AES.MODE_CTR, counter=ctr)
    return iv + aes.encrypt(plaintext)
def decrypt_message(key, ciphertext):
    iv = ciphertext[:16]
    ctr = Counter.new(128, initial_value=int_of_string(iv))
    aes = AES.new(key, AES.MODE_CTR, counter=ctr)
    return aes.decrypt(ciphertext[16:])

Ich kann auf jeden Fall zu spät sein, und ich kann die bisherigen Antworten übersehen haben, aber ich habe nicht eine klare Aussage darüber, wie dies sollte (zumindest meiner Meinung nach) erfolgt gemäß den PyCrypto Paketen finden.

Das Crypto.Util.Counter Paket bietet aufrufbar Stateful Zähler, die sehr nützlich sind, aber es war einfach, zumindest für mich, sie nicht ordnungsgemäß verwendet werden.

Sie haben einen Zähler zu schaffen, mit z.B. ctr = Counter.new('parameters here'). Jedes Mal, wenn Ihr Zähler wird von Ihrem Zählermodus Chiffre-Objekt aufgerufen, die Nachricht zu verschlüsseln, wird erhöht. Dies ist für eine gute Kryptographie Praktiken erforderlich, sonst Informationen über gleiche Blöcke aus dem verschlüsselten Text austreten können.

Nun können Sie die Entschlüsselungsfunktion auf dem gleichen Chiffre-Objekt nicht nennen, weil es wieder die gleichen Zähler nennen würde, die in der Zwischenzeit erhöht wurden, möglicherweise mehrmals. Was Sie tun müssen, ist ein neues Chiffre-Objekt mit einem anderen Zähler mit den gleichen Parametern initialisiert zu erstellen. richtig auf diese Weise funktioniert die Entschlüsselung, den Zähler aus dem gleichen Ausgangspunkt wie die Verschlüsselung durchgeführt wurde.

Arbeits Beispiel unter:

# 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

Warum braucht es es 16 Bytes zu sein, wenn meine Schlüssel 32 Bytes

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

Weitere Informationen:

  1. der Zählerwert muss eindeutig sein - wenn Sie jemals den gleichen Zählerwert verwenden zwei verschiedene Klartexte unter dem gleichen Schlüssel zu verschlüsseln, du hast nur Ihre Schlüssel weg.
  2. wie ein IV, wird der Zähler nicht geheim - es ist nur zusammen mit dem verschlüsselten Text senden. Wenn Sie den Code mehr kompliziert, indem Sie versuchen es geheim zu halten, werden Sie wahrscheinlich selbst in den Fuß schießen.
  3. der Zählerwert muss nicht unvorhersehbar sein - beginnend bei Null und dem Hinzufügen einer für jeden Block ist völlig in Ordnung. Aber beachten Sie, dass, wenn Sie mehrere Nachrichten zu verschlüsseln, müssen Sie den Überblick über die Zählerwerte zu halten, die bereits verbraucht worden sind, dh Sie den Überblick behalten müssen, wie viele Blöcke haben bereits mit diesem Schlüssel verschlüsselt worden sind (und Sie können nicht die gleiche verwenden Schlüssel in verschiedenen Instanzen des Programms oder auf verschiedenen Rechnern).
  4. der Klartext kann beliebig lang sein -. CTR-Modus wird eine Blockchiffre in eine Stromchiffre

Standard Disclaimer: Crypto ist hart. Wenn Sie nicht verstehen, was Sie tun, Sie wird bekommen es falsch.

Ich möchte nur einige Passwörter über mehrere Sitzungen hinweg speichern.

Verwenden Scrypt. Scrypt umfasst encrypt und decrypt, die mit einem Kennwort abgeleiteten Schlüssel AES-CTR verwenden.

$ 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.'

Der Initialisierungsvektor ( „counter“) muss gleich bleiben, ebenso wie der Schlüssel der Fall ist, zwischen Verschlüsselung und Entschlüsselung. Es wird verwendet, so dass Sie den gleichen Text eine Million Mal kodieren können, und verschiedenen verschlüsselten Text jedes Mal erhalten (einige Crib und Pattern-Matching / Angriffe zu verhindern). Sie müssen noch die gleichen IV verwenden, wenn sie als Entschlüsseln bei der Verschlüsselung. Normalerweise, wenn Sie einen Stream starten zu entschlüsseln, initialisieren Sie die IV auf den gleichen Wert, dass Sie begann mit, wenn Sie begann diesen Strom zu verschlüsseln.

Siehe http://en.wikipedia.org/wiki/Initialization_vector für Informationen über Initialisierung Vektoren.

Beachten Sie, dass os.urandom (16) ist nicht ‚deterministisch‘, was eine Voraussetzung für die Zählerfunktionen ist. Ich schlage vor, Sie die Schrittfunktion verwenden, wie das ist, wie CTR-Modus ausgelegt ist. Der anfängliche Zählerwert sollte zufällig sein, aber die aufeinanderfolgenden Werte sollten von dem Anfangswert (deterministisch) vollständig vorhersagbar sein. Der Anfangswert auch gesorgt für Sie sein kann (ich weiß nicht, die Details)

über den Schlüssel, IV und Eingangsgrößen, es klingt wie die Chiffre Sie wählten eine Blockgröße von 16 Byte. Alles, was Sie beschreiben, passt das und scheint normal zu mir.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top