Как проверить данные подписи с открытым ключом, который использует sha1ecdsa?

Зная немного о криптографии, у меня большие проблемы с тем, что кажется простой задачей.

У меня есть сертификат .pem, байты данных и подпись этих данных. Я хочу проверить, изменил ли кто-либо данные, сопоставив его с сигнатурой.

Моя попытка:

private bool VerifySignature(byte[] data, byte[] signature)
{
  try
  {
    X509Certificate certificate = new X509Certificate("cert_filename.pem");
    if (certificate == null)
      return false;

    DSACryptoServiceProvider dsa = (DSACryptoServiceProvider)certificate.PublicKey.Key;

    return dsa.VerifyData(data, signatureData);
  }
  catch
  {
    return false;
  }
}

Но это дает мне ошибку

'Алгоритм ключа сертификатов не поддерживается' (System.NotSupportedException).

В загруженном сертификате говорится, что алгоритм подписи является "sha1ecdsa".

Я пытаюсь проверить данные только подписи. Что мне здесь не хватает? Я бы хотел сделать это без каких-либо внешних решений, поскольку это кажется действительно тривиальной задачей.

Обновление: я пытаюсь достичь такой же функциональности, как в следующем Java-коде:

private boolean verify(byte[] data, byte[] signature)
{
  boolean isLicenseCorrect = false;

  Signature sig = Signature.getInstance("SHA1WithECDSA");
  sig.initVerify(certificate.getPublicKey());
  sig.update(data);

  return sig.verify(signature);
}

Ответы

Ответ 1

Хотя DSA и ECDSA связаны между собой, они не совпадают. Почему бы не попробовать ECDsaCryptoServiceProvider? Обратите внимание, что поддержка ECDSA для эллиптических кривых включает только кривые NIST.

Ответ 2

.NET 4.6.1 добавлена ​​улучшенная поддержка ECDSA. Хотя я не поклонник вашего catch-all-and-return-false, я буду держать его здесь для сравнения:

private bool VerifySignature(byte[] data, byte[] signature)
{
    try
    {
        // new cannot return null, so no point in a null check. It would have thrown.

        using (X509Certificate certificate = new X509Certificate("cert_filename.pem"))
        using (ECDsa ecdsa = certificate.GetECDsaPublicKey())
        using (RSA rsa = certificate.GetRSAPublicKey())
        // Improved DSA is 4.6.2
        {
            // You said the cert was ECDSA-SHA1, but that doesn't mean the original data was.
            // I assumed it was.
            if (ecdsa != null)
                return ecdsa.VerifyData(data, signature, HashAlgorithmName.SHA1);

            if (rsa != null)
                return rsa.VerifyData(data, signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);

            return false;
        }
    }
    catch
    {
        return false;
    }
}

Обратите внимание, что в .NET 4.6 базовый класс RSA имеет определенные методы Sign/Verify, а в 4.6.1 базовый класс ECDsa получил аналогичную обработку. Новый код не должен говорить о типах * CryptoServiceProvider, если не загружать уже существующие именованные ключи.

Также стоит отметить, что методы PublicKey Get [Algorithm] возвращают null, когда открытый ключ не относится к типу алгоритма, поэтому проверка нулей оправдана.