2014-10-02 23 views
7

Varolan .NET sınıflarımızın şifresini çözebilecekleri metni şifreleyecek bir Python modülü yazmaya çalışıyorum. Anlayabildiğim kadarıyla kod satırlarım yukarı ancak şifresini çözmüyor (C# tarafındaki 'Geçersiz bir dolgu uzunluğu' hatası alıyorum). Pkcs7 kodum iyi görünüyor, ancak araştırma geçersiz anahtarların aynı soruna neden olabileceğini gösteriyor.PBKDF2 Python anahtarları vs .NET Rfc2898

Bu iki kurulum arasında ne fark var? Python:

derived_key = PBKDF2(crm_key, salt, 256/8, iterations) 
iv = PBKDF2(crm_key, salt, 128/8, iterations) 

encoder = pkcs7.PKCS7Encoder() 

cipher = AES.new(derived_key, AES.MODE_CBC, iv) 
decoded = cipher.decrypt(encoded_secret) 

#encode - just stepped so i could debug. 
padded_secret = encoder.encode(secret)    # 1 
encodedtext = cipher.encrypt(padded_secret)   # 2 
based_secret = base64.b64encode(encodedtext)  # 3 

O based_secret C# kadar geçmiş olsun diye düşündüm ve orada deşifre. Ama başarısız oluyor. Aynı şifreleyerek C# kodu: Ben kullanıyorum

var rfc = new Rfc2898DeriveBytes(key, saltBytes); 


     // create provider & encryptor 
     using (var cryptoProvider = new AesManaged()) 
     { 
      // Set cryptoProvider parameters 
      cryptoProvider.BlockSize = cryptoProvider.LegalBlockSizes[0].MaxSize; 
      cryptoProvider.KeySize = cryptoProvider.LegalKeySizes[0].MaxSize; 

      cryptoProvider.Key = rfc.GetBytes(cryptoProvider.KeySize/8); 
      cryptoProvider.IV = rfc.GetBytes(cryptoProvider.BlockSize/8); 

      using (var encryptor = cryptoProvider.CreateEncryptor()) 
      { 
       // Create a MemoryStream. 
       using (var memoryStream = new MemoryStream()) 
       { 
        // Create a CryptoStream using the MemoryStream and the encryptor. 
        using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) 
        { 
         // Convert the passed string to a byte array. 
         var valueBytes = Encoding.UTF8.GetBytes(plainValue); 

         // Write the byte array to the crypto stream and flush it. 
         cryptoStream.Write(valueBytes, 0, valueBytes.Length); 
         cryptoStream.FlushFinalBlock(); 

         // Get an array of bytes from the 
         // MemoryStream that holds the 
         // encrypted data. 
         var encryptBytes = memoryStream.ToArray(); 

         // Close the streams. 
         cryptoStream.Close(); 
         memoryStream.Close(); 

         // Return the encrypted buffer. 
         return Convert.ToBase64String(encryptBytes); 
        } 
       } 
      } 

Python pkcs7 uygulamasıdır: https://gist.github.com/chrix2/4171336

+1

denemek istiyorum ilk şey oluşturulan anahtar C# ve Python aynı olup olmadığını kontrol etmektir. – NullUserException

+0

C# anahtar çıktısı bir bayt dizisi ve Python'daki bir UTF-8 dizesidir. Bunları doğru bir şekilde karşılaştırmak için, .ToBase64 (csharpKey) ve base64.encode (pythonkey) 'ı Dönüştürebilir miyim? Bu bana benzer öğeleri almalı mı? – shelbydz

+0

Bir ton araştırma yaptıktan sonra yardımcı olan birkaç şey buldum: Rfc2898DeriveBytes.GetBytes'in ilk örneği ve PBKDF2'ye yapılan çağrı aynı anahtarı üretiyor. Ancak, MSDN'ye göre, GetBytes yeni bir anahtar oluşturmak için çağrıları birleştiriyor. GetBytes (IV) almak için ikinci kez, çıktı tamamen farklı. – shelbydz

cevap

7

Öncelikle, ben Rfc2898 ve PBKDF2 aynı şey olduğunu doğruladı. Daha sonra, yukarıda belirtildiği gibi, sorun bir .net ism olarak görünmektedir. Her aramada, örneğin, Rfc2898DeriveBytes'in içindeki GetBytes uygulamasının değiştiğini, yani msdn

adresinde buldum. devleti tutar. (Yine sözde çıkış) .NET

derived_key = PBKDF2(key, salt, 32, 1000) 
iv = PBKDF2(key, salt, 16, 1000) 
print(base64.b64encode(derived_key)) 
print(base64.b64encode(iv)) 
$123456789101112134== 
$12345678== 

aynı (imsi) kodu: Python (sözde çıkış) içinde

Örnek (sayfa yarıya ilgili açıklamalara bakınız)

var rfc = new Rfc2898DeriveBytes(key, saltBytes); 
    using (var cryptoProvider = new AesManaged()) 
    { 
     // Set cryptoProvider parameters 
     cryptoProvider.BlockSize = cryptoProvider.LegalBlockSizes[0].MaxSize; 
     cryptoProvider.KeySize = cryptoProvider.LegalKeySizes[0].MaxSize; 

     cryptoProvider.Key = rfc.GetBytes(cryptoProvider.KeySize/8); 
     cryptoProvider.IV = rfc.GetBytes(cryptoProvider.BlockSize/8); 
    } 
Console.Writeline(Convert.ToBase64(cryptoProvider.Key)); 
Console.Writeline(Convert.ToBase64(cryptoProvider.IV)); 

$123456789101112134== 
$600200300== 

Sonraki çağrılar rfc.GetBytes her zaman farklı sonuçlar üretir. MSDN, çağrılarda anahtar boyutlarını birleştirdiğini söylüyor. Yani GetBytes (20), iki kez çağırırsanız, GetBytes (20 + 20) veya GetBytes (40) 'ı çağırmakla aynı şeydir. Teorik olarak, bu sadece anahtarın boyutunu arttırmalı, tamamen değiştirmemelidir.

Bu sorunun üstesinden gelmek için bazı çözümler vardır; bu, ilk çağrıda daha uzun bir anahtar oluşturabilir ve sonra hem türetilmiş bir anahtar hem de IV'e dilimleyebilir veya rastgele bir IV oluşturarak kodlanmış iletiye ekleyebilir. ve şifresini çözmeden önce onu soymak.

Python çıktısının kesilmesi, .NET ile aynı sonuçları verir. Bu şuna benzer:

derived_key = PBKDF2(key, salt, 32, 1000) 
iv = PBKDF2(key, salt, 32 + 16, 1000) # We need 16, but we're compensating for .NETs 'already called' awesomeness on the GetBytes method 
split_key = iv[32:] 

print(base64.b64encode(derived_key)) 
print(base64.b64encode(iv)) 
print(base64.b64encode(split_key)) 

$ 123456789101112134== # matches our derived key 
$ 12345678== # doesn't match 
$ 600200300== # matches. this is the base 64 encoded version of the tailing 16 bytes. 

Enjoy,