piątek, 6 marca 2009

PyCrypto - kryptografia w Pythonie

W bibliotece standartowej Python-a brak modułu służącego do szyfrowania. Pewne nadzieje może robić moduł crypto, lecz jest to moduł służący do łamamia haseł w Uniksie.

Na szczęście istnieje biblioteka PyCrypto pozwalająca na szyfrowanie zarówno z kluczem publicznym jak i symetryczne.

Szyfrowanie symetryczne

PyCrypto wspiera takie symetryczne algorytmy szyfrowania jak AES, Blowfish czy IDEA.

Używanie szyfrów symetrycznych jest dość proste. Przykładowo, aby zaszyfrować wiadomość przy użyciu AES:

>>> from Crypto.Cipher import AES
>>> mojKlucz = '1234567890ABCEFG'
>>> k = AES.new(mojKlucz) # klucz musi być ciągiem znaków i mieć długość 16, 24 lub 32 bajty.
>>> enc = k.encode('wiadomosc\0\0\0\0\0\0\0') # długość wiadomości musi być podzielna przez 16 
>>> enc
'2\xd61:<\xcaY\xe4\x9c\x8eE\xa5!?\x1e@'
>>> k.decode(enc)
'wiadomosc\0\0\0\0\0\0\0'
>>>

Szyfrowanie kluczem publicznym

PyCrypto obsługuje także wszystkie znaczące algorytmy szyfrowania kluczem publicznym np.: ElGamal, RSA, DSA. Użycie tych szyfrów jest równie proste jak w przypadku kryptografi symetrycznej.

>>> from Crypto.PublicKey import RSA 
>>> import os
>>> key = RSA.generate(2048, os.urandom) # generujemy klucz. 2048 - bity klucza, os.urandom - funkcja losowa
>>> key.decrypt(key.encrypt('tekst', None))
'tekst'
>>> key.verify('tekst', key.sign('tekst', None))
True
>>> key_as_tuple = [ getattr(key, name) for name in key.keydata ] # "wyciąganie" danych z klucza
>>> key_copy = RSA.construct(key_as_tuple) # i mamy kopię
>>> public_key = key.publickey() # klucz tylko do szyfrowania i weryfikowania
>>> 

Niestety RSA nie potrafi kodować dużych wiadomości (> 2kB) - należy wtedy uciec się do pomocy szyfrów symetrycznych:

  1. Wylosuj klucz AES.
    key = os.urandom(32)
    aes_key = AES.new(key)
    
  2. Zaszyfruj klucz AES kluczem RSA.
    cipher_key = rsa_key.encrypt(key)
    
  3. Zaszyfruj wiadomość kluczem AES.
    cipher_message = aes_key.encrypt(messsage)
    
  4. Zapisz zaszyfrowany klucz i zaszyfrowaną wiadomość.
    return cipher_key, cipher_message
    

Brak komentarzy: