问题描述
我想使用以下代码制作ECDSA签名:
I want to make a ECDSA signature with this code :
AsymmetricKeyAlgorithmProvider objAsymmAlgProv = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.EcdsaSha256);
CryptographicKey keypair = objAsymmAlgProv.CreateKeyPairWithCurveName(EccCurveNames.SecP256r1);
BinaryStringEncoding encoding = BinaryStringEncoding.Utf8;
buffMsg = CryptographicBuffer.ConvertStringToBinary("Test Message", encoding);
IBuffer buffSIG = CryptographicEngine.Sign(keypair, buffMsg);
byte [] SignByteArray = buffSIG.ToArray();
bool res = CryptographicEngine.VerifySignature(keypair, buffMsg, buffSIG);
VerifySignature
始终返回true,这是可以的
VerifySignature
always returns true and this is ok.
但是我在签名时遇到了一些问题。
But I have some problems with signature.
为什么签名长度( SignByteArray
)已修复? (0x40字节)。
Why is length of signature ( SignByteArray
) fixed? (0x40 byte).
为什么 SignByteArray [0]
和 SignByteArray [2] ]
值不正确? (我认为它们应该是0x30和0x02)
And Why are SignByteArray [0]
and SignByteArray [2]
values incorrect? (I think they should be 0x30 and 0x02)
我期望像
推荐答案
ECDSA规范以确定该对( r
, s
)为签名作为结论。它忽略了做的事情是指示应该如何记录它们。
The ECDSA specification concludes with a determination that the pair (r
, s
) are the signature. What it neglects to do is indicate how one should write them down.
Windows和.NET使用IEEE(P)1363格式,即big-endian r
concat big-endian s
。 r
和 s
具有相同的大小(由密钥大小确定),因此签名始终是均匀的长度,并且r是上半部分。
Windows and .NET use the IEEE (P)1363 format, which is big-endian r
concat big-endian s
. r
and s
have the same size (determined by the key size), so the signature is always even in length and r is the first half.
OpenSSL使用ASN.1 / DER编码,即SEQUENCE(INTEGER(r),INTEGER(s))。 DER编码可以一直下降到6个字节( 30 04 02 00 02 00
,在简并的r = 0,s = 0中),平均而言,比IEEE格式大6个字节。它编码为 30 [长度,一个或多个字节] 02 [长度,一个或多个字节] [可选的填充00] [没有前导00的big-endian r] 02 [长度,一个或多个字节] ] [可选的填充00] [big-endian s,无前导00s]
。
OpenSSL uses an ASN.1/DER encoding, which is SEQUENCE(INTEGER(r), INTEGER(s)). The DER encoding can go all the way down to 6 bytes (30 04 02 00 02 00
, in the degenerate r=0, s=0) and is, on average, 6 bytes bigger than the IEEE form. It encodes as 30 [length, one or more bytes] 02 [length, one or more bytes] [optional padding 00] [big-endian r with no leading 00s] 02 [length, one or more bytes] [optional padding 00] [big-endian s with no leading 00s]
.
DER格式过于依赖数据,无法具体描述,所以一个例子应该有所帮助。假设我们在32位字段中使用曲线并生成(r = 1016,s = 2289644760)。
The DER form is too data dependant to specifically describe, so an example should help. Assuming we're using a curve in a 32-bit field and we generate (r=1016, s=2289644760).
IEEE 1363:
IEEE 1363:
// r
00 00 03 F8
// s
88 79 34 D8
DER:
SEQUENCE(INTEGER(1016), INTEGER(2289644760))
// Encode r
// 1016 => 0x3F8 => 03 F8 (length 02)
SEQUENCE(
02 02
03 F8,
INTEGER(2289644760))
// Encode s
// 2289644760 => 0x887934D8 => 88 79 34 D8
// But since the high bit is set this is a negative number (-2005322536),
// and s is defined to be positive. So insert a 00 to ensure the high bit is clear.
// => 00 88 79 34 D8 (length 05)
SEQUENCE(
02 02
03 F8
02 05
00 88 79 34 D8)
// And encode the sequence, whose payload length we can now count as 11 (0B)
30 0B
02 02
03 F8
02 05
00 88 79 34 D8
因此Windows / .NET发出 00 00 03 F8 88 79 34 D8
,而OpenSSL发出 30 0B 02 02 03 F8 02 05 00 88 79 34 D8
。但是他们俩都只是说(r,s)=(1016,2289644760)
。
So Windows/.NET emit 00 00 03 F8 88 79 34 D8
, and OpenSSL emits 30 0B 02 02 03 F8 02 05 00 88 79 34 D8
. But they're both just saying (r, s) = (1016, 2289644760)
.
(在旁边:您观察到DER编码中的signature [2] == 0x02对于您正在使用的大小密钥是正确的,但是在大约496位密钥处,SEQUENCE长度在统计上可能需要一个以上的字节;因此对于P-521密钥,最有可能以 03 81 88 02
开头,并且在 88
字节中具有可变性)
(Aside: Your observation that signature[2] == 0x02 in the DER encoding is correct for the size key you're working with, but at around a 496-bit key the SEQUENCE length becomes statistically likely to require more than one byte; so for a P-521 key it's most likely that it starts as 03 81 88 02
, with variability in the 88
byte)
这篇关于UWP ECDSP签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!