2009-04-13 11 views
12

Używam klasy .NET 3.0 klasy System.Security.Cryptography.MACTripleDES do generowania wartości MAC. Niestety pracuję z urządzeniem sprzętowym, które używa "1111111111111111" (jako hex) jako klucz DES o pojedynczej długości. Biblioteka System.Security.Cryptography wykonuje pewne sprawdzanie poprawności na kluczu i zwraca wyjątek, jeśli spróbujesz użyć słabego klucza kryptograficznego.TripleDES: Określony klucz jest znanym słabym kluczem dla "TripleDES" i nie może być używany

Na przykład:

byte[] key = new byte[24]; 
for (int i = 0; i < key.Length; i++) 
    key[i] = 0x11; 

byte[] data = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 
byte[] computedMac = null; 
using (MACTripleDES mac = new MACTripleDES(key)) 
{ 
    computedMac = mac.ComputeHash(data); 
} 

zgłasza wyjątek

System.Security.Cryptography.CryptographicException : Specified key is a known weak key for 'TripleDES' and cannot be used. 

wiem, że to nie jest bezpieczny klucz. Podczas produkcji urządzenie będzie migać nowym, bezpiecznym kluczem. Czy w międzyczasie istnieje jakiś sposób, aby powstrzymać ten Wyjątek przed rzuceniem? Być może ustawienia rejestru lub app.config?

Edytuj: Klucz byłby w rzeczywistości 101010 ... z powodu algorytmu wymuszającego nieparzystą parzystość. Nie jestem pewien, czy jest to uniwersalne dla algorytmu DES, czy tylko wymaganie w przetwarzaniu płatności, które wykonuję.

Edycja 2: Poniższa odpowiedź Daniela zawiera bardzo dobre informacje o hakowaniu .NET. Niestety, nie mogłem rozwiązać mojego problemu za pomocą tej techniki, ale wciąż jest tam interesująca lektura.

+0

(Re: Twój edit) DES i 3DES tylko korzysta z Top 7 bitów każdy bajt w kluczu. Najmniej znaczący bit jest zwykle używany jako bit parzystości. –

+0

Chciałbym wrócić do domu. Wydaje się dziwne, że coś takiego byłoby egzekwowane na poziomie biblioteki. Osoby używające szyfrowania powinny wiedzieć, jak trudniej odgadnąć klucze, a biblioteka nie powinna egzekwować tych rzeczy. – Kibbee

+1

@Kibbee, Słaby klucz w tym kontekście nie oznacza "trudny do odgadnięcia". Oznacza to klucz, dla którego określony algorytm wykazuje pewne zdegenerowane zachowanie, które je osłabia. – caf

Odpowiedz

1

Zamiast używać MACTripleDES z powtarzanym klawiszem DES, aby sfałszować pojedynczy DES CBC-MAC, można po prostu zaimplementować CBC-MAC samodzielnie pod numerem DESCryptoServiceProvider.

< 1111111111111111> nie jest słabym kluczem DES.

Ten obliczy DES CBC-MAC:

public static byte[] CalcDesMac(byte[] key, byte[] data){ 
     DESCryptoServiceProvider des = new DESCryptoServiceProvider(); 
     des.Key = key; 
     des.IV = new byte[8]; 
     des.Padding = PaddingMode.Zeros; 
     MemoryStream ms = new MemoryStream(); 
     using(CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write)){ 
      cs.Write(data, 0, data.Length); 
     } 
     byte[] encryption = ms.ToArray(); 
     byte[] mac = new byte[8]; 
     Array.Copy(encryption, encryption.Length-8, mac, 0, 8); 
     PrintByteArray(encryption); 
     return mac; 
    } 
+0

To działa dobrze. Myślę, że skupiłem się właśnie na klasie MACTripleDES, która, gdybym ją przemyślała, jest naprawdę używana tylko dla Triple DES, a nie pojedynczego DES. Szkoda, że ​​nie zajęło mi to roku, abym przeczytał twoją odpowiedź! Skończyłem wdrażanie CBC-MAC ręcznie. –

1

Niestety tego zachowania nie można przesłonić.

6

Naprawdę nie polecam, ale powinieneś być w stanie zmodyfikować IL-kod, który sprawdza słabych kluczy wykorzystujących Reflector oraz dodatek ReflexIL

edit:

Niestety, zajęło trochę czasu, abym załadował to wszystko na mojej maszynie wirtualnej (z systemem Ubuntu) i nie chciał zepsuć Mono.

  • Instalacja REFLEXIL Add-in: Widok -> dodatki -> Dodaj
  • Otwórz REFLEXIL: Narzędzia -> REFLEXIL v0.9
  • Znajdź funkcję IsWeakKey(). (Możesz użyć Search: F3)
  • Pojawią się dwie funkcje, dwukrotnie kliknij tę znalezioną w System.Security.Cryptography.TripleDES
  • ReflexIL również powinien pojawić się. Na karcie Instrukcje przewiń całą drogę w dół do linii 29 (przesunięcie 63).
  • Zmień ldc.i4.1 na ldc.i4.0, co oznacza, że ​​funkcja zawsze zwróci false.

W panelu złożeń (po lewej) można teraz przewinąć w górę i kliknąć "Common Language Runtime Library", panel ReflexIL daje możliwość zapisania go.

Ważne uwagi:

  • wykonać kopię zapasową oryginalnego zespołu pierwszy! (mscorlib.dll)
  • mscorlib.dll to podpisany zespół i będziesz potrzebować pakietu .NET SDK (sn.exe) dla ReflexIL, aby pominąć weryfikację. Właśnie to sprawdziłem, powinieneś już to mieć z zainstalowanym Visual C#. Wystarczy kliknąć "Zarejestruj się, aby pominąć weryfikację (na tym komputerze)", gdy zostaniesz o to poproszony.
  • Nie sądzę, muszę ci powiedzieć, aby to wykorzystać tylko na jednym komputerze :)

powodzenia! Jeśli potrzebujesz dodatkowych instrukcji, użyj komentarza.

Edit2:

Jestem mylić!

http://i44.tinypic.com/2r6fwbo_th.png

Całkowicie usunięto kontrolę IsWeakKey z funkcji set_Key w zespole mscorlib. Jestem absolutnie pewien, że zmodyfikowałem poprawną funkcję i że zrobiłem to poprawnie. Dezasembler reflektora nie pokazuje już czeku. Zabawne jest jednak to, że Visual C# wciąż rzuca ten sam wyjątek.

To prowadzi mnie do przekonania, że ​​mscorlib musi jakoś zostać gdzieś zbuforowany. Jednak zmiana nazwy mscorlib.dll na mscorlib.dll_ prowadzi MSVC# do awarii, więc nadal musi być zależna od oryginalnej biblioteki dll.

To bardzo ciekawe rzeczy, ale myślę, że doszedłem do punktu, w którym nie mam pojęcia, co się dzieje, to po prostu nie ma sensu! Zobacz załączony obraz. :(

Edit3:

zauważam w Olly, że w przeciwieństwie do zespołów takich jak Mscoree, mscorsec i mscorwks; mscorlib.dll nie jest w rzeczywistości znajduje się w: C: \ WINDOWS \ Microsoft.NET \ Framework \ v2.0.50727 \

ale zamiast tego, w co wydaje się być nieistniejąca lokalizacja: C: \ WINDOWS \ assembly \ NativeImages_v2.0.50727_32 \ mscorlib \ 6d667f19d687361886990f3ca0f49816 \ mscorlib.ni.dll

myślę Coś tu brakuje :) Zajmę się tym dalej.

edit4:

Nawet po połatany się wszystkiego w IsWeakKey i bawił się zarówno usuwanie i tworzenie nowych rodzimych obrazów (x. ni .dll) z użyciem pliku mscorlib.dll „ngen.exe” Otrzymuję ten sam wyjątek. Należy zauważyć, że nawet po odinstalowaniu natywnych obrazów mscorlib, nadal używa on mscorlib.ni.dll ... Meh.

Poddaję się. Mam nadzieję, że ktoś będzie w stanie odpowiedzieć na pytanie, do diabła, ponieważ ja na pewno nie wiem. :)

+0

Dość ciekawe rozwiązanie! Poprawiłem mój plik mscorlib.dll, ale nie zmieniło się zachowanie funkcji. Czy ta biblioteka dll jest gdzieś zbuforowana? Zmieniam tylko .... \ Microsoft.NET \ Framework \ v2.0.50737 \ mscorlib.dll. –

+0

Właśnie przetestowałem kod, masz rację. Zbadam i zgłoś się ponownie :) –

+0

To co najmniej dziwne. Teraz zmieniłem rzeczywistą kontrolę IsWeakKey na set_Key(), i robi to samo. Musi być gdzieś zbuforowana.Zbadam jeszcze trochę :) –

0

Nie jestem ekspertem od zabezpieczeń, ale czy nie wystarczyłoby XORing twojego klucza z inną wartością, aby spełnić test poczytalności? Możesz to zrobić dla swojej wersji debugowania (z właściwym IFDEF), abyś mógł dokonać właściwego sprawdzenia i usunąć go dla wydania lub wersji produkcyjnej, w której klucz byłby wystarczająco silny.

+0

To by naprawdę zadowoliło sprawdzanie poprawności, ale sprzęt, z którym pracuje, nadal używa oryginalnego klucza. –

+0

Tak. Właśnie o tym myślałem. Myślałem o tym tylko z punktu widzenia kodu i nawet nie brałem pod uwagę sprzętu. My Bad :) –

4

znalazłem się, co trzeba zrobić.Na szczęście istnieje dostępna metoda, która tworzy ICryptoTranforms, które nie sprawdza słabych kluczy. Musisz także uważać na klasę podstawową, ponieważ sprawdza też stan zdrowia psychicznego. Poprzez odbicie po prostu wywołaj metodę _NewEncryptor (musisz zrobić trochę więcej refleksji, ale taki jest pomysł).

Na szczęście MACTripLEDES ma pole typu TripleDES, więc wywodzi się z MACTripLEDES i zastępuje je przez odbicie w konstruktorach. Wykonałem dla ciebie całą pracę.

Nie mogę zweryfikować poprawności adresu MAC, ale nie są zgłaszane żadne wyjątki. Co więcej, możesz chcieć dodać komentarz do kodu i wykonać obsługę wyjątku (błędy odbicia - np. Jeśli pola/metody tam nie ma) - ale to jest SO; więc nie zawracałem sobie głowy.

using System; 
using System.Reflection; 
using System.Security.Cryptography; 
using System.IO; 

namespace DesHack 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      byte[] key = new byte[24]; 
      for (int i = 0; i < key.Length; i++) 
       key[i] = 0x11; 

      byte[] data = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 
      byte[] computedMac = null; 
      using (MACTripleDES mac = new MACTripleDESHack(key)) 
      { 
       computedMac = mac.ComputeHash(data); 
      } 
     } 
    } 

    class MACTripleDESHack : MACTripleDES 
    { 
     TripleDES _desHack = new DesHack(); 

     static FieldInfo _cspField = typeof(MACTripleDES).GetField("des", BindingFlags.Instance | BindingFlags.NonPublic); 

     public MACTripleDESHack() 
      : base() 
     { 
      RewireDes(); 
     } 

     public MACTripleDESHack(byte[] rgbKey) 
      : base(rgbKey) 
     { 
      RewireDes(); 
     } 

     private void RewireDes() 
     { 
      _cspField.SetValue(this, _desHack); 
     } 

    } 

    class DesHack : TripleDES 
    { 
     TripleDESCryptoServiceProvider _backing = new TripleDESCryptoServiceProvider(); 

     static MethodInfo _newEncryptor; 
     static object _encrypt; 
     static object _decrypt; 

     public override int BlockSize 
     { 
      get 
      { 
       return _backing.BlockSize; 
      } 
      set 
      { 
       _backing.BlockSize = value; 
      } 
     } 

     public override int FeedbackSize 
     { 
      get 
      { 
       return _backing.FeedbackSize; 
      } 
      set 
      { 
       _backing.FeedbackSize = value; 
      } 
     } 

     // For these two we ALSO need to avoid 
     // the base class - it also checks 
     // for weak keys. 
     private byte[] _iv; 
     public override byte[] IV 
     { 
      get 
      { 
       return _iv; 
      } 
      set 
      { 
       _iv = value; 
      } 
     } 

     private byte[] _key; 
     public override byte[] Key 
     { 
      get 
      { 
       return _key; 
      } 
      set 
      { 
       _key = value; 
      } 
     } 

     public override int KeySize 
     { 
      get 
      { 
       return _backing.KeySize; 
      } 
      set 
      { 
       _backing.KeySize = value; 
      } 
     } 

     public override KeySizes[] LegalBlockSizes 
     { 
      get 
      { 
       return _backing.LegalBlockSizes; 
      } 
     } 

     public override KeySizes[] LegalKeySizes 
     { 
      get 
      { 
       return _backing.LegalKeySizes; 
      } 
     } 

     public override CipherMode Mode 
     { 
      get 
      { 
       return _backing.Mode; 
      } 
      set 
      { 
       _backing.Mode = value; 
      } 
     } 

     public override PaddingMode Padding 
     { 
      get 
      { 
       return _backing.Padding; 
      } 
      set 
      { 
       _backing.Padding = value; 
      } 
     } 


     static DesHack() 
     { 
      _encrypt = typeof(object).Assembly.GetType("System.Security.Cryptography.CryptoAPITransformMode").GetField("Encrypt").GetValue(null); 
      _decrypt = typeof(object).Assembly.GetType("System.Security.Cryptography.CryptoAPITransformMode").GetField("Decrypt").GetValue(null); 
      _newEncryptor = typeof(TripleDESCryptoServiceProvider).GetMethod("_NewEncryptor", BindingFlags.NonPublic | BindingFlags.Instance); 
     } 

     public DesHack() 
     {    
     } 

     public override ICryptoTransform CreateDecryptor() 
     { 
      return CreateDecryptor(_key, _iv); 
     } 

     public override ICryptoTransform CreateEncryptor() 
     { 
      return CreateEncryptor(_key, _iv); 
     } 

     public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV) 
     { 
      // return this._NewEncryptor(rgbKey, base.ModeValue, rgbIV, base.FeedbackSizeValue, CryptoAPITransformMode.Decrypt); 
      return (ICryptoTransform) _newEncryptor.Invoke(_backing, 
       new object[] { rgbKey, ModeValue, rgbIV, FeedbackSizeValue, _decrypt }); 
     } 

     public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV) 
     { 
      // return this._NewEncryptor(rgbKey, base.ModeValue, rgbIV, base.FeedbackSizeValue, CryptoAPITransformMode.Encrypt); 
      return (ICryptoTransform) _newEncryptor.Invoke(_backing, 
       new object[] { rgbKey, ModeValue, rgbIV, FeedbackSizeValue, _encrypt }); 
     } 

     public override void GenerateIV() 
     { 
      _backing.GenerateIV(); 
     } 

     public override void GenerateKey() 
     { 
      _backing.GenerateKey(); 
     } 

     protected override void Dispose(bool disposing) 
     { 
      if (disposing) 
       ((IDisposable) _backing).Dispose(); 
      base.Dispose(disposing); 
     } 
    } 
} 
-1

Rozwiązania refleksja oparta Ci sobie z tym problemem, ale są brudne i złe. Nikt jeszcze nie wspomniał o bardzo użyteczną metodę: TripleDES.IsWeakKey

miałem ten problem i rozwiązać go z bardzo proste narzędzie, które mogę wykorzystać natychmiast, zanim ustawić klucz na moim CryptoServiceProvider:

private void MakeSecureKey(byte[] key) 
{ 
    while(TripleDES.IsWeakKey(key)) 
    { 
     var sha = SHA256Managed.Create().ComputeHash(key); 
     Array.Copy(sha,key,key.Length); 
    } 
} 

Jeśli zadzwonisz w dowolnym momencie, gdy utworzysz szyfrujące lub odszyfrowujące, powinno to zapobiec awarii i zawsze dać ci bezpieczny klucz.

+0

To naprawdę nie pomaga, jeśli trzeba współdziałać z urządzeniem, które wymaga określonego klucza. –

+0

Wystarczająco fair. Pomyślałem, że dodam go tutaj, ponieważ jest to numer jeden trafiony w Google dla tego błędu i może być przydatny dla kogoś w nieco innej sytuacji. – captncraig

-1

Dość proste (Po obejrzeniu kodu z GitHub)

static bool TripleDES.IsWeakKey (Byte [] rgbKey)

Ponieważ jest statyczna - jest łatwy do testowania klucz przeciwko niemu

  1. Rozmiar musi być 16 lub 24 bajty (???) Dlaczego nie można umieścić go w dokumentacji
  2. Sprawdzanie kodu dla kilku prostych powtórzeń Wystarczy utworzyć losowy enuogh wartości

patrz kod na: https://github.com/mono/mono/blob/master/mcs/class/corlib/System.Security.Cryptography/TripleDES.cs

Dekel

Powiązane problemy