Делает ECDiffieHellmanCng in.NET имейте ключевую функцию вывода, которая реализует NIST SP 800-56A, раздел 5.8.1

у меня есть задача, которая требует получения ключевого материала с помощью функции вывода ключа, описанной в NIST SP 800-56A, раздел 5.8.1. Я не эксперт в криптографии, поэтому, пожалуйста, извините меня, если вопрос наивен. Вот что я сделал до сих пор:

  1. у меня есть открытый ключ другой стороны и мой секретный ключ
  2. теперь я пытаюсь создать общий секрет с помощью ECDH 1.3.132.1.12 с помощью C# (.NET 4) ECDiffieHellmanCng класса, как Итак:

    // 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
    

наконец-то сделать это:

ecDiffieHellmanCng.DeriveKeyMaterial(otherPartyPublicKey:);

где / как установить другие параметры алгоритма ID, Party U Info, Party V Info?

редактировать Я открыт для использования других библиотек, таких как Bouncy Castle (при условии, что они могут быть вызваны из .NET)

1 ответов


TL; DR; я не нашел способ получить симметричный ключ, используя KDF, описанный в NIST SP 800-56A, раздел 5.8.1, используя встроенные классы только в .NET 4.0

хорошая новость (для меня : -)) заключается в том, что в .NET 4.0 можно использовать прекрасную библиотеку BouncyCastle (NuGet: Install-Package BouncyCastle-Ext-Version "1.7.0"). Вот как:

Шаг 1: получите открытый ключ другой стороны

в зависимости от вашего сценария, это может быть считаны из сертификата или прийти к вы как часть сообщения, содержащего зашифрованные данные. Как только у вас есть открытый ключ с кодировкой Base64, прочитайте его в организации.После установки BouncyCastle.Криптографический.Параметры.Объект ECPublicKeyParameters выглядит так:

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

Шаг 2: прочитайте свой закрытый ключ

это чаще всего будет включать чтение закрытого ключа из сертификата PFX/P12. Учетная запись windows, выполняющая код, должна иметь доступ к PFX / P12 и дополнительно, если сертификат импортирован в хранилище сертификатов, вам нужно будет предоставить разрешения через меню все задачи - > управление закрытым ключом в 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;
           }
       }
   }
}

Шаг 3: вычислить общий секрет

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

Шаг 4: Подготовьте информацию, необходимую для вычисления симметричного ключа:

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();

Шаг 5: выведите симметричный ключ

// 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);

теперь у вас есть симметричный ключ для расшифровки. Для выполнения расшифровки с помощью AES можно использовать BouncyCastle IWrapper. Получить IWrapper с помощью Орг.После установки BouncyCastle.Безопасность.WrapperUtilities, вызвав WrapperUtilities.GetWrapper ("AES//"), например"AES/CBC/PKCS7". Это также будет зависеть от соглашения между двумя взаимодействующими сторонами.

инициализируйте шифр (IWrapper) с помощью симметричного ключа и вектора инициализации (IV) и вызовите метод Unwrap для получения байтов простого текста. Наконец, преобразуйте в строковый литерал, используя кодировку символов (например, UTF8 / ASCII / Unicode)