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();