У меня проблема с цифровой подписью XML-сообщения. Требования диктуют, что сертификат ECDSA должен использоваться с определенной кривой. Это означает, что функциональность RSA и DSA, предоставляемая методом SignedXml.ComputeSignature(...)
, не будет работать без создания пользовательской реализации , AsymmetricSignatureFormatter
и AsymmetricSignatureDeformatter
.Ключ не существует - с помощью самоподписанного сертификата ECDSA
Это, как говорится, и не публикуя много кода. Я создал простую функцию, которая должна принимать сертификат и использовать его открытый ключ для записи данных с использованием класса ECDsaCng
, так как это то, что я использовал для создания пользовательской реализации, упомянутой выше ,
Что происходит, даже с моей пользовательской реализацией, я получаю исключение «System.Security.Cryptography.CryptographicException: Key does not exist.
». Если, однако, я просто создаю CngKey
, а не импортирую его. Из того, что я могу видеть это исключение выгоняют из кода, который вызывает метод на internal static extern ErrorCode NCryptSignHash(...)
, который находится в ncrypt.dll
Так что мой вопрос, почему исключение «System.Security.Cryptography.CryptographicException: Key does not exist.
» и как ее устранить.
[TestMethod]
public void CreateSignatureTest()
{
var request = "Some xml goes here...";
var store = new X509Store(StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var certificates = store.Certificates;
var applicableCertificate = certificates.Cast<X509Certificate2>()
.FirstOrDefault(certificate => certificate.Subject.Contains("ECDSA_CERT_NAME"));
var encryptingKey = (ECDsaCng)applicableCertificate.GetECDsaPublicKey();
var exported = encryptingKey.Key.Export(CngKeyBlobFormat.EccPublicBlob);
var creationParameters = new CngKeyCreationParameters
{
ExportPolicy = CngExportPolicies.AllowPlaintextExport
};
using (CngKey objCngKey = CngKey.Import(exported, CngKeyBlobFormat.EccPublicBlob)) // This will throw a Key Does Not Exist Exception
//using (CngKey objCngKey = CngKey.Create(CngAlgorithm.ECDsaP256, null, creationParameters)) // This works...
{
//'Convert String to be signed to a byte array
var data = Encoding.Default.GetBytes(request);
//'Create a ECDsaCng Object
var ecdsa = new ECDsaCng(objCngKey);
//'Sign the string
var bSignature = ecdsa.SignData(data);
//'Convert Signature to Base64 string for better reading
var sSignature = Convert.ToBase64String(bSignature);
}
}
Я пробовал это var encryptingKey = (ECDsaCng) применимоCertificate.GetECDsaPrivateKey(); var exported = ((ECDsaCng) encryptingKey) .Key.Export (CngKeyBlobFormat.EccPrivateBlob); Теперь получите другое исключение. Запрошенная операция не поддерживается. У меня создалось впечатление, что я зашифрую публикацию, и получатель будет проверять секретный ключ? – Geek
Вот как работает шифрование, да; но подписание - наоборот. Подписчик использует закрытый ключ (который у них только есть), верификатор использует публикацию. Но я до сих пор не понимаю, почему вы клонируете объект вообще (что не будет работать для смарт-карты). 'cert.GetECDsaPrivateKey(). SignData (...)' (хотя использование операторов является хорошим) – bartonjs
Последний комментарий был отличным указателем, я вынул клонирование, и теперь я могу подписывать и возвращать подпись. Моя единственная проблема, оставшаяся сейчас, заключается в том, как применить это к пользовательским реализациям SignatureDescription, AsymmetricSignatureFormatter и AsymmetricSignatureDeformatter, чтобы затем создать узел Signature XML. – Geek