2013-11-22 38 views
6

Piszę metodę rozszerzenia, która upraszcza tworzenie skrótów, usuwając tonę płyty głównej, ale moim problemem jest to, że za każdym razem, gdy przechodzę przez kod, widzę, że to zawsze wybiera wybiera SHA256Managed, niezależnie od tego, czy wzywam SHA256.Create(), SHA256Cng.Create(), SHA256Managed.Create() lub SHA256CryptoServiceProvider.Create()Dlaczego wszystkie warianty SHA256 są wyświetlane jako SHA256Managed?

To ta sama historia, kiedy wybiorę inny algorytm haszowania jak MD5, ale w przypadku MD5 go zawsze rozgrywki MD5CryptoServiceProvider niezależnie od klasy, które faktycznie używać ...

Dlaczego ja tak?

Oto mój kod:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Security.Cryptography; 
using System.Text; 
using System.Threading.Tasks; 

namespace Utility.Methods 
{ 
    public enum HashType { MD5, SHA512, SHA256, SHA384, SHA1 } 
    public enum HashSubType {Normal, Cng, Managed, CryptoServiceProvider} 

    public static class TextHasher 
    { 
     public static string Hash(this string input, HashType hash, HashSubType subType = HashSubType.Normal) 
     { 
      Func<HashAlgorithm, string> hashFunction = alg => HashingHelper(input, alg); 

      switch (subType) 
      { 
       case HashSubType.Normal: 
        return hashFunction(NormalHashes(hash)); 
       case HashSubType.Cng: 
        return hashFunction(CngHashes(hash)); 
       case HashSubType.Managed: 
        return hashFunction(ManagedHashes(hash)); 
       case HashSubType.CryptoServiceProvider: 
        return hashFunction(CSPHashes(hash)); 
       default: return "error"; // unreachable 
      } 
     } 

     private static string HashingHelper(string text, HashAlgorithm algorithm) 
     { 
      Func<string, byte[]> getHash = input => algorithm.ComputeHash(Encoding.UTF8.GetBytes(input)); 

      var sb = new StringBuilder(); 
      Array.ForEach(getHash(text), b => sb.Append(b.ToString("X"))); 

      return sb.ToString(); 
     } 

     private static HashAlgorithm NormalHashes(HashType hash) 
     { 
      switch (hash) 
      { 
       case HashType.MD5: 
        return MD5.Create(); 
       case HashType.SHA1: 
        return SHA1.Create(); 
       case HashType.SHA256: 
        return SHA256.Create(); 
       case HashType.SHA384: 
        return SHA384.Create(); 
       case HashType.SHA512: 
        return SHA512.Create(); 
       default: return null; // unreachable 
      } 
     } 

     private static HashAlgorithm CngHashes(HashType hash) 
     { 
      switch (hash) 
      { 
       case HashType.MD5: 
        return MD5Cng.Create(); 
       case HashType.SHA1: 
        return SHA1Cng.Create(); 
       case HashType.SHA256: 
        return SHA256Cng.Create(); 
       case HashType.SHA384: 
        return SHA384Cng.Create(); 
       case HashType.SHA512: 
        return SHA512Cng.Create(); 
       default: return null; // unreachable 
      } 
     } 

     private static HashAlgorithm ManagedHashes(HashType hash) 
     { 
      switch (hash) 
      { 
       case HashType.SHA1: 
        return SHA1Managed.Create(); 
       case HashType.SHA256: 
        return SHA256Managed.Create(); 
       case HashType.SHA384: 
        return SHA384Managed.Create(); 
       case HashType.SHA512: 
        return SHA512Managed.Create(); 
       default: return null; // unreachable 
      } 
     } 

     private static HashAlgorithm CSPHashes(HashType hash) 
     { 
      switch (hash) 
      { 
       case HashType.MD5: 
        return MD5CryptoServiceProvider.Create(); 
       case HashType.SHA1: 
        return SHA1CryptoServiceProvider.Create(); 
       case HashType.SHA256: 
        return SHA256CryptoServiceProvider.Create(); 
       case HashType.SHA384: 
        return SHA384CryptoServiceProvider.Create(); 
       case HashType.SHA512: 
        return SHA512CryptoServiceProvider.Create(); 
       default: return null; // unreachable 
      } 
     } 
    } 
} 

więc każda pomoc?

+0

To nie jest szczególnie zaskakujące (ale bym myślał należy generować ostrzeżenia) od 'Create' statycznie zdefiniowane na' Klasa SHA256' i inne klasy dziedziczą z tego i dlatego wywołujesz tę samą metodę w każdym przypadku. Klasy nie abstrakcyjne mają publiczne konstruktory. –

+0

, więc jaki jest sens posiadania innych wersji klasy, jeśli metoda create nie zmienia tego, co robi? –

+0

Ponieważ wystąpienia tych klas robią różne rzeczy. Po prostu nie są istotne dla twojego przypadku użycia. – Mark

Odpowiedz

10

To dlatego, że zawsze wywołujesz tę samą metodę statyczną, SHA256.Create. SHA256 jest klasą abstrakcyjną, a jej potomkowie mają , a nie dostarczają alternatywnej metody. W rzeczywistości program Resharper wyświetli ostrzeżenie, że uzyskujesz dostęp do statycznego elementu z typu pochodnego.

W rzeczywistości wywołanie SHA256.Create jest takie samo jak wywołanie HashAlgorithm.Create. Obie klasy wywołują tę samą implementację wewnętrznie i po prostu rzucają wynik do różnych typów.

Sposób SHA256.Create stworzy domyślną implementację określonego w machine.config i mogą być nadpisane w app.config

Jeśli chcesz używać konkretnego dostawcę, użyj SHA256.Create(string) przekazując nazwę dostawcy ty chcesz użyć.

Przykładami są:

SHA256.Create("System.Security.Cryptography.SHA256Cng"); 
HashAlgorithm.Create("System.Security.Cryptography.SHA256Cng"); 
SHA256.Create("System.Security.Cryptography.SHA256CryptoServiceProvider"); 

EDIT

Dokumentacja HashAlgorithm.Create określa listę poprawnych nazw algorytmu. Artykuł MSDN o numerze Mapping Algorithm Names to Cryptography Classes opisuje, w jaki sposób można odwzorowywać nazwy algorytmów na innych dostawców (własne, zewnętrzne, sprzętowe lub inne) i używać ich zamiast domyślnych algorytmów.

EDIT 2

Możliwe jest również, aby zmienić mapowanie programowo. Tak więc, aby map „Dog” do SHA512CryptoServiceProvider, wystarczy napisać:

CryptoConfig.AddAlgorithm(
      typeof(System.Security.Cryptography.SHA512CryptoServiceProvider), 
      "Dog"); 
var t4 = HashAlgorithm.Create("Dog"); 
+0

ale nie używam sha256.create za każdym razem ... Używam sha256Managed.create i sha256Cng.create dla innych, i nadal daje mi ten sam wynik ... –

+1

@ ElectricCoffee - nie ma 'sha256Managed.Create 'method - ale' sha256Managed' * dziedziczy * z 'Sha256', więc połączenie może zostać skompilowane. –

+0

więc o co chodzi? –