Есть ли в ECDiffieHellmanCng в.NET функция извлечения ключей, реализующая NIST SP 800-56A, раздел 5.8.1
У меня есть задача, которая требует получения материала ключа с использованием функции вывода ключа, описанной в NIST SP 800-56A, раздел 5.8.1. Я не специалист по криптографии, поэтому извините, если вопрос наивный. Вот что я сделал до сих пор:
- У меня есть открытый ключ другой стороны и мой закрытый ключ
Теперь я пытаюсь сгенерировать общий секрет, используя ECDH 1.3.132.1.12, используя класс CCD (.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:);
Где / как мне установить другие параметры Идентификатор алгоритма, Сторона U Информация, Сторона V Информация?
РЕДАКТИРОВАТЬ Я открыт для использования других библиотек, таких как 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, считайте его в объект Org.BouncyCastle.Crypto.Parameters.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, используя Org.BouncyCastle.Security.WrapperUtilities, вызвав WrapperUtilities.GetWrapper("AES//"), например, "AES/CBC/PKCS7". Это также будет зависеть от соглашения между двумя связывающимися сторонами.
Инициализируйте шифр (IWrapper) с симметричным ключом и вектором инициализации (IV) и вызовите метод Unwrap, чтобы получить байты в виде простого текста. Наконец, преобразуйте в строковый литерал, используя используемую кодировку символов (например, UTF8/ASCII/Unicode)