2010-05-12 6 views
7

Mam szyfrowanie AES wykonywane na dwóch kolumnach: jedna z tych kolumn jest przechowywana w bazie danych SQL Server ; drugi jest przechowywany w bazie danych SQL Server .Jak uzyskać zgodność między szyfrowaniem AES a SQL2k8?

Ponieważ baza danych pierwszej kolumny (2000) nie ma natywnej funkcjonalności do szyfrowania/odszyfrowywania, zdecydowaliśmy się na logikę kryptografii na poziomie aplikacji, z klasami .NET, dla obu.

Jednak jako że baza danych drugiej kolumny (2008) pozwala na tego rodzaju funkcjonalność, chcielibyśmy, aby migracja danych za pomocą funkcji bazy danych była szybsza, ponieważ migracja danych w SQL 2k jest znacznie mniejsza niż ta druga i potrwa dłużej niż 50 godzin, ponieważ jest wykonywany na poziomie aplikacji.

Mój problem rozpoczął się w tym momencie: używając tego samego klucza, nie osiągnąłem tego samego wyniku podczas szyfrowania wartości, ani tego samego rozmiaru wyniku.

Poniżej mamy pełną logikę w obie strony .. Oczywiście ja nie wykazujące klucz, ale wszystko inne jest takie samo:

private byte[] RijndaelEncrypt(byte[] clearData, byte[] Key) 
{ 
    var memoryStream = new MemoryStream(); 

    Rijndael algorithm = Rijndael.Create(); 

    algorithm.Key = Key; 
    algorithm.IV = InitializationVector; 

    var criptoStream = new CryptoStream(memoryStream, algorithm.CreateEncryptor(), CryptoStreamMode.Write); 
    criptoStream.Write(clearData, 0, clearData.Length); 
    criptoStream.Close(); 

    byte[] encryptedData = memoryStream.ToArray(); 
    return encryptedData; 
} 

private byte[] RijndaelDecrypt(byte[] cipherData, byte[] Key) 
{ 
    var memoryStream = new MemoryStream(); 

    Rijndael algorithm = Rijndael.Create(); 

    algorithm.Key = Key; 
    algorithm.IV = InitializationVector; 

    var criptoStream = new CryptoStream(memoryStream, algorithm.CreateDecryptor(), CryptoStreamMode.Write); 

    criptoStream.Write(cipherData, 0, cipherData.Length); 

    criptoStream.Close(); 

    byte[] decryptedData = memoryStream.ToArray(); 

    return decryptedData; 
} 

To jest przykładowy kod SQL:

open symmetric key columnKey decryption by password = N'{pwd!!i_ll_not_show_it_here}' 

declare @enc varchar(max) 

set @enc = dbo.VarBinarytoBase64(EncryptByKey(Key_GUID('columnKey'), 'blablabla')) 

select LEN(@enc), @enc 

To varbinaryToBase64 to przetestowana funkcja sql, której używamy do konwertowania varbinary do tego samego formatu, którego używamy do przechowywania ciągów w aplikacji .net.

Wynik w C# jest: eg0wgTeR3noWYgvdmpzTKijkdtTsdvnvKzh + uhyN3Lo =

Taki sam wynik w SQL2k8 jest: AI0zI7D77EmqgTQrdgMBHAEAAACyACXb + P3HvctA0yBduAuwPS4Ah3AB4Dbdj2KBGC1Dk4b8GEbtXs5fINzvusp8FRBknF15Br2xI1CqP0Qb/M4W

po prostu jeszcze nie dostać to, co robię źle.

Czy masz jakieś pomysły?

EDIT: Jeden punkt myślę, że ma kluczowe znaczenie: Mam jeden wektor inicjujący w moim kodu C#, 16 bajtów. Ta IV nie jest ustawiona na klucz symetryczny SQL, czy mógłbym to zrobić?

Ale nawet nie wypełniając IV w C#, otrzymuję bardzo różne wyniki, zarówno pod względem treści, jak i długości.

+0

Czy jest coś w dokumentacji, która stwierdza, że ​​dwa algorytmy szyfrowania są w rzeczywistości takie same? – Joe

+0

mówią, że oba są AES, prawda? Myślałem, że to wystarczy, aby zapewnić pewne współdziałanie .. –

Odpowiedz

5

Istnieje kilka rzeczy bym spojrzeć na:

  1. Bądź absolutnie pewien, że tekst jawny jest identyczne w treści i kodowania. IIRC, domyślnie strumieniami są UTF-8, natomiast jeśli twoja funkcja VarBinaryToBase64 przyjmuje parametr nvarchar, będzie to kod Unicode.

  2. Upewnij się, że oba algorytmy szyfrowania używają tego samego rozmiaru bloku. W SQL, określasz algorytm, kiedy wywołujesz CREATE SYMMETRIC KEY. Jeśli nie określisz algorytmu, użyje AES256. W .NET przy użyciu RijndaelManaged, domyślny rozmiar bloku jest 128, ale można ustawić go na 256 (nie można, jeśli używasz klasy Aes).

  3. Ostatnią rzeczą, której szukam, jest to, jak SQL Server zajmuje się wektorami inicjalizacji, o czym wspomniałeś w swoim zmienionym wpisie. Chcę powiedzieć, że używa on do tego parametru authenticator, ale jest to dzikie domysły.

EDIT

byłem daleko. Zważywszy na to, co odkryłem, nie można użyć klasy .NET do odszyfrowania tekstu zaszyfrowanego przez wbudowane szyfrowanie programu SQL Server, ponieważ SQL Server dodaje wiele lepusów do tego, co zostanie zaszyfrowane, w tym losowy wektor inicjalizacyjny. Z książki Michaela Cole'a „Pro T-SQL 2005 programisty Guide” (choć 2008 robi to w taki sam sposób):

Kiedy SQL Server szyfruje przez symetrycznego klucza, dodaje metadane do zaszyfrowanego rezultacie, jak również padding, dzięki czemu zaszyfrowany wynik jest większy (czasami znacznie większy) niż niezaszyfrowany zwykły tekst . Format zaszyfrowany wynik z metadanych następujący format:

  • pierwszych 16 bajtów zaszyfrowanych wyniku reprezentowania GUID klucza symetrycznego używany do szyfrowania danych
  • Kolejne 4 bajty reprezentują numer wersji, obecnie oznaczony na stałe jako "01000000".
  • Następne 8 bajtów dla szyfrowania DES (16 bajtów dla szyfrowania AES) reprezentuje losowo wygenerowany wektor inicjujący .
  • Następne 8 bajtów to informacje nagłówkowe reprezentujące opcje służące do szyfrowania danych. Jeśli użyta jest opcja uwierzytelnienia , ta informacja nagłówkowa zawiera 20-bajtowy mieszacz SHA1 z autentyfikatora, co powoduje, że ma informacje o nagłówku o długości 28 bajtów o długości .
  • Ostatnią częścią zaszyfrowanych danych są rzeczywiste dane i dopełnienie. W przypadku algorytmów DES długość zaszyfrowanych danych będzie wielokrotnością 8 bajtów. W przypadku algorytmów AES długość będzie wielokrotnością 16 bajtów.
+0

Sądząc po długości wyjściowej (84 bajty przed kodowaniem base64), nie sądzę, że SQL Server używa AES256. Jednak nie jest to wielokrotność liczby 16. Dość dziwne. – Thorarin

+0

@Thorarin - Believe Coles mówi tylko, że dopełnienie danych + będzie wielokrotnością 16, a nie całym szyfrem. Zatem 84 mniej 36-bajtowego nagłówka to 48 bajtów, co jest wielokrotnością 16. – Thomas

+0

Ah, twoja edycja znacznie poprawia to, przynajmniej wyjaśnia, dlaczego pierwsze 18 znaków base64 było takich samych, a reszta ciągle się zmienia ... Jednak , odszyfrowanie z .NET powinno być możliwe teraz, gdy znasz układ nagłówka. Szyfrowanie, którego nie jestem pewien, zależy od skrótu SHA1. – Thorarin

1

Niezupełnie odpowiedź, ale za duża na komentarz. Być może pomoże to komuś innemu dowiedzieć się :)
SQL Server wydaje się robić dużo dopełnienia. Kiedy próbowałem twojego przykładu, ciągle otrzymywałem różne wyniki, chociaż pierwsze 18 znaków wydaje się być za każdym razem takie samo. Dla mnie to jednak nie ma sensu ...

Nie pokazuje się, jak wywoływane jest RijndaelEncrypt, ale przy różnych długościach danych zastanawiałem się nad różnicami w kodowaniu Unicode i ANSI. Wydaje się jednak, że nie używasz unicode w SQL Server, więc różnica długości byłaby odwrotna, jeśli w ogóle.