14

对密码学知之甚少,我对看似简单的任务有很大的问题。

我有 .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);
}
4

2 回答 2

6

虽然 DSA 和 ECDSA 相关,但它们并不相同。为什么不试试ECDsaCryptoServiceProvider?请注意,ECDSA 对椭圆曲线的支持仅包括 NIST 命名曲线。

于 2015-05-09T21:41:22.360 回答
0

.NET 4.6.1 添加了对 ECDSA 的改进支持。虽然我不喜欢你的 catch-everything-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 类型。

还值得注意的是,null当公钥不是该算法类型时,Get[Algorithm]PublicKey 方法会返回,因此需要进行空检查。

于 2016-07-01T01:06:07.207 回答