C# ECC p-128未在c中生成32字节数组签名#
signature1值在转换为十六进制时始终为39字节[]数组,长度大于64。 我想从c#中的P-128 ECC算法生成精确的64长度十六进制签名值 让我解释一下下面的代码:C# ECC p-128未在c中生成32字节数组签名#,c#,.net,cryptography,bouncycastle,elliptic-curve,C#,.net,Cryptography,Bouncycastle,Elliptic Curve,signature1值在转换为十六进制时始终为39字节[]数组,长度大于64。 我想从c#中的P-128 ECC算法生成精确的64长度十六进制签名值 让我解释一下下面的代码: 对我必须签名的纯文本消息进行哈希 从本地文件夹读取128位PEM密钥 传递密钥并生成签名 public static string GenerateSignature(string message, string privateKeyPath) { string hashMessage;
有不同的签名格式,一种是ASN.1 DER格式,在代码中使用,并对其进行了说明。对于曲线secp128r1(P-128),生成的签名长度在38到40字节之间 您似乎期望的格式是r | s(请参阅),对于曲线secp128r1,其长度为32字节 您可以轻松地手动在这两种格式之间进行转换 更新版本的BouncyCastle for C#还允许直接生成r|s格式的签名,请参见,例如,使用
SHA-256withPLAIN-ECDSA
(而不是SHA-256withECDSA
)
请注意:
- 根据NIST,128位的密钥大小同时太小(相反,2019-2030年建议至少224位)。secp128r1仍在(从2000年起)中推荐,但在(从2010年起)中不再推荐
(SHA-256withECDSA
)隐式散列消息(使用SHA-256),即不需要显式散列,并导致双重(冗余)散列SHA-256withPLAIN-ECDSA
- 此外,在显式散列中,传递给签名者的不是实际的二进制散列,而是UTF-8编码的十六进制编码散列
- secp128r1对应于128位(16字节)的密钥大小(基点顺序)。但是对于SHA256,您使用的摘要是两倍大(32字节)。在这种情况下,根据NIST FIPS 186-4,使用散列的最左边n位
消息进行编码,并根据曲线secp128r1和摘要SHA256生成r|s格式的ECDSA签名(对应于IEEE P1363):
public static string GenerateSignature(string message, string privateKeyPath)
{
byte[] messageBytes = Encoding.UTF8.GetBytes(message);
ISigner signer = SignerUtilities.GetSigner("SHA-256withPLAIN-ECDSA");
AsymmetricCipherKeyPair keyPair = getPrivateKeyFromPemFile(privateKeyPath); // get secp128r1 key pair
signer.Init(true, keyPair.Private);
signer.BlockUpdate(messageBytes, 0, messageBytes.Length);
byte[] signature = signer.GenerateSignature();
return ByteArrayToString(signature); // https://stackoverflow.com/a/311179/9014097
}
请注意与您最初发布的代码相比的差异:
- 由于(
Org.BouncyCastle.Crypto.
)ISigner#GenerateSignature()
隐式散列,因此不执行显式散列
SHA-256withPLAIN-ECDSA
直接以r|s格式生成签名,自v1.8.4(bccrypto-csharp-1.8.4,2018年10月27日发布)起存在
如果是较旧的BouncyCastle版本(仅提供带有ECDSA的SHA-256
),则必须手动将签名从ASN.1 DER转换为r | s格式。这很容易,因为r和s可以直接从ASN.1 DER格式中提取,请参阅
如果客户端的验证仍然未能通过上述代码,请检查两侧的键、曲线和摘要是否匹配以及验证过程本身
为了完整性:
当然,也可以使用(
Org.BouncyCastle.Crypto.Signers.
)ECDsaSigner.GenerateSignature(byte[]msg)
生成签名。重要的是,此方法不会隐式散列,即这里确实必须显式散列。这个方法返回r和s作为(Org.BouncyCastle.Math.
)biginger[]
,这样这两部分都可以很容易地用十六进制编码,例如toString(16)
,然后连接到r | s。Tapaco,我需要IEEE P1363输出64长度的单个十六进制字符串,我得到签名(r,s)如果我加入它,它将转换为64长度的十六进制。但它仍然没有在我的客户处验证。请帮助曲线secp128r1(P-128)生成的签名长度在38到40字节之间。我需要精确的32字节(使用IEEE P1363),然后它将转换为64个字节。您如何修改代码以生成r | s格式的签名,您是否将SHA-256替换为ECDSA
?对于更复杂的更改,例如,如果您手动从ASN.1 DER格式派生r|s格式,请编辑您的答案并添加当前代码以创建r|s签名(请不要更改已发布的代码,而是添加新代码)。您的代码中还有其他问题,特别是我列表底部的第2点和第3点:ISigner#GenerateSignature()
隐式地进行哈希运算(这就是摘要名称包含在说明符中的原因),因此无需显式地进行哈希运算。因此,您可以尝试将BlockUpdate
中的hashMessageBytes
替换为Encoding.UTF8.GetBytes(message)
。最后发布的代码与原始代码明显不同。使用三个代码没有什么意义,因此我在原始代码的基础上发布了一个可能的解决方案,请参阅我答案中的编辑部分。