2015-07-10 35 views
11

Mam zadanie, które wymaga klucza pochodnego przy użyciu funkcji wyprowadzania klucza opisanej w NIST SP 800-56A, sekcja 5.8.1. Nie jestem ekspertem od kryptografii, więc przepraszam, jeśli pytanie jest naiwne. Oto co zrobiłem do tej pory:Czy funkcja ECDiffieHellmanCng w .NET ma funkcję wyprowadzania klucza, która implementuje NIST SP 800-56A, sekcja 5.8.1

  1. mam klucza publicznego rozmówcy i mojego klucza prywatnego
  2. Teraz próbuję wygenerować wspólne hasło używając ECDH 1.3.132.1.12 przy użyciu C# (.NET 4) klasa ECDiffieHellmanCng tak:

    // The GetCngKey method reads the private key from a certificate in my Personal certificate store 
    
    CngKey cngPrivateKey = GetCngKey(); 
    
    ECDiffieHellmanCng ecDiffieHellmanCng = new ECDiffieHellmanCng(cngPrivateKey); 
    
    ecDiffieHellmanCng.HashAlgorithm = CngAlgorithm.ECDiffieHellmanP256; 
    ecDiffieHellmanCng.KeyDerivationFunction = ?? // What do I set here 
    

Wreszcie to zrobić:

ecDiffieHellmanCng.DeriveKeyMaterial(otherPartyPublicKey:); 

Gdzie/jak ustawić inne parametry Identyfikator algorytmu, Informacje o stronie U, Informacje o stronie V?

EDIT Jestem otwarty do korzystania z innych bibliotek jak nadmuchiwany zamek (o ile mogą one być wywołana z .NET)

Odpowiedz

8

TL; DR; Nie znalazłem sposobu na wyprowadzenie klucza symetrycznego za pomocą KDF opisanego w NIST SP 800-56A, rozdział 5.8.1 przy użyciu wbudowanych klas samego .NET 4.0

Dobra wiadomość (dla mnie :-)) jest to możliwe w .NET 4.0 za pomocą pięknej biblioteki BouncyCastle (NuGet: Install-Package BouncyCastle-Ext -Version "1.7.0"). Oto jak:

KROK 1: Get druga strona public key

W zależności od sytuacji, może to być odczytane z certyfikatem lub przyjść do was jako części wiadomości zawierającej zaszyfrowane dane. Raz masz Base64 zakodowanego klucza publicznego, przeczytaj ją w Org.BouncyCastle.Crypto.Parameters.ECPublicKeyParameters obiekt tak:

var publicKeyBytes = Convert.FromBase64String(base64PubKeyStr); 
ECPublicKeyParameters otherPartyPublicKey = (ECPublicKeyParameters)PublicKeyFactory.CreateKey(publicKeyBytes); 

KROK 2: Przeczytaj swój prywatny klucz

To MOST zwykle wymagają przeczytania klucza prywatnego z certyfikatu PFX/P12. Konto systemu Windows z uruchomionym kodem powinno mieć dostęp do PFX/P12 i dodatkowo, jeśli certyfikat jest importowany do magazynu certyfikatów, musisz udzielić uprawnień za pośrednictwem menu Wszystkie zadania -> zarządzaj kluczem prywatnym w certmgr.msc

using (StreamReader reader = new StreamReader(path)) 
{ 
    var fs = reader.BaseStream; 
    string password = "<password for the PFX>"; 
    Pkcs12Store store = new Pkcs12Store(fs, passWord.ToCharArray()); 

    foreach (string n in store.Aliases) 
    { 
     if (store.IsKeyEntry(n)) 
     { 
      AsymmetricKeyEntry asymmetricKey = store.GetKey(n); 

      if (asymmetricKey.Key.IsPrivate) 
      { 
       ECPrivateKeyParameters privateKey = asymmetricKey.Key as ECPrivateKeyParameters; 
      } 
     } 
    } 
} 

KROK 3: oblicz wspólne hasło

IBasicAgreement aKeyAgree = AgreementUtilities.GetBasicAgreement("ECDH"); 
aKeyAgree.Init(privateKey); 
BigInteger sharedSecret = aKeyAgree.CalculateAgreement(otherPartyPublicKey); 
byte[] sharedSecretBytes = sharedSecret.ToByteArray(); 

KROK 4: Przygotuj informacje wymagane do obliczenia klucza symetrycznego:

byte[] algorithmId = Encoding.ASCII.GetBytes(("<prependString/Hex>" + "id-aes256-GCM")); 
byte[] partyUInfo = Encoding.ASCII.GetBytes("<as-per-agreement>"); 
byte[] partyVInfo = <as-per-agreement>; 
MemoryStream stream = new MemoryStream(algorithmId.Length + partyUInfo.Length + partyVInfo.Length); 
var sr = new BinaryWriter(stream); 
sr.Write(algorithmId); 
sr.Flush(); 
sr.Write(partyUInfo); 
sr.Flush(); 
sr.Write(partyVInfo); 
sr.Flush(); 
stream.Position = 0; 
byte[] keyCalculationInfo = stream.GetBuffer(); 

Krok 5: Wyprowadź SY klucz mmetric

// NOTE: Use the digest/Hash function as per your agreement with the other party 
IDigest digest = new Sha256Digest(); 
byte[] symmetricKey = new byte[digest.GetDigestSize()]; 
digest.Update((byte)(1 >> 24)); 
digest.Update((byte)(1 >> 16)); 
digest.Update((byte)(1 >> 8)); 
digest.Update((byte)1); 
digest.BlockUpdate(sharedSecret, 0, sharedSecret.Length); 
digest.BlockUpdate(keyCalculationInfo, 0, keyCalculationInfo.Length); 
digest.DoFinal(symmetricKey, 0); 

Teraz masz klucz symetryczny gotowy do deszyfrowania. Aby wykonać deszyfrowanie za pomocą AES, można użyć BouncyCastle IWrapper. Uzyskaj IWrapper za pomocą Org.BouncyCastle.Security.WrapperUtilities, wywołując WrapperUtilities.GetWrapper ("AES //") np. "AES/CBC/PKCS7". Będzie to również zależało od porozumienia między dwiema stronami, które się komunikują.

Zainicjuj szyfr (IWrapper) za pomocą klucza symetrycznego i wektora inicjalizacyjnego (IV) i wywołaj metodę Unwrap, aby pobrać bajty zwykłego tekstu. Wreszcie przekonwertować ciąg dosłownym stosując kodowanie znaków używane (np UTF8/ASCII/Unicode)

+0

Na stronie szyfrowania BouncyCastle ma klasę ConcatenationKDFGenerator https://github.com/bcgit/bc-csharp/blob/0801c1543f0cafc79c44b225e53c973bdd1b0a0f/ crypto/src/crypto/agreement/kdf/ConcatenationKdfGenerator.cs – Sentinel