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
r
ands
in byte[] in P1363 format? - How to make sure I can convert it back through take half of array for
r
and other half fors
. - Sometimes
r
equals
, ors
larger 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
StandardDsaEncoding
used to encode/decode ASN1.Der format.PlainDsaEncoding
used 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.