2011-07-19 4 views
6

Próbuję przekonwertować ten kod C# do Pythona (2.5, GAE). Problem polega na tym, że zaszyfrowany łańcuch ze skryptu Pythona jest inny za każdym razem, gdy uruchamiane jest szyfrowanie (w tym samym łańcuchu).Python do C# AES CBC PKCS7

string Encrypt(string textToEncrypt, string passphrase) 
{ 
    RijndaelManaged rijndaelCipher = new RijndaelManaged(); 
    rijndaelCipher.Mode = CipherMode.CBC; 
    rijndaelCipher.Padding = PaddingMode.PKCS7; 

    rijndaelCipher.KeySize = 128; 
    rijndaelCipher.BlockSize = 128; 
    byte[] pwdBytes = Encoding.UTF8.GetBytes(passphrase); 
    byte[] keyBytes = new byte[16]; 
    int len = pwdBytes.Length; 
    if (len > keyBytes.Length) 
    { 
     len = keyBytes.Length; 
    } 
    Array.Copy(pwdBytes, keyBytes, len); 
    rijndaelCipher.Key = keyBytes; 
    rijndaelCipher.IV = new byte[16]; 
    ICryptoTransform transform = rijndaelCipher.CreateEncryptor(); 
    byte[] plainText = Encoding.UTF8.GetBytes(textToEncrypt); 
    return Convert.ToBase64String(transform.TransformFinalBlock(plainText, 0, plainText.Length)); 
} 

kod Pythona (PKCS7Encoder: http://japrogbits.blogspot.com/2011/02/using-encrypted-data-between-python-and.html)

from Crypto.Cipher import AES 
from pkcs7 import PKCS7Encoder 
#declared outside of all functions 
key = '####' 
mode = AES.MODE_CBC 
iv = '\x00' * 16 
encryptor = AES.new(key, mode, iv) 
encoder = PKCS7Encoder() 

def function(self): 
text = self.request.get('passwordTextBox') 
pad_text = encoder.encode(text) 
cipher = encryptor.encrypt(pad_text) 
enc_cipher = base64.b64encode(cipher) 

C# kod jest dziedziczona. Kod Pythona musi być szyfrowany i odszyfrowywany w ten sam sposób, aby kod C# mógł poprawnie zdekodować wartość.

Uwaga: jestem noobem w Pythonie :)

Edit: Przepraszam. Powinien był rozróżnić, że jest wywoływana funkcja.

Dzięki!

+2

Czy wiesz, jak działa tryb IV/CBC? Jeśli za każdym razem uruchamiasz ten kod pośredniczący, powinien on wytwarzać to samo wyjście dla tego samego wejścia. Jeśli jednak wielokrotnie wywołasz encryptor.encrypt z tym samym wejściem bez ponownego inicjowania szyfrowania (aby zresetować go do tego samego stanu początkowego), za każdym razem będzie generował inny wynik. – Foon

+0

Czy moja edycja zmienia Twój komentarz? jeśli nie, jaki jest najlepszy sposób, aby to naprawić? – Eonasdan

+0

naprawiono przez przeniesienie: encryptor = AES.new (klawisz, tryb, iv) do funkcji. Dzięki @Foon – Eonasdan

Odpowiedz

2

Twój kod C# jest nieprawidłowy.

Funkcja Encrypt trwa w haśle jako string passphrase ale potem próbuje odwoływać się do niej w tej linii byte[] pwdBytes = Encoding.UTF8.GetBytes(key);

Zmian key do passphrase.

Dwie funkcje produkują teraz identyczne wyniki dla mnie:

Python

secret_text = 'The rooster crows at midnight!' 
key = 'A16ByteKey......' 
mode = AES.MODE_CBC 
iv = '\x00' * 16 

encoder = PKCS7Encoder() 
padded_text = encoder.encode(secret_text) 

e = AES.new(key, mode, iv) 
cipher_text = e.encrypt(padded_text) 

print(base64.b64encode(cipher_text)) 

# e = AES.new(key, mode, iv) 
# cipher_text = e.encrypt(padded_text) 
# print(base64.b64encode(cipher_text)) 

C# (z poprawką typo wspomniano powyżej)

Console.WriteLine(Encrypt("The rooster crows at midnight!", "A16ByteKey......")); 

Python Wynik

XAW5KXVbItrc3WF0xW175UJoiAfonuf + s54w2iEs + 7A =

C# Wynik

XAW5KXVbItrc3WF0xW175UJoiAfonuf + s54w2iEs + 7A =

Podejrzewam jesteś ponowne wykorzystanie 'e' w Pythonie koduj wiele razy. Jeśli odkomentujesz dwa ostatnie wiersze mojego skryptu python, zobaczysz, że dane wyjściowe są teraz inne. Ale jeśli odkomentujesz ostatnie trzy linie, zobaczysz, że dane wyjściowe są takie same. Jak powiedział Foon, jest to spowodowane how CBC works.

CBC (łańcuchy bloków szyfrowania) działa podczas szyfrowania sekwencji bajtów w blokach. Pierwszy blok jest zaszyfrowany poprzez włączenie IV z pierwszymi bajtami twojego zwykłego tekstu ("Kogut ..."). Drugi blok wykorzystuje wynik pierwszej operacji zamiast IV.

Po ponownym wywołaniu e.encrypt() (np. Przez wykluczenie dwóch ostatnich wierszy skryptu Pythona) przechodzisz do miejsca, w którym zostało przerwane. Zamiast używać IV podczas szyfrowania pierwszego bloku, użyje wyjścia ostatniego zaszyfrowanego bloku. Dlatego wyniki wyglądają inaczej. Przez niepowiadomienie ostatnich trzech wierszy skryptu Pythona inicjalizujesz nowy szyfrator, który będzie używał IV dla swojego pierwszego bloku, powodując uzyskanie identycznych wyników.

+0

masz rację. linia w moim kodzie C# powinna mieć odczyt: byte [] pwdBytes = Encoding.UTF8.GetBytes (passphrase) ;. naprawiony w oryginalnym – Eonasdan

+0

Świetnie dobrze objaśniony post, ale zakodowałem go i wciąż otrzymuję inny zaszyfrowany tekst, używając tego samego kodu, który miałeś powyżej. Jakieś pomysły? Używam Visual C# 2010 Express i Python 2.7.2 z pycrypto 2.3.1. Połączyłem stronę Pythona zarówno w systemie Linux, jak i Windows (ActiveState Python) z tymi samymi wynikami - po prostu nie można tego dopasować do C#. – spidie

3

zmieniony kod Pythona do:

from Crypto.Cipher import AES 
from pkcs7 import PKCS7Encoder 
#declared outside of all functions 
key = '####' 
mode = AES.MODE_CBC 
iv = '\x00' * 16 
encoder = PKCS7Encoder() 

def function(self): 
encryptor = AES.new(key, mode, iv)** 
text = self.request.get('passwordTextBox') 
pad_text = encoder.encode(text) 
cipher = encryptor.encrypt(pad_text) 
enc_cipher = base64.b64encode(cipher) 

w przypadku gdy ktoś osiąga tę stronę za pomocą google

+0

+1, ponieważ z jednej strony doceniam, że poświęcają Państwo na to czas. – Foon

0

Ten esotic koder PKCS7 to coś innego niż funkcja, która posiada statyczną długość. Więc wprowadziły go z samym chipie kodu

#!/usr/bin/env python 

from Crypto.Cipher import AES 
import base64 

# the block size for the cipher object; must be 16, 24, or 32 for AES 
BLOCK_SIZE = 16 

# the character used for padding--with a block cipher such as AES, the value 
# you encrypt must be a multiple of BLOCK_SIZE in length. This character is 
# used to ensure that your value is always a multiple of BLOCK_SIZE 

# PKCS7 method 
PADDING = '\x06' 
mode = AES.MODE_CBC 
iv = '\x08' * 16 # static vector: dangerous for security. This could be changed periodically 
# 

# one-liner to sufficiently pad the text to be encrypted 
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING 

# one-liners to encrypt/encode and decrypt/decode a string 
# encrypt with AES, encode with base64 
EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s))) 
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING) 



def CryptIt(password, secret): 
    cipher = AES.new(secret, mode, iv) 
    encoded = EncodeAES(cipher, password) 
    return encoded 

def DeCryptIt(encoded, secret): 
    cipher = AES.new(secret, mode, iv) 
    decoded = DecodeAES(cipher, encoded) 
    return decoded 

mam nadzieję, że to może pomóc. Pozdrowienia

+0

Zadałem to pytanie (i przyjąłem odpowiedź) w lipcu 2011 prawie 2 lata temu! Twoja odpowiedź może pomóc innym w przyszłości, ale już dawno przeniosłem się z tego projektu – Eonasdan

0

Implementacja Microsoft PKCS7 jest nieco inna niż w Pythonie.

Ten artykuł bardzo mi pomógł z tym problemem: http://japrogbits.blogspot.com/2011/02/using-encrypted-data-between-python-and.html

Jego kod do kodowania PKCS7 i dekodowania jest na github tutaj: https://github.com/janglin/crypto-pkcs7-example

Z tej biblioteki PKCS7, kod ten pracował dla mnie:

from Crypto.Cipher import AES 

aes = AES.new(shared_key, AES.MODE_CBC, IV) 
aes.encrypt(PKCS7Encoder().encode(data)) 
Powiązane problemy