it-swarm.com.de

Verschlüsseln und Entschlüsseln mit PyCrypto AES 256

Ich versuche, zwei Funktionen mit PyCrypto zu erstellen, die zwei Parameter akzeptieren: die Nachricht und den Schlüssel und dann die Nachricht verschlüsseln/entschlüsseln.

Ich habe im Internet mehrere Links gefunden, die mir helfen, aber jeder von ihnen hat Fehler:

Dieses bei codekoala verwendet os.urandom, was von PyCrypto nicht empfohlen wird.

Darüber hinaus ist es nicht garantiert, dass der Schlüssel, den ich der Funktion gebe, genau die erwartete Länge hat. Was kann ich tun, um das zu erreichen?

Außerdem gibt es mehrere Modi. Welcher wird empfohlen? Ich weiß nicht, was ich verwenden soll: /

Was genau ist die IV? Kann ich eine andere IV zum Verschlüsseln und Entschlüsseln bereitstellen oder wird dies zu einem anderen Ergebnis führen?

Folgendes habe ich bisher gemacht:

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

BLOCK_SIZE=32

def encrypt(message, passphrase):
    # passphrase MUST be 16, 24 or 32 bytes long, how can I do that ?
    IV = Random.new().read(BLOCK_SIZE)
    aes = AES.new(passphrase, AES.MODE_CFB, IV)
    return base64.b64encode(aes.encrypt(message))

def decrypt(encrypted, passphrase):
    IV = Random.new().read(BLOCK_SIZE)
    aes = AES.new(passphrase, AES.MODE_CFB, IV)
    return aes.decrypt(base64.b64decode(encrypted))
136
Cyril N.

Hier ist meine Implementierung und funktioniert für mich mit einigen Korrekturen und verbessert die Ausrichtung des Schlüssels und der geheimen Phrase um 32 Bytes und IV bis 16 Bytes:

import base64
import hashlib
from Crypto import Random
from Crypto.Cipher import AES

class AESCipher(object):

    def __init__(self, key): 
        self.bs = 32
        self.key = hashlib.sha256(key.encode()).digest()

    def encrypt(self, raw):
        raw = self._pad(raw)
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return base64.b64encode(iv + cipher.encrypt(raw))

    def decrypt(self, enc):
        enc = base64.b64decode(enc)
        iv = enc[:AES.block_size]
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')

    def _pad(self, s):
        return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)

    @staticmethod
    def _unpad(s):
        return s[:-ord(s[len(s)-1:])]
109
mnothic

Möglicherweise benötigen Sie die folgenden zwei Funktionen zum Auffüllen (bei Verschlüsselung) und Aufheben (bei Entschlüsselung), wenn die Länge der Eingabe kein Vielfaches von BLOCK_SIZE ist.

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

Sie fragen also nach der Länge des Schlüssels? Sie können die MD5-Summe des Schlüssels verwenden, anstatt sie direkt zu verwenden.

Aufgrund meiner geringen Erfahrung bei der Verwendung von PyCrypto wird die IV dazu verwendet, die Ausgabe einer Verschlüsselung zu mischen, wenn die Eingabe gleich ist. Daher wird die IV als zufällige Zeichenfolge ausgewählt und als Teil der Verschlüsselungsausgabe verwendet Verwenden Sie es, um die Nachricht zu entschlüsseln.

Und hier ist meine Implementierung, hoffe es wird für Sie nützlich sein:

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

class AESCipher:
    def __init__( self, key ):
        self.key = key

    def encrypt( self, raw ):
        raw = pad(raw)
        iv = Random.new().read( AES.block_size )
        cipher = AES.new( self.key, AES.MODE_CBC, iv )
        return base64.b64encode( iv + cipher.encrypt( raw ) ) 

    def decrypt( self, enc ):
        enc = base64.b64decode(enc)
        iv = enc[:16]
        cipher = AES.new(self.key, AES.MODE_CBC, iv )
        return unpad(cipher.decrypt( enc[16:] ))
139
Marcus

Lassen Sie mich Ihre Frage zu "Modi" beantworten. AES256 ist eine Art Blockchiffre. Als Eingabe werden ein 32-Byte-String key und ein 16-Byte-String mit dem Namen block verwendet und ein Block ausgegeben. Wir verwenden AES in einer Betriebsart, um zu verschlüsseln. Die obigen Lösungen schlagen die Verwendung von CBC vor, was ein Beispiel ist. Eine andere Methode heißt CTR und ist etwas einfacher zu bedienen:

from Crypto.Cipher import AES
from Crypto.Util import Counter
from Crypto import Random

# AES supports multiple key sizes: 16 (AES128), 24 (AES192), or 32 (AES256).
key_bytes = 32

# Takes as input a 32-byte key and an arbitrary-length plaintext and returns a
# pair (iv, ciphtertext). "iv" stands for initialization vector.
def encrypt(key, plaintext):
    assert len(key) == key_bytes

    # Choose a random, 16-byte IV.
    iv = Random.new().read(AES.block_size)

    # Convert the IV to a Python integer.
    iv_int = int(binascii.hexlify(iv), 16) 

    # Create a new Counter object with IV = iv_int.
    ctr = Counter.new(AES.block_size * 8, initial_value=iv_int)

    # Create AES-CTR cipher.
    aes = AES.new(key, AES.MODE_CTR, counter=ctr)

    # Encrypt and return IV and ciphertext.
    ciphertext = aes.encrypt(plaintext)
    return (iv, ciphertext)

# Takes as input a 32-byte key, a 16-byte IV, and a ciphertext, and outputs the
# corresponding plaintext.
def decrypt(key, iv, ciphertext):
    assert len(key) == key_bytes

    # Initialize counter for decryption. iv should be the same as the output of
    # encrypt().
    iv_int = int(iv.encode('hex'), 16) 
    ctr = Counter.new(AES.block_size * 8, initial_value=iv_int)

    # Create AES-CTR cipher.
    aes = AES.new(key, AES.MODE_CTR, counter=ctr)

    # Decrypt and return the plaintext.
    plaintext = aes.decrypt(ciphertext)
    return plaintext

(iv, ciphertext) = encrypt(key, 'hella')
print decrypt(key, iv, ciphertext)

Dies wird oft als AES-CTR bezeichnet. Ich rate zur Vorsicht bei der Verwendung von AES-CBC mit PyCrypto. Der Grund dafür ist, dass Sie das Auffüllschema angeben müssen, wie in den anderen angegebenen Lösungen veranschaulicht. Im Allgemeinen, wenn Sie nicht sehr vorsichtig mit der Polsterung sind, gibt es Angriffe , die die Verschlüsselung vollständig aufheben !

Nun ist es wichtig zu beachten, dass der Schlüssel eine zufällige 32-Byte-Zeichenfolge sein muss; ein Passwort reicht nicht aus Normalerweise wird der Schlüssel folgendermaßen generiert:

# Nominal way to generate a fresh key. This calls the system's random number
# generator (RNG).
key1 = Random.new().read(key_bytes)

Ein Schlüssel kann von einem Passwort abgeleitet sein auch:

# It's also possible to derive a key from a password, but it's important that
# the password have high entropy, meaning difficult to predict.
password = "This is a rather weak password."

# For added # security, we add a "salt", which increases the entropy.
#
# In this example, we use the same RNG to produce the salt that we used to
# produce key1.
salt_bytes = 8 
salt = Random.new().read(salt_bytes)

# Stands for "Password-based key derivation function 2"
key2 = PBKDF2(password, salt, key_bytes)

Einige der obigen Lösungen schlagen die Verwendung von SHA256 zum Ableiten des Schlüssels vor, dies wird jedoch allgemein als schlechte kryptografische Praxis angesehen. Lesen Sie wikipedia , um mehr über die Betriebsarten zu erfahren.

10
tweaksp

Für jemanden, der urlsafe_b64encode und urlsafe_b64decode verwenden möchte, sind hier die Versionen, die für mich funktionieren (nachdem ich einige Zeit mit dem Unicode-Problem verbracht habe)

BS = 16
key = hashlib.md5(settings.SECRET_KEY).hexdigest()[:BS]
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
unpad = lambda s : s[:-ord(s[len(s)-1:])]

class AESCipher:
    def __init__(self, key):
        self.key = key

    def encrypt(self, raw):
        raw = pad(raw)
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return base64.urlsafe_b64encode(iv + cipher.encrypt(raw)) 

    def decrypt(self, enc):
        enc = base64.urlsafe_b64decode(enc.encode('utf-8'))
        iv = enc[:BS]
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return unpad(cipher.decrypt(enc[BS:]))
6
Hoang HUA

Sie können eine Passphrase aus einem beliebigen Kennwort erhalten, indem Sie eine kryptografische Hashfunktion (NICHTPython's hash) wie SHA-1 oder SHA-256 verwenden. Python unterstützt beide in seiner Standardbibliothek:

import hashlib

hashlib.sha1("this is my awesome password").digest() # => a 20 byte string
hashlib.sha256("another awesome password").digest() # => a 32 byte string

Sie können einen kryptografischen Hashwert einfach mit [:16] oder [:24] abschneiden, und die Sicherheit wird bis zu der von Ihnen angegebenen Länge beibehalten.

6
nneonneo

Zum Wohle anderer ist hier meine Implementierung der Entschlüsselung, zu der ich durch die Kombination der Antworten von @Cyril und @Marcus gekommen bin. Dies setzt voraus, dass diese über HTTP-Request mit dem in verschlüsselten verschlüsselten Text und base64-codiertem Eingang eingehen.

import base64
import urllib2
from Crypto.Cipher import AES


def decrypt(quotedEncodedEncrypted):
    key = 'SecretKey'

    encodedEncrypted = urllib2.unquote(quotedEncodedEncrypted)

    cipher = AES.new(key)
    decrypted = cipher.decrypt(base64.b64decode(encodedEncrypted))[:16]

    for i in range(1, len(base64.b64decode(encodedEncrypted))/16):
        cipher = AES.new(key, AES.MODE_CBC, base64.b64decode(encodedEncrypted)[(i-1)*16:i*16])
        decrypted += cipher.decrypt(base64.b64decode(encodedEncrypted)[i*16:])[:16]

    return decrypted.strip()
5
scottmrogowski

Eine andere Einstellung zu diesem (stark von den obigen Lösungen abgeleiteten) aber

  • verwendet null zum Auffüllen 
  • verwendet kein Lambda (war noch nie ein Fan)
  • getestet mit Python 2.7 und 3.6.5

    #!/usr/bin/python2.7
    # you'll have to adjust for your setup, e.g., #!/usr/bin/python3
    
    
    import base64, re
    from Crypto.Cipher import AES
    from Crypto import Random
    from Django.conf import settings
    
    class AESCipher:
        """
          Usage:
          aes = AESCipher( settings.SECRET_KEY[:16], 32)
          encryp_msg = aes.encrypt( 'ppppppppppppppppppppppppppppppppppppppppppppppppppppppp' )
          msg = aes.decrypt( encryp_msg )
          print("'{}'".format(msg))
        """
        def __init__(self, key, blk_sz):
            self.key = key
            self.blk_sz = blk_sz
    
        def encrypt( self, raw ):
            if raw is None or len(raw) == 0:
                raise NameError("No value given to encrypt")
            raw = raw + '\0' * (self.blk_sz - len(raw) % self.blk_sz)
            raw = raw.encode('utf-8')
            iv = Random.new().read( AES.block_size )
            cipher = AES.new( self.key.encode('utf-8'), AES.MODE_CBC, iv )
            return base64.b64encode( iv + cipher.encrypt( raw ) ).decode('utf-8')
    
        def decrypt( self, enc ):
            if enc is None or len(enc) == 0:
                raise NameError("No value given to decrypt")
            enc = base64.b64decode(enc)
            iv = enc[:16]
            cipher = AES.new(self.key.encode('utf-8'), AES.MODE_CBC, iv )
            return re.sub(b'\x00*$', b'', cipher.decrypt( enc[16:])).decode('utf-8')
    
2
MIkee

Es ist wenig spät, aber ich denke, das wird sehr hilfreich sein. Niemand erwähnt ein Verwendungsschema wie das PKCS # 7-Padding. Sie können stattdessen die vorherigen Funktionen zum Auffüllen (bei der Verschlüsselung) und zum Aufheben (bei der Entschlüsselung) verwenden.

import base64
import hashlib
from Crypto import Random
from Crypto.Cipher import AES
import pkcs7
class Encryption:

    def __init__(self):
        pass

    def Encrypt(self, PlainText, SecurePassword):
        pw_encode = SecurePassword.encode('utf-8')
        text_encode = PlainText.encode('utf-8')

        key = hashlib.sha256(pw_encode).digest()
        iv = Random.new().read(AES.block_size)

        cipher = AES.new(key, AES.MODE_CBC, iv)
        pad_text = pkcs7.encode(text_encode)
        msg = iv + cipher.encrypt(pad_text)

        EncodeMsg = base64.b64encode(msg)
        return EncodeMsg

    def Decrypt(self, Encrypted, SecurePassword):
        decodbase64 = base64.b64decode(Encrypted.decode("utf-8"))
        pw_encode = SecurePassword.decode('utf-8')

        iv = decodbase64[:AES.block_size]
        key = hashlib.sha256(pw_encode).digest()

        cipher = AES.new(key, AES.MODE_CBC, iv)
        msg = cipher.decrypt(decodbase64[AES.block_size:])
        pad_text = pkcs7.decode(msg)

        decryptedString = pad_text.decode('utf-8')
        return decryptedString

import StringIO
import binascii


def decode(text, k=16):
    nl = len(text)
    val = int(binascii.hexlify(text[-1]), 16)
    if val > k:
        raise ValueError('Input is not padded or padding is corrupt')

    l = nl - val
    return text[:l]


def encode(text, k=16):
    l = len(text)
    output = StringIO.StringIO()
    val = k - (l % k)
    for _ in xrange(val):
        output.write('%02x' % val)
    return text + binascii.unhexlify(output.getvalue())

2

Dankbar für die anderen Antworten, die mich inspirierten, aber nicht funktionierten. 

Nachdem ich stundenlang versucht hatte herauszufinden, wie es funktioniert, habe ich mir die Implementierung der neuesten PyCryptodomex - Bibliothek vorgenommen (es ist eine andere Geschichte, wie ich es geschafft habe, es hinter Proxy, Windows, in einer Virtualenv .. Puh) 

Denken Sie daran, an Ihrer Implementierung Padding-, Kodierungs-, Verschlüsselungsschritte (und umgekehrt) aufzuschreiben. Sie müssen die Bestellung einpacken und auspacken.

 import base64 
 import hashlib 
 aus Cryptodome.Cipher importieren AES 
 aus Cryptodome.Random import get_random_bytes 

__ key__ = hashlib.sha256 (b'16-character key '). digest () 

 def verschlüsseln (roh): 
 BS = AES.block_size 
 pad = Lambda s: s + (BS - len (s)% BS) * chr (BS - len (s)% BS) 

 raw = base64.b64encode (pad (raw) .encode ('utf8')) 
 iv = get_random_bytes (AES.block_size) 
 cipher = AES.new (Schlüssel = __key__, Modus = AES.MODE_CFB, iv = iv) 
 return base64.b64encode (iv + cipher.encrypt (raw)) 

 def decrypt (enc): 
 unpad = lambda s: s [: - ord (s [-1:])] 

 enc = base64.b64decode (enc) 
 iv = enc [: AES.block_size] 
 cipher = AES.new (__ key__, AES.MODE_CFB, iv) 
 Rückgabe eines unpad (base64.b64decode (cipher.decrypt (enc [AES.block_size:])).. decode ('utf8')) 
1
cenkarioz

Ich habe sowohl Crypto als auch PyCryptodomex Bibliothek verwendet und es ist blitzschnell ...

import base64
import hashlib
from Cryptodome.Cipher import AES as domeAES
from Cryptodome.Random import get_random_bytes
from Crypto import Random
from Crypto.Cipher import AES as cryptoAES


BLOCK_SIZE=16

key = "my_secret_key".encode()
__key__ = hashlib.sha256(key).digest()
print(__key__)


def encrypt(raw):
    BS = cryptoAES.block_size
    pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
    raw = base64.b64encode(pad(raw).encode('utf8'))
    iv = get_random_bytes(cryptoAES.block_size)
    cipher = cryptoAES.new(key= __key__, mode= cryptoAES.MODE_CFB,iv= iv)
    a= base64.b64encode(iv + cipher.encrypt(raw))
    IV = Random.new().read(BLOCK_SIZE)
    aes = domeAES.new(__key__, domeAES.MODE_CFB, IV)
    b = base64.b64encode(IV + aes.encrypt(a))
    return b

def decrypt(enc):
    passphrase = __key__
    encrypted = base64.b64decode(enc)
    IV = encrypted[:BLOCK_SIZE]
    aes = domeAES.new(passphrase, domeAES.MODE_CFB, IV)
    enc = aes.decrypt(encrypted[BLOCK_SIZE:])
    unpad = lambda s: s[:-ord(s[-1:])]
    enc = base64.b64decode(enc)
    iv = enc[:cryptoAES.block_size]
    cipher = cryptoAES.new(__key__, cryptoAES.MODE_CFB, iv)
    b=  unpad(base64.b64decode(cipher.decrypt(enc[cryptoAES.block_size:])).decode('utf8'))
    return b

encrypted_data =encrypt("Hi Steven!!!!!")
print(encrypted_data)
print("=======")
decrypted_data = decrypt(encrypted_data)
print(decrypted_data)
1
Smack Alpha
from Crypto import Random
from Crypto.Cipher import AES
import base64

BLOCK_SIZE=16
def trans(key):
     return md5.new(key).digest()

def encrypt(message, passphrase):
    passphrase = trans(passphrase)
    IV = Random.new().read(BLOCK_SIZE)
    aes = AES.new(passphrase, AES.MODE_CFB, IV)
    return base64.b64encode(IV + aes.encrypt(message))

def decrypt(encrypted, passphrase):
    passphrase = trans(passphrase)
    encrypted = base64.b64decode(encrypted)
    IV = encrypted[:BLOCK_SIZE]
    aes = AES.new(passphrase, AES.MODE_CFB, IV)
    return aes.decrypt(encrypted[BLOCK_SIZE:])
0
yuen

https://stackoverflow.com/a/21928790/11402877

kompatible utf-8 Kodierung

def _pad(self, s):
    s = s.encode()
    res = s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs).encode()
    return res
0
sixiyizai