Extract r and s from ECDSA signature signedxml c#

594 Views Asked by At

I'm using Signedxml class in .net 5 to generate signature using ECDSA and I need the value of r and s but I can not extract it and another problem is signature length . My signature always 64 bytes but ECDSA signature length is 71 and I do not know why this length change . Please help me extract r and s

1

There are 1 best solutions below

0
On

When converting the ECDSA signature from ASN.1/DER to P1363 (r|s) format, the following must be taken into account:

  • In ASN.1/DER format r and s are contained as signed, big endian arrays, in P1363 format as unsigned, big endian arrays.
  • In ASN.1/DER format r and s are included as minimal sized arrays, in P1363 both are padded to their maximum size (length of the order of the generator point) with leading 0x00 values. Example: For NIST P-256, the maximum size of r and s is 32 bytes each.

Possible implementation with .NET 5+ using the AsnReader class:

using System.Formats.Asn1;
...
public static byte[] DERtoP1363(byte[] derSignature, int maxSize)
{
    AsnReader sequence = new AsnReader(derSignature, AsnEncodingRules.DER).ReadSequence();
    byte[] rBytes = sequence.ReadInteger().ToByteArray(true, true); // convert to unsigned, big endian
    byte[] sBytes = sequence.ReadInteger().ToByteArray(true, true); // convert to unsigned, big endian
    byte[] rsBytes = new byte[2 * maxSize];
    Buffer.BlockCopy(rBytes, 0, rsBytes, maxSize - rBytes.Length, rBytes.Length);     // resize to maximum size
    Buffer.BlockCopy(sBytes, 0, rsBytes, 2 * maxSize - sBytes.Length, sBytes.Length); // resize to maximum size
    return rsBytes;
}

AsnReader is available since .NET 5.

For completeness: In other .NET versions BouncyCastle can be applied (using classes from the Org.BouncyCastle.Asn1 namespace). For this, the first three lines in DERtoP1363() must by replaced by:

Asn1Sequence sequence = Asn1Sequence.GetInstance(derSignature);
byte[] rBytes = DerInteger.GetInstance(sequence[0]).PositiveValue.ToByteArrayUnsigned();
byte[] sBytes = DerInteger.GetInstance(sequence[1]).PositiveValue.ToByteArrayUnsigned();