starkbank / ecdsa-dotnet

A lightweight and fast pure C# ECDSA library
https://starkbank.com
Other
49 stars 20 forks source link

How to print Der value from signature #27

Open smartkodian opened 2 years ago

smartkodian commented 2 years ago

Hi,

I am using this command to show Der value but doesn't work with me, Any help please?

PrivateKey privateKey = PrivateKey.fromPem(privateKeyPem); Signature signatures = Ecdsa.sign(message, privateKey); byte[] der = signatures.toDer(); Console.WriteLine(der);

softwarekamal commented 2 years ago

Hello @smartkodian, You can use Convert.ToBase64(der), or BitConverter.ToString(der).Replace("-", "")

I wish they can support P1363 format! short signature like Bouncy Castle SHA256WithPlain-ECDSA Because for 256 bit curves. library default output are ASN1 = 70-71, while P1363 are fixed size. 64 byte. That's it! But not implemented :disappointed:

But I try to do manually. It worked for sign, But can't verified! because library only verify ASN1 DER. I don't know how to apply it. Am sad my friend no community to support us, we can cry together.... :sob:

        var signature = EllipticCurve.Ecdsa.sign("hello dear", privateKey);
            var signatureBytes = signature.toDer();

            Tuple<byte[], byte[]> tuple = Der.removeSequence(signatureBytes);

            Tuple<BigInteger, byte[]> tuple2 = Der.removeInteger(tuple.Item1);
            Tuple<BigInteger, byte[]> tuple3 = Der.removeInteger(tuple2.Item2);

            var byte1 = tuple2.Item1.ToByteArray().Reverse().ToArray(); // O
            var byte2 = tuple3.Item1.ToByteArray().Reverse().ToArray();
            var P1363ShortSignature = byte1.Concat(byte2).ToArray();
smartkodian commented 2 years ago

Hello @softwarekamal yes bro, Actually I faced the issue with 64 byte issue in starkbank library but now I am testing on PHP and I am using openssl_sign beside checking the 32 byte for R and S value but I have problem with ECDSA signature format. Can we contact?

softwarekamal commented 2 years ago

Welcome back @smartkodian, Do you try Bouncy Castle?, If you need already defined curves Bouncy Castle are very good. But I can't use custom curves with it. There's another library Called Ecc, Its do the short fixed signature, for example 256 will give exactly 64 Bytes. You can try it. But its not give extra padding like current hard-coded library :100:

Ccrrent library ecdsa-dotnet need more extension methods to make it beautiful like: EllipticCurve.Ecdsa.FromShortDer(), EllipticCurve.Ecdsa.ToShortDer(), If you have any custom implementation you can share it :1st_place_medal: I wish you tell me what other libraries you can use for custom curves. Because I can't use Bouncy Castle for custom curves.

I will share you my bouncy castle ECDSA class that give fixed 64 bytes length: Note: you must download Bouncy Castle Nuget

using System;
using System.Text;
using System.IO;

using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;

namespace ECDSABouncy
{
    public static class ECDSAEncryption
    {
        /// <summary>
        /// Get private or public <see cref="AsymmetricKeyParameter"/> from PEM key format,
        /// </summary>
        private static AsymmetricKeyParameter GetAsymmetricKeyParameter(string key)
        {
            if (string.IsNullOrWhiteSpace(key))
                throw new ArgumentNullException(nameof(key));
            if (!key.Trim().StartsWith("-----BEGIN "))
                throw new ArgumentException("Given key doesn't start with -----BEGIN, Key must be in PEM format");

            using (StringReader reader = new StringReader(key))
            {
                PemReader pemReader = new PemReader(reader);
                if (key.Trim().EndsWith("PRIVATE KEY-----"))
                    return ((AsymmetricCipherKeyPair)pemReader.ReadObject()).Private;
                return (AsymmetricKeyParameter)pemReader.ReadObject();
            }
        }

        /// <summary>
        /// Generate ECDSA key pair. Allowed key sizes: 192, 224, 239, 256, 384, 521
        /// </summary>
        public static (string privateKey, string publicKey) GenerateRandomKeys(int keySize = 256)
        {
            ECKeyPairGenerator keyGenerator = new ECKeyPairGenerator();
            keyGenerator.Init(new KeyGenerationParameters(new SecureRandom(), keySize));
            AsymmetricCipherKeyPair keyPair = keyGenerator.GenerateKeyPair();
            string privateKey, publicKey;

            using (StringWriter writer = new StringWriter())
            {
                PemWriter pemWriter = new PemWriter(writer);
                pemWriter.WriteObject(keyPair.Private);
                privateKey = writer.ToString().Trim();

                writer.GetStringBuilder().Clear();
                pemWriter.WriteObject(keyPair.Public);
                publicKey = writer.ToString().Trim();
            }
            return (privateKey, publicKey);
        }

        /// <summary>
        /// Generate ECDSA signature of <paramref name="message"/> with given <paramref name="privateKey"/>.
        /// </summary>
        public static byte[] GenerateSignature(byte[] message, string privateKey)
        {
            if (message == null || message.Length == 0)
                throw new ArgumentException("message can't be null or zero length", nameof(message));

            AsymmetricKeyParameter keyParameter = GetAsymmetricKeyParameter(privateKey);
            ISigner sign = SignerUtilities.GetSigner("SHA256WithPlain-ECDSA");
            sign.Init(true, keyParameter);
            sign.BlockUpdate(message, 0, message.Length);
            byte[] signedBytes = sign.GenerateSignature();
            return signedBytes;
        }

        /// <summary>
        /// Generate ECDSA signature of <paramref name="message"/> with given <paramref name="privateKey"/>.
        /// </summary>
        public static string GenerateSignature(string message, string privateKey)
        {
            byte[] signedBytes = GenerateSignature(Encoding.UTF8.GetBytes(message), privateKey);
            string signature = Convert.ToBase64String(signedBytes);
            return signature;
        }

        /// <summary>
        /// Verify ECDSA <paramref name="signature"/> of <paramref name="message"/> with given <paramref name="publicKey"/>.
        /// </summary>
        public static bool VerifySignature(byte[] message, byte[] signature, string publicKey)
        {
            if (message == null || message.Length == 0)
                throw new ArgumentException("message can't be null or zero length", nameof(message));

            AsymmetricKeyParameter keyParameter = GetAsymmetricKeyParameter(publicKey);
            ISigner sign = SignerUtilities.GetSigner("SHA256WithPlain-ECDSA");
            sign.Init(false, keyParameter);
            sign.BlockUpdate(message, 0, message.Length);
            bool isVerified = sign.VerifySignature(signature);
            return isVerified;
        }

        /// <summary>
        /// Verify ECDSA <paramref name="signature"/> of <paramref name="message"/> with given <paramref name="publicKey"/>.
        /// </summary>
        public static bool VerifySignature(string message, string signature, string publicKey)
        {
            bool isVerified = VerifySignature(Encoding.UTF8.GetBytes(message), Convert.FromBase64String(signature), publicKey);
            return isVerified;
        }
    }
}

Usage:

            var myKeys = ECDSAEncryption.GenerateRandomKeys();
            var mySignature = ECDSAEncryption.GenerateSignature("Hello World", myKeys.privateKey);
            var isVerified = ECDSAEncryption.VerifySignature("Hello World", mySignature, myKeys.publicKey);

If you need to talk more privately, My email: softwarek94@gmail.com