当前位置: 首页 > 知识库问答 >
问题:

使用带有 SHA256 证书的 ECDSA 进行 C# 签名验证

上官和惬
2023-03-14

我正在尝试使用C#和内置的加密库来验证使用EC密钥SHA256创建的签名。

我使用openssl创建了一个私钥和相应的证书:

$ openssl ecparam -genkey -name prime256v1 -out ca.key
$ openssl req -x509 -new -SHA256 -nodes -key ca.key -days 36500 -out ca.crt

以下是我正在使用的密钥(别担心,它们并不重要):

$ cat ca.key 
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIHd3OvRV1nEnoDxGzzemX1x8l2rHasWH3L/LflUGg5vloAoGCCqGSM49
AwEHoUQDQgAE7f1xwQL5m/UcN4zL+zsly6V1g3/wNcL5TdCfWt0XfnUfg0x+RsIf
1uerBnhrmhH0cN9o0xfXg5B3hURFlXVuEQ==
-----END EC PRIVATE KEY-----

$ cat ca.crt 
-----BEGIN CERTIFICATE-----
MIIB4TCCAYegAwIBAgIUKt0WdaKI2eRXBO2nVk+OF6AZqHMwCgYIKoZIzj0EAwIw
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yMDA1MDcxMzM2MTNaGA8yMTIwMDQx
MzEzMzYxM1owRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAf
BgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBZMBMGByqGSM49AgEGCCqG
SM49AwEHA0IABO39ccEC+Zv1HDeMy/s7JculdYN/8DXC+U3Qn1rdF351H4NMfkbC
H9bnqwZ4a5oR9HDfaNMX14OQd4VERZV1bhGjUzBRMB0GA1UdDgQWBBRGuUmsyB2h
JCXMRTVMRTcdoWZQaDAfBgNVHSMEGDAWgBRGuUmsyB2hJCXMRTVMRTcdoWZQaDAP
BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIGG8tQZlh7aJaI34Y7jq
44SmSc/ule9MgjIX+Gg+i5vwAiEA9Jb/304KO4t9OMqFMQeWZXIHdzhDFBwx7FWz
78+UsnY=
-----END CERTIFICATE-----

然后,我有一个包含字符串“Hello”的简单数据文件。然后,我使用openssl对该文件进行签名,如下所示:

$ openssl dgst -sha256 -sign ca.key data.txt > sig
$ base64 sig 
MEUCIQD5593C/NBhHA1DILT72gjhGj/lKjom9vYP+JbuypBrxQIgNAjYT1LihEpPbUhe1n9ccUHQ
vw676bGqOTEU/25qcRQ=

然后,我可以通过首先从证书中提取公钥,然后使用公钥来验证签名:

$ openssl x509 -pubkey -noout -in ca.crt > ca.pub
$ cat ca.pub 
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7f1xwQL5m/UcN4zL+zsly6V1g3/w
NcL5TdCfWt0XfnUfg0x+RsIf1uerBnhrmhH0cN9o0xfXg5B3hURFlXVuEQ==
-----END PUBLIC KEY-----
$ openssl dgst -verify ca.pub -sha256 -signature sig data.txt 
Verified OK

然后,我尝试使用 C#(.NET Core 3.1)来验证签名。代码如下:

using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace security_sandbox
{
    class Program
    {
        static void Main(string[] args)
        {
            var certData = Encoding.ASCII.GetBytes(
                @"-----BEGIN CERTIFICATE-----
MIIB4TCCAYegAwIBAgIUKt0WdaKI2eRXBO2nVk+OF6AZqHMwCgYIKoZIzj0EAwIw
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yMDA1MDcxMzM2MTNaGA8yMTIwMDQx
MzEzMzYxM1owRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAf
BgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBZMBMGByqGSM49AgEGCCqG
SM49AwEHA0IABO39ccEC+Zv1HDeMy/s7JculdYN/8DXC+U3Qn1rdF351H4NMfkbC
H9bnqwZ4a5oR9HDfaNMX14OQd4VERZV1bhGjUzBRMB0GA1UdDgQWBBRGuUmsyB2h
JCXMRTVMRTcdoWZQaDAfBgNVHSMEGDAWgBRGuUmsyB2hJCXMRTVMRTcdoWZQaDAP
BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIGG8tQZlh7aJaI34Y7jq
44SmSc/ule9MgjIX+Gg+i5vwAiEA9Jb/304KO4t9OMqFMQeWZXIHdzhDFBwx7FWz
78+UsnY=
-----END CERTIFICATE-----");

            var cert = new X509Certificate2(certData);
            var ecdsa = cert.GetECDsaPublicKey();

            var data = Encoding.ASCII.GetBytes("Hello");
            var signature = Convert.FromBase64String("MEUCIQD5593C/NBhHA1DILT72gjhGj/lKjom9vYP+JbuypBrxQIgNAjYT1LihEpPbUhe1n9ccUHQvw676bGqOTEU/25qcRQ=");

            var success = ecdsa.VerifyData(data, signature, HashAlgorithmName.SHA256);

            if (success)
            {
                Console.WriteLine("Verified");
            } else
            {
                Console.WriteLine("Failed");
            }
        }
    }
}

可惜总是验证失败,错在哪里?

共有1个答案

上官鸿晖
2023-03-14

中缺少PEM/OpenSSL兼容的操作工具。NET被证明是非常令人沮丧的。我最终使用Bouncy Castle来加载证书或公钥,然后用它来验证我的ASN签名。下面是一个完整的工作代码示例,演示了如何使用证书和PEM公钥以及使用ASN编码的签名来执行签名验证。

using System;
using System.IO;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.X509;

namespace security_sandbox
{
    class Program
    {
        static void Main(string[] args)
        {

            var certificateString =  @"-----BEGIN CERTIFICATE-----
MIIB4TCCAYegAwIBAgIUKt0WdaKI2eRXBO2nVk+OF6AZqHMwCgYIKoZIzj0EAwIw
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yMDA1MDcxMzM2MTNaGA8yMTIwMDQx
MzEzMzYxM1owRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAf
BgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBZMBMGByqGSM49AgEGCCqG
SM49AwEHA0IABO39ccEC+Zv1HDeMy/s7JculdYN/8DXC+U3Qn1rdF351H4NMfkbC
H9bnqwZ4a5oR9HDfaNMX14OQd4VERZV1bhGjUzBRMB0GA1UdDgQWBBRGuUmsyB2h
JCXMRTVMRTcdoWZQaDAfBgNVHSMEGDAWgBRGuUmsyB2hJCXMRTVMRTcdoWZQaDAP
BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIGG8tQZlh7aJaI34Y7jq
44SmSc/ule9MgjIX+Gg+i5vwAiEA9Jb/304KO4t9OMqFMQeWZXIHdzhDFBwx7FWz
78+UsnY=
-----END CERTIFICATE-----";
            var pemreader = new PemReader(new StringReader(certificateString));
            var cert = (X509Certificate)pemreader.ReadObject();

            // Alternatively, load the public key directly
            var pubkeyString = 
@"-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7f1xwQL5m/UcN4zL+zsly6V1g3/w
NcL5TdCfWt0XfnUfg0x+RsIf1uerBnhrmhH0cN9o0xfXg5B3hURFlXVuEQ==
-----END PUBLIC KEY-----";
            pemreader = new PemReader(new StringReader(pubkeyString));
            var pubkey = (AsymmetricKeyParameter)pemreader.ReadObject();

            var data = "Hello";
            var signature = Convert.FromBase64String("MEUCIQD5593C/NBhHA1DILT72gjhGj/lKjom9vYP+JbuypBrxQIgNAjYT1LihEpPbUhe1n9ccUHQvw676bGqOTEU/25qcRQ=");

            // Verify using the public key
            var signer = SignerUtilities.GetSigner("SHA-256withECDSA");
            signer.Init(false, pubkey);
            signer.BlockUpdate(Encoding.ASCII.GetBytes(data), 0, data.Length);
            var success = signer.VerifySignature(signature);

            if (success) {
                Console.WriteLine("Signature verified successfully using public key");
            } else {
                Console.WriteLine("Failed to verify signature using public key");
            }

            // Verify using the certificate - the certificate's public key is extracted using the GetPublicKey method.
            signer.Init(false, cert.GetPublicKey());
            signer.BlockUpdate(Encoding.ASCII.GetBytes(data), 0, data.Length);
            success = signer.VerifySignature(signature);

            if (success) {
                Console.WriteLine("Signature verified successfully using certificate");
            } else {
                Console.WriteLine("Failed to verify signature using certificate");
            }
        }
    }
}
 类似资料:
  • 我有一个包含EC私钥的文件: 我有一个证书,它的公钥对应于私钥: 在 pem 格式中: 以txt格式: 我正在努力完成两件事: < li >使用ecdsa-with-SHA256签名算法使用私钥对字节数组进行签名 < li >使用证书中的公钥验证签名是否正确 我尝试过使用充气城堡图书馆。这是我到目前为止所拥有的。我的断言是失败的。

  • 下面是我的场景--我从条形码中读取数据,并将其转换为纯文本。本文是条码数据+数字签名的结合。数字签名附加在末尾,使我能够分离出实际数据和数字签名数据。数字签名数据使用sha256哈希-用户将公钥作为windows证书文件()发送给我。 所需实现:-需要从证书中提取公钥,并根据提供的条形码数据和数字签名验证公钥。 问题:

  • 我在开发安全系统时遇到了以下问题: 我们收到一些数据,我们必须通过签名进行验证。签名算法是ecdsa-with-SHA256,openssl_verify()似乎没有这个选项。已经尝试过搜索像phpseclib这样的独立PHP库了——也不走运,ecdsa-with-SHA1似乎是他们提供的最佳选择。 对于这个问题,什么是合适的解决方案?也许我错过了一些实现这种功能的库?

  • 也就是说,我需要创建一个可以通过WCF JSON调用公钥的客户机,以便稍后用于签名验证,但我似乎无法使其工作。首先,这里是我用来生成证书的代码: 完成后,我使用以下代码对消息进行签名: 最后,我试图验证:

  • 我想创建一个签名并使用openssl验证它。我想有我的签名的十六进制输出。 这是我的密码 我得到这个错误: 如果我在创建签名的过程中删除了-hex,它就可以工作了。

  • 我应该如何更改A方法?任何想法都是好的。提前谢谢。