应用程序调用openssl来使用
openssl rsautl -sign -in rasi.bin -inkey riktest.key -out allkiri.bin如何将其转换为.NET 6,以便不需要调用openssl?
riktest.key是包含
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAfddAQEArYjDH7msMFifeYc1AG/TkKpcz2LITI73sC0eqnlgmWi3F7PD
Bo8lWrCw32h3v/FFMrK8KuktlnBtsSLaCCz1DWuXORzHaW7EqG8O8QNzFSmhIoqp
...这是ASP.NET 6 MVC应用程序。.NET 6 System.Security.Cryptography命名空间是否包含此OpenSsl功能?
发布于 2022-03-20 12:01:28
为什么通常不能使用本机.NET方法
对于RSASignaturePadding.Pkcs1,本机.NET实现SignData()和SignHash()遵循RFC8017中描述的5签名方案,该方案将5应用于编码操作:对消息进行散列处理,并对以下值进行签名(即用私钥加密):
EM = 0x00 || 0x01 || PS || 0x00 || T在这里,PS包含如此多的0xff值,使得EM的大小等于键的模数的大小。T是DigestInfo值的高级编码,它包含摘要OID和散列,例如对于SHA256:
3031300d060960864801650304020105000420 || H 其中H是要签名的消息M的32字节SHA56散列。
相反,https://www.openssl.org/docs/man1.1.1/man1/rsautl.html直接使用RSA算法,如备注部分中提到的,即对以下数据进行签名:
EM' = 0x00 || 0x01 || PS || 0x00 || M通常情况下,本机.NET方法无法实现这一点(除了特殊用例之外,请参阅下面):SignData()散列(因此失败),SignHash()不散列,但在内部(如SignData())生成DigestInfo值的DER编码。
另一种选择是BouncyCastle,它使用算法NoneWithRSA签名,就像openssl一样。
该算法的一个缺点是,由于缺少散列,只能对短消息进行签名,因为对于较长的消息,不能满足长度准则(根据该准则,EM‘的大小必须与密钥模数的大小相对应)。
密钥导入
posted密钥是PKCS#1格式的PEM编码私钥。
自.NET 5以来,ImportFromPem()支持ImportFromPem()导入PEM编码密钥(私有/公共、PKCS#8/PKCS#1格式),但从.NET Core3.0开始就支持DER编码密钥的导入。PKCS#1格式的私有DER编码密钥可以用ImportRSAPrivateKey()导入( PEM和DER编码之间的转换非常简单,包括删除页眉、页脚和换行以及其余主体的Base64解码)。
BouncyCastle支持使用PemReader类导入PEM编码的密钥。
--使用BouncyCastle实现发布的OpenSSL功能的可能性
以下代码生成与OpenSSL语句相同的签名,当rasi.bin保存来自dataToSign的数据,而riktest.key持有来自privatePkcs1Pem的密钥时
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using System;
using System.IO;
...
// For testing purposes a 512 bits key is used.
// In practice, keys >= 2048 bits must be used for security reasons!
string privatePkcs1Pem = @"-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBANoHbFSEZoOSB9Kxt7t8PoBwmauaODjECHqJgtTU3h4MW5K3857+
04Flc6x6a9xxyvCKS5RtOP2gaOlOVtrph0ECAwEAAQJBALu8LpRr2RWrdV7/tfQT
HIJd8oQnbAe9DIvuwh/fF08IwApOE/iGL+Ded49eoHHu1OXycZhpHavN/sQMnssP
FNECIQDyDIW7V5UUu16ZAeupeQ7zdV6ykVngd0bb3FEn99EchQIhAOaYe3ll211q
SIXVjKHudMn3xe6Vvguc9O7cwCB+gyqNAiEAsr3kk6/de23SMZNlf8TR8Z8eyybj
BAuQ3BMaKzWpyjECIFMR0UFNYTYIyLF12aCoH2h2mtY1GW5jj5TQ72GFUcktAiAf
WWXnts7m8kZWuKjfD0MQiW+w4iAph+51j+wiL3EMAQ==
-----END RSA PRIVATE KEY-----";
byte[] dataToSign = Convert.FromHexString("3031300d060960864801650304020105000420d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592");
// Import private PKCS#1 key, PEM encoded
PemReader pemReader = new PemReader(new StringReader(privatePkcs1Pem));
AsymmetricKeyParameter privateKeyParameter = ((AsymmetricCipherKeyPair)pemReader.ReadObject()).Private;
// Sign raw data
ISigner signer = SignerUtilities.GetSigner("NoneWithRSA");
signer.Init(true, privateKeyParameter);
signer.BlockUpdate(dataToSign, 0, dataToSign.Length);
byte[] signature = signer.GenerateSignature();
Console.WriteLine(Convert.ToHexString(signature)); // 8C83CAD897EDA249FEC9EBA231061D585DAFC99177267E3E71BB8A3FCE07CC6663BF4DF7AF2E1C1945D2A6BB42EB25F042228B591FC18CDA82D92CAAE844670C特殊用例-当本机C#方法可以使用时
如果rasi.bin包含DigestInfo值的DER编码,则不需要BouncyCastle。
下面的示例假设rasi.bin包含消息的DigestInfo值的DER编码,快速棕狐跳过以SHA256作为摘要的懒狗。即,最后32个字节对应于SHA256哈希。
然后,使用本机.NET方法的一个可能的实现是:
using System;
using System.Security.Cryptography;
...
// For testing purposes a 512 bits key is used.
// In practice, keys >= 2048 bits must be used for security reasons!
string privatePkcs1Pem = @"-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBANoHbFSEZoOSB9Kxt7t8PoBwmauaODjECHqJgtTU3h4MW5K3857+
04Flc6x6a9xxyvCKS5RtOP2gaOlOVtrph0ECAwEAAQJBALu8LpRr2RWrdV7/tfQT
HIJd8oQnbAe9DIvuwh/fF08IwApOE/iGL+Ded49eoHHu1OXycZhpHavN/sQMnssP
FNECIQDyDIW7V5UUu16ZAeupeQ7zdV6ykVngd0bb3FEn99EchQIhAOaYe3ll211q
SIXVjKHudMn3xe6Vvguc9O7cwCB+gyqNAiEAsr3kk6/de23SMZNlf8TR8Z8eyybj
BAuQ3BMaKzWpyjECIFMR0UFNYTYIyLF12aCoH2h2mtY1GW5jj5TQ72GFUcktAiAf
WWXnts7m8kZWuKjfD0MQiW+w4iAph+51j+wiL3EMAQ==
-----END RSA PRIVATE KEY-----";
byte[] sha256DigestInfoDer = Convert.FromHexString("3031300d060960864801650304020105000420d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592");
byte[] sha256HashToSign = new byte[32];
Buffer.BlockCopy(sha256DigestInfoDer, sha256DigestInfoDer.Length - sha256HashToSign.Length, sha256HashToSign, 0, sha256HashToSign.Length);
using (RSA rsa = RSA.Create())
{
rsa.ImportFromPem(privatePkcs1Pem);
byte[] signature = rsa.SignHash(sha256HashToSign, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); // pass the SHA256 hash, internally the DER encoding of the DigestInfo is generated (which is why the digest must be specified)
Console.WriteLine(Convert.ToHexString(signature)); // 8C83CAD897EDA249FEC9EBA231061D585DAFC99177267E3E71BB8A3FCE07CC6663BF4DF7AF2E1C1945D2A6BB42EB25F042228B591FC18CDA82D92CAAE844670C
}这提供了相同的签名,因为rasi.bin在两种情况下都是相同的。
但是,请记住,只有当rasi.bin包含DigestInfo值的DER编码时,最后一种方法才能工作,而第一种解决方案则适用于rasi.bin中的任意数据(只要满足长度条件)。
https://stackoverflow.com/questions/71538998
复制相似问题