2011-06-23 62 views
6

Muszę przesłać pliki XML i muszą one zostać zaszyfrowane. Znalazłem kilka przykładów, że jestem blisko, ale kiedy odszyfrowuję plik, kończę na ciągłych znakach śmieciowych. Jest kilka postów na ten temat, ale nie widziałem żadnych, które dokładnie pomogą. Oto szyfrowanie i odszyfrowywanie kodu.Używanie Rijndael do szyfrowania/odszyfrowywania plików

private void EncryptFile(string inputFile, string outputFile, string key) { 
    try { 
     byte[] keyBytes; 
     keyBytes = Encoding.Unicode.GetBytes(key); 

     Rfc2898DeriveBytes derivedKey = new Rfc2898DeriveBytes(key, keyBytes); 

     RijndaelManaged rijndaelCSP = new RijndaelManaged(); 
     rijndaelCSP.Key = derivedKey.GetBytes(rijndaelCSP.KeySize/8); 
     rijndaelCSP.IV = derivedKey.GetBytes(rijndaelCSP.BlockSize/8); 

     ICryptoTransform encryptor = rijndaelCSP.CreateEncryptor(); 

     FileStream inputFileStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read); 

     byte[] inputFileData = new byte[(int)inputFileStream.Length]; 
     inputFileStream.Read(inputFileData, 0, (int)inputFileStream.Length); 

     FileStream outputFileStream = new FileStream(outputFile, FileMode.Create, FileAccess.Write); 

     CryptoStream encryptStream = new CryptoStream(outputFileStream, encryptor, CryptoStreamMode.Write); 
     encryptStream.Write(inputFileData, 0, (int)inputFileStream.Length); 
     encryptStream.FlushFinalBlock(); 

     rijndaelCSP.Clear(); 
     encryptStream.Close(); 
     inputFileStream.Close(); 
     outputFileStream.Close(); 
    } 
    catch (Exception ex) { 
     MessageBox.Show(ex.Message, "Encryption Failed!", MessageBoxButtons.OK, MessageBoxIcon.Error); 
     return; 
    } 

    MessageBox.Show("File Encryption Complete!"); 

} 

private void DecryptFile(string inputFile, string outputFile, string key) { 
    try { 
     byte[] keyBytes = Encoding.Unicode.GetBytes(key); 

     Rfc2898DeriveBytes derivedKey = new Rfc2898DeriveBytes(key, keyBytes); 

     RijndaelManaged rijndaelCSP = new RijndaelManaged(); 
     rijndaelCSP.Key = derivedKey.GetBytes(rijndaelCSP.KeySize/8); 
     rijndaelCSP.IV = derivedKey.GetBytes(rijndaelCSP.BlockSize/8); 
     ICryptoTransform decryptor = rijndaelCSP.CreateDecryptor(); 

     FileStream inputFileStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read); 

     CryptoStream decryptStream = new CryptoStream(inputFileStream, decryptor, CryptoStreamMode.Read); 

     byte[] inputFileData = new byte[(int)inputFileStream.Length]; 
     decryptStream.Read(inputFileData, 0, (int)inputFileStream.Length); 

     FileStream outputFileStream = new FileStream(outputFile, FileMode.Create, FileAccess.Write); 
     outputFileStream.Write(inputFileData, 0, inputFileData.Length); 
     outputFileStream.Flush(); 

     rijndaelCSP.Clear(); 

     decryptStream.Close(); 
     inputFileStream.Close(); 
     outputFileStream.Close(); 
    } 
    catch (Exception ex) { 
     MessageBox.Show(ex.Message, "Decryption Failed!", MessageBoxButtons.OK, MessageBoxIcon.Error); 
     return; 
    } 

    MessageBox.Show("File Decryption Complete!"); 
} 

I skończyć z

<?xml version="1.0" encoding="UTF-8"?> 
<transaction> 
    <header> 
    <qOrderNumber></qOrderNumber> 
    <qRequestDate></qRequestDate> 
    <testOrder></testOrder> 
    <qCustomerNumber></qCustomerNumber> 
    <transactionStatus></transactionStatus> 
    </header> 
    <lines> 
    <line> 
     <productID></productID> 
     <serialNumber></serialNumber> 
    </line> 
    <line> 
     <productID></productID> 
     <serialNumber></serialNumber> 
    </line> 
    </lines> 
</transaction>NULNULNULNULNULNUL 

Odpowiedz

10

Podczas odszyfrowywania zwracaj uwagę na wartość zwracaną przez wywołanie CryptoStream.Read. Informuje o długości odszyfrowanych danych w tablicy bajtów (zwykle nie będzie ona odpowiadać długości zaszyfrowanych danych z powodu dopełnienia). Spróbuj użyć następujących funkcji deszyfrujących:

int decrypt_length = decryptStream.Read(inputFileData, 0, (int)inputFileStream.Length); 
FileStream outputFileStream = new FileStream(outputFile, FileMode.Create, FileAccess.Write); 
outputFileStream.Write(inputFileData, 0, decrypt_length); 
+0

I mamy zwycięzcę !!!! Wielkie dzięki! – mjames

2

na obiekcie RijndaelManaged, należy ustawić właściwość Padding do PaddingMode.ANSIX923 lub PaddingMode.ISO10126.

Te puste bajty zostały dodane, aby wypełnić ostatni zaszyfrowany blok. Został domyślnie dopełniony zerami, co oznacza, że ​​nie podano informacji o rzeczywistej długości danych. Pozostałe tryby wypełniania zawierają długość w bajcie końcowym, dzięki czemu można usunąć wypełnienie po odszyfrowaniu.

Ustaw właściwość padding zarówno w procedurze szyfrowania i odszyfrowywania na tę samą wartość.

rijndaelCSP.Padding = PaddingMode.ANSIX923; 

Jeśli wie, czego się spodziewać, strumień odszyfrowujący automatycznie usunie dopełnienie, więc żadne dalsze zmiany nie będą konieczne.

UPDATE

Od patrząc na kod, wydaje się, że liczba bajtów, które piszesz do pliku wyjściowego jest równa liczbie bajtów do odczytu z pliku wejściowego.

byte[] inputFileData = new byte[(int)inputFileStream.Length]; 
decryptStream.Read(inputFileData, 0, (int)inputFileStream.Length); 

Proces deszyfrowania nie zamierza całkowicie wypełnić tablicę inputFileData, ze względu na dopełnienie w wejściu.

Strumień wyjściowy wypisze następnie całą długość bufora, mimo że nie został całkowicie wypełniony.

outputFileStream.Write(inputFileData, 0, inputFileData.Length); 

To jest źródło twoich zer.

Być może zechcesz zmienić sposób szyfrowania i deszyfrowania, aby nie używać już buforów o stałej długości. Ewentualnie możesz przechowywać długość zaszyfrowanych danych na początku i pisać tylko liczbę bajtów odpowiadających tej długości.

+0

+1 Spotkałem się z tym w przeszłości. Uważam, że jest to rozwiązanie, które go naprawiłem. –

+0

Próbowałem obu tych trybów wypełniania i uzyskać ten sam wynik. – mjames