C# Can';无法获取Openssl签名数据以匹配.NET签名数据或BouncyCastle签名数据

C# Can';无法获取Openssl签名数据以匹配.NET签名数据或BouncyCastle签名数据,c#,openssl,bouncycastle,C#,Openssl,Bouncycastle,上周五我一直在做这件事,现在仍然很困惑 运行此命令时: echo -n "Data To Sign" | openssl pkeyutl -sign -inkey path/to/my.pem | openssl base64 通过openssl,我获得了以下输出: 1c284UkFgC6pqyJ+woSU+DiWB4MabWVDVhhUbBrTtF7CkpG8MjY+KkPFsZm9ZNM8vCjZjf...Kw= 我想在C#中复制这种行为。我的第一次尝试是使用openssl从我的.pem

上周五我一直在做这件事,现在仍然很困惑

运行此命令时:

echo -n "Data To Sign" | openssl pkeyutl -sign -inkey path/to/my.pem | openssl base64
通过openssl,我获得了以下输出:

1c284UkFgC6pqyJ+woSU+DiWB4MabWVDVhhUbBrTtF7CkpG8MjY+KkPFsZm9ZNM8vCjZjf...Kw=
我想在C#中复制这种行为。我的第一次尝试是使用openssl从我的.pem文件创建一个.p12文件。为此,我运行了以下两个openssl命令:

openssl req -new -key path/to/my.pem -x509 -batch > my.crt
openssl pkcs12 -export -in my.crt -inkey path/to/my.pem -out my.p12
然后使用
X509Certificate2
RSACryptServiceProvider
类加载.p12并签名。代码如下:

var dataToSign = "Data To Sign";
var p12 = new X509Certificate2(@"path\to\my.p12","");
var rsa = (RSACryptoServiceProvider)p12.PrivateKey;
var signedBytes = rsa.SignData(Encoding.UTF8.GetBytes(dataToSign), "SHA1");
var result = Convert.ToBase64String(signedBytes);
这将产生:

B2qM6MTjoZFSbnckezzpXrKFq67vFgsCPYBmaAbKOFmzVQLIU4a+GC6LWTMdNO4...Q0=
不幸的是,输出不匹配。经过一段时间的斗争后,我决定走一些答案建议的蹦蹦跳跳路线。下面是我使用该库得到的代码:

StreamReader sr = new StreamReader(@"path\to\my.pem");
PemReader pr = new PemReader(sr);
var pemKeyParams = (RsaPrivateCrtKeyParameters)pr.ReadObject();
var cypherParams = new RsaKeyParameters(true, pemKeyParams.Modulus, pemKeyParams.Exponent);
ISigner sig = SignerUtilities.GetSigner("SHA1withRSA");
sig.Init(true, cypherParams);
var bytes = Encoding.UTF8.GetBytes("Data To Sign");
sig.BlockUpdate(bytes, 0, bytes.Length);
byte[] signature = sig.GenerateSignature();
var result = Convert.ToBase64String(signature);
这也产生了:

B2qM6MTjoZFSbnckezzpXrKFq67vFgsCPYBmaAbKOFmzVQLIU4a+GC6LWTMdNO4...Q0=
BouncyCastle输出与使用安全命名空间中的本机库的C#代码给出的输出匹配,但我想匹配openssl的输出。我做错了什么

版本-
OpenSSL 1.0.1c
.NET 4.0
BouncyCastle 1.7.0
视窗7

佩姆先生-

-----开始私钥----- MIICDWIBADANBGKQHKIG9W0BAQEFAASCAMEWGGIDAGEAOGBAOTK3BYDQSJEG1XY 2KGF8ECWCPUDPENV32OIBTA+h2hXQ853ZRsxusopm7vmqtI2/aVfc2vyw9AGY0U CJQPNEQ7ET5OQYDO5+aTEW3PenP9DR3MJ273ipPbrYX+I3XzJ+I6//k6DO/OAIA JLLXC9IT1PBLsrymfnekifiugJ3GMBAAECGYBTP1LMWO3MS8JECWEIEH/a8D9f H4OZBD7DFQNXDICGUW1HM8PyrsljomqD8AgjRohpzNLZFQHQU4YE9RH8WAWSKUJ Qst/RJYDU3SNSCU/eg+ezuawUXafpPUEUTJ0aofdHn9GIVipiIi/4uaPP/IYtuC U2smep4C2+geqfTugQJBAP5MTaRQjoYBGKS/BGD0JB16MHF6FPDCX3NZ2CLTYZM o8edQZI4SbWoxkJaGqBOqDbz/dSmTLfRNmpAmC+AZ5SCQDs+CyDLbs3URvD7ajx JjsJoPbuVmqPBPGmAy/4Qt3QVp9AWk+9uckU90DYMqJp5bdGoeokmA65uuEcvqbs YZFVAKEA018文件7RJNFEOEDN9DXVBC2D14A0JTLLOAWZ1S8I4UPGWCJAJD7Q53X VYS7MOG1JAUG87+8CNAYZLZBI5xHQJANYQBAJQGQB2AWJ8CUM81BUVU0K2HXOW i5hoXXprmynfTyL3N2r99gSNswcuqkqRPT9KfBRuMSzhZUi5IZ05tQJBAKdQ3mJZ 1Vys2nEAXbQD5/ldi1+VF/0t4Z+JxqFBjqtsAoASBN+KSIPANRL375OZ9M9GKD 5YSN0L+WD5Bf4U= -----结束私钥-----

出于这个问题的目的,我生成了一个新的.pem,上面的密钥不保护任何重要的内容,但我提供它是为了复制上面的步骤

到目前为止我考虑过的事情:
*编码(ASCII与UTF8)
*Endianess(-openssl的版本仍然与两个编码结果都不匹配)
*hashalg(我在任何地方都找不到“SHA1”是正式使用的正确的哈希算法,但它似乎是其他人正在使用的,尝试其他选项也没有帮助)
*换行符(我相信回声上的-N需要与库保持一致,但是删除它没有帮助) *询问SO(结果待定:-)


TIA

RSA签名可以使用不同的填充模式(PKCS#1、PSS等)。对于最后一个,它使用一些随机盐,因此每次签名都会不同。
因此,首先检查openssl每次是否生成相同的值(我没有找到openssl代码使用的默认填充,您可以使用-rsa_padding_mode参数对其进行更改),实际上,检查另一方是否可以正确验证这两个签名。

我猜openssl pkeyutl命令实际上是直接对数据进行签名,而不是签署数据摘要

pkeyutl上的openssl文档包含以下建议性评论:

“除非另有说明,否则所有算法都支持摘要:alg 选项,指定用于签名、验证和验证的摘要 verifyrecover操作。值alg应表示摘要名称 在EVP_get_digestbyname()函数中使用,例如sha1。“

我在命令行中没有看到摘要选项。此外,来自相同的文档(在RSA部分):

“在PKCS#1填充中,如果未设置消息摘要,则提供 直接对数据进行签名或验证,而不是使用摘要信息 结构。如果设置了摘要,则使用摘要信息结构 其长度必须与摘要类型相对应。”


另请参阅openssl dgst的文档。

Ding。这给了我需要的提示。运行以下命令
echo-n“要签名的数据”| openssl dgst-sha1-Sign my.pem | openssl base64
会给出与我的C代码相同的签名。耶。现在我只需要弄清楚如何告诉C代码在签名之前不要消化消息。那么,就BC而言,切换到SignerUtilites.GetSigner(“RSA”)有效吗?对于RSACryptoServiceProvider,您可能需要使用SignHash,尽管该方法似乎要求所讨论的数据实际上是通过某个命名的哈希创建的……是的,GetSigner(“RSA”)实现了openssl与BC的匹配。我对RSACsp的SignHash有一个例外。现在,我将只接受对BC的依赖,稍后再回到它。谢谢你的帮助+1,thx伙计,帮了我很多