How to sign and verify an ECDSA with SHA256 signature in C#

10,065

Mr Polk is correct, you need to use verifier.blockUpdate with the data, and then use the signature bytes in VerifySignature.

Signatures cannot be verified on their own. The algorithm requires the data as input to calculate the hash value before entering the validation state. Of course having the signature verified without the data only provides limited value: you can just prove that the private key was used.

With ECDSA there is also no real option to verify any part of the signature without the hash


RSA / PKCS#1 in theory would allow you to verify that the contents of the signature are at least created by the private key, even though the contents are unknown. As you can retrieve the full hash value, it is possible to guess the data input without having to go through the signature verification phase for each possible input value. Most API's are of course not geared towards such use of signatures as this is specific to certain schemes.

Share:
10,065

Related videos on Youtube

qgoehrig
Author by

qgoehrig

Updated on June 04, 2022

Comments

  • qgoehrig
    qgoehrig almost 2 years

    I have a file containing an EC private key:

    -----BEGIN EC PRIVATE KEY-----
    <data>
    -----END EC PRIVATE KEY-----
    

    I have a certificate with a public key that corresponds to the private key:

    In pem format:

    -----BEGIN CERTIFICATE-----
    <data>
    -----END CERTIFICATE-----
    

    In txt format:

    Certificate:
        Data:
            Version: 3 (0x2)
            Serial Number:
                80:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:15
            Signature Algorithm: ecdsa-with-SHA256
            Issuer: CN = MyIssuer
            Validity
                Not Before: Jan 27 19:33:43 2020 GMT
                Not After : Jun 10 19:33:43 2021 GMT
            Subject: CN = MyIssuer MyCert
            Subject Public Key Info:
                Public Key Algorithm: id-ecPublicKey
                    Public-Key: (256 bit)
                    pub:
                        04:6a:9c:40:7b:71:06:3a:7f:3a:1e:4c:5c:60:9e:
                        d0:c4:a0:c0:c7:39:ec:6d:f1:5b:27:5a:5f:3b:f8:
                        77:29:7e:38:8e:e6:77:cf:d2:9c:77:c2:43:f4:92:
                        73:a8:10:d2:e9:f2:bb:d7:4d:97:76:07:d0:1f:16:
                        7b:01:d3:35:26
                    ASN1 OID: prime256v1
                    NIST CURVE: P-256
            X509v3 extensions:
                X509v3 Basic Constraints: critical
                    CA:FALSE
                X509v3 Authority Key Identifier: 
                    keyid:E0:1C:E6:36:88:8B:3D:77:A6:9D:80:8B:7B:9B:1D:1E:FF:24:74:B3
    
                X509v3 Extended Key Usage: 
                    TLS Web Server Authentication, TLS Web Client Authentication
                X509v3 Subject Key Identifier: 
                    49:57:2F:01:37:1B:E2:B6:9C:1A:C7:A9:03:9A:D1:61:7E:9B:4A:84
                X509v3 Key Usage: critical
                    Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment
        Signature Algorithm: ecdsa-with-SHA256
             30:44:02:20:2c:1a:5c:ee:4a:58:59:f1:5a:4a:93:ed:e0:24:
             70:9d:15:11:5e:11:df:30:5a:0f:54:a0:9f:95:c4:eb:f9:6d:
             02:20:17:fe:e4:8c:ef:ef:34:56:fb:5d:79:40:f8:fc:f4:2f:
             97:90:4b:ac:cb:b6:64:c0:58:3e:2d:fe:7b:4f:ea:19
    -----BEGIN CERTIFICATE-----
    MIIBrTCCAVSgAwIBAgIVAIAAAAAAAAAAAAAAAAAAAAAAAAAVMAoGCCqGSM49BAMC
    MBIxEDAOBgNVBAMMB0lzc3VlckMwHhcNMjAwMTI3MTkzMzQzWhcNMjEwNjEwMTkz
    MzQzWjAaMRgwFgYDVQQDDA9Jc3N1ZXJDIERldmljZTMwWTATBgcqhkjOPQIBBggq
    hkjOPQMBBwNCAARqnEB7cQY6fzoeTFxgntDEoMDHOext8VsnWl87+HcpfjiO5nfP
    0px3wkP0knOoENLp8rvXTZd2B9AfFnsB0zUmo38wfTAMBgNVHRMBAf8EAjAAMB8G
    A1UdIwQYMBaAFOAc5jaIiz13pp2Ai3ubHR7/JHSzMB0GA1UdJQQWMBQGCCsGAQUF
    BwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUSVcvATcb4racGsepA5rRYX6bSoQwDgYD
    VR0PAQH/BAQDAgTwMAoGCCqGSM49BAMCA0cAMEQCICwaXO5KWFnxWkqT7eAkcJ0V
    EV4R3zBaD1Sgn5XE6/ltAiAX/uSM7+80VvtdeUD4/PQvl5BLrMu2ZMBYPi3+e0/q
    GQ==
    -----END CERTIFICATE-----
    

    I am trying to accomplish two things:

    1. Sign an array of bytes using the private key using the ecdsa-with-SHA256 signing algorithm
    2. Verify the signature is correct using the public key within the certificate

    I have tried using the Bouncy Castle library. Here is what I have so far. My assertion is failing.

        [TestMethod]
        public void TestSignAndVerify()
        {
    
            var data = new byte[] {6, 5, 4, 3, 2};
    
            var keyPair = GetKeyPair();
    
            var signature = SignData(data, keyPair.Private);
    
            var valid = VerifySignature(signature, keyPair.Public);
            Assert.IsTrue(valid);
    
        }
    
        // get key pair from two local files
        private AsymmetricCipherKeyPair GetKeyPair()
        {
    
            AsymmetricKeyParameter privateKey, publicKey;
    
            var privateKeyString = File.ReadAllText("C:\\privatekey.pem");
            using (var textReader = new StringReader(privateKeyString))
            {
                // Only a private key
                var pseudoKeyPair = (AsymmetricCipherKeyPair)new PemReader(textReader).ReadObject();
                privateKey = pseudoKeyPair.Private;
            }
    
            var certificateString = File.ReadAllText("C:\\publicCert.pem");
            using (var textReader = new StringReader(certificateString))
            {
                // Only a private key
                Org.BouncyCastle.X509.X509Certificate bcCertificate = (X509Certificate)new PemReader(textReader).ReadObject();
                publicKey = bcCertificate.GetPublicKey();
            }
    
            return new AsymmetricCipherKeyPair(publicKey, privateKey);
    
        }
    
        public byte[] SignData(byte[] data, AsymmetricKeyParameter privateKey)
        {
            var signer = SignerUtilities.GetSigner("SHA-256withECDSA");
    
            signer.Init(true, privateKey);
    
            signer.BlockUpdate(data, 0, data.Length);
    
            return signer.GenerateSignature();
        }
    
        public bool VerifySignature(byte[] signature, AsymmetricKeyParameter publicKey)
        {
    
            var verifier = SignerUtilities.GetSigner("SHA-256withECDSA");
    
            verifier.Init(false, publicKey);
    
            verifier.BlockUpdate(signature, 0, signature.Length);
    
            return verifier.VerifySignature(signature);
    
        }
    
    • President James K. Polk
      President James K. Polk about 4 years
      umm... you didn't actually use the data in your verification code.
    • qgoehrig
      qgoehrig almost 2 years
      Yes this was the issue! :)