I don't find any reference for deterministic with P1363 format. the r and s always different in deterministic mode.
Non-Deterministic with P1363 -> WithPlain-ECDSA OK
ISigner sign = SignerUtilities.GetSigner("SHA256WithPlain-ECDSA");
sign.Init(true, privateKey);
sign.BlockUpdate(message, 0, message.Length);
byte[] signedBytes = sign.GenerateSignature(); // Signature can divded by 2. OK
Deterministic way: (How to apply WithPlain-ECDSA?)
var signer = new ECDsaSigner(new HMacDsaKCalculator(new Sha256Digest()));
signer.Init(true, privateKey);
var toto = signer.GenerateSignature(message);
var r = toto[0].ToByteArray(); // sometimes r are equqal s
var s = toto[1].ToByteArray(); // sometimes s larger than s byte one.
I can't return r.Concat(s).ToArray(). There's no way to convert r and s to byte[] untill it converted to P1363? which doesn't exist in deterministic version above...
- How to concatenate
randsin byte[] in P1363 format? - How to make sure I can convert it back through take half of array for
rand other half fors. - Sometimes
requals, orslarger thanr, How to make sure exactly both are equal when generated?
I don't find any reference for P1363. But I found only ASN1 DER format:
using (MemoryStream ms = new MemoryStream())
using (Asn1OutputStream asn1stream = new Asn1OutputStream(ms))
{
DerSequenceGenerator seq = new DerSequenceGenerator(asn1stream);
seq.AddObject(new DerInteger(s));
seq.AddObject(new DerInteger(s));
seq.Close();
var arrr = ms.ToArray();
}
Am also tried this trick
But I looped 1000 and check if arrays of r.Length == s.Length, No equality in all loop.. As he use BigInteger.ToByteArrayUnsigned().
Not sure exactly 100% if above guy's trick work, But the guy try to generate it in fixed way:
Array.Copy(sig1, 0, sig, 0 (32 - sig1.Length), sig1.Length);
Array.Copy(sig2, 0, sig, 32 (32 - sig2.Length), sig2.Length);
Short Answer:
According to @Topaco answer, its fast manual approach. Many thanks to him. There's also two classes we can use after investigation StandardDsaEncoding and PlainDsaEncoding classes
StandardDsaEncodingused to encode/decode ASN1.Der format.PlainDsaEncodingused to encode/decode P1363 format.
PlainDsaEncoding.Instance.Encode() // This convert to P1363 format.
PlainDsaEncoding.Instance.Decode() // Decode to signature BigInteger[] again. (r, s)
Note: ECDsaSigner can wrapped inside DsaDigestSigner to allow hash of message automatically. or compute hash(message) manually then use ECDsaSigner exactly like @Topaco other post answer.
CodePudding user response:
For P1363 it's irrelevant whether the deterministic or non-deterministic ECDSA algorithm is used to determine the signature.
In P1363:
- r and s are contained as unsigned, big endian arrays
- r and s are padded to their maximum size (length of the order of the generator point) with leading 0x00 values
In your code, r (toto[0]) and s (toto[1]) are both of type Org.BouncyCastle.Math.BigInteger. The conversion to P1363 is then simply possible with (for simplicity, the maximum size is not calculated, but passed):
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Utilities.Encoders;
using System;
// r and s as BigIntegers
BigInteger r = new BigInteger("184277181267172538606383136781492460232995304963063764346199145255201368533");
BigInteger s = new BigInteger("59980738789003505646930326203273200546254161299399868639304126982806381806190");
// Convert to unsigned, big endian arrays
var rBytes = r.ToByteArrayUnsigned();
var sBytes = s.ToByteArrayUnsigned();
// Pad to maximum size
int maxSize = 32;
byte[] rsBytes = new byte[2 * maxSize];
Buffer.BlockCopy(rBytes, 0, rsBytes, maxSize - rBytes.Length, rBytes.Length);
Buffer.BlockCopy(sBytes, 0, rsBytes, 2 * maxSize - sBytes.Length, sBytes.Length);
Console.WriteLine(Hex.ToHexString(rsBytes)); // 00684c148ab8582b55fa0929de7853503a05f57119d80cb8b0172103eca369d5849be52463b4911ab97c4cbb17322afc0be9a973269d9d263e23bdd43f18426e
The output is 2 * maxSize bytes large and for this example:
00684c148ab8582b55fa0929de7853503a05f57119d80cb8b0172103eca369d5849be52463b4911ab97c4cbb17322afc0be9a973269d9d263e23bdd43f18426e
The first maxSize bytes are r, the last maxSize bytes are s.
For comparison: The same signature in ASN.1/DER format is:
3044021f684c148ab8582b55fa0929de7853503a05f57119d80cb8b0172103eca369d5022100849be52463b4911ab97c4cbb17322afc0be9a973269d9d263e23bdd43f18426e
Edit:
The OP pointed out that BouncyCastle already has implementations for this conversion. This is indeed the case:
using Org.BouncyCastle.Crypto.Signers;
// Applied curve: secp256r1 aka P-256 aka prime256v1
BigInteger n = new BigInteger(1, Convert.FromHexString("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551")); // n: order of generator point
byte[] p1363 = PlainDsaEncoding.Instance.Encode(n, r, s);
Console.WriteLine(Hex.ToHexString(p1363)); // 00684c148ab8582b55fa0929de7853503a05f57119d80cb8b0172103eca369d5849be52463b4911ab97c4cbb17322afc0be9a973269d9d263e23bdd43f18426e
byte[] asn1Der = StandardDsaEncoding.Instance.Encode(n, r, s);
Console.WriteLine(Hex.ToHexString(asn1Der)); // 3044021f684c148ab8582b55fa0929de7853503a05f57119d80cb8b0172103eca369d5022100849be52463b4911ab97c4cbb17322afc0be9a973269d9d263e23bdd43f18426e
The Encode() methods determine the maximum size from the order n of the generator point.
