使用C#中的.Pem / .Pkcs8密钥文件中的MD5WithRSA对数据进行签名

我在Java中有以下代码示例,我需要在C#中重新编写它:

PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(pkcs8PrivateKey); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PrivateKey privKey = keyFactory.generatePrivate(privKeySpec); Signature sign = Signature.getInstance("MD5withRSA"); sign.initSign(privKey); sign.update(data); byte[] signature = sign.sign(); 

是否可以使用标准的.Net Crypto API,还是应该使用BouncyCastle? 谢谢,

我遇到了一个非常类似的问题,试图创建一个用于打包Chrome扩展的原生C#工具(使用SHA1,而不是MD5,但这没有太大区别)。 我相信我已经尝试过.Net的所有可能的解决方案:System.Security.Cryptography,BouncyCastle,OpenSSL.Net和Chilkat RSA。

最好的解决方案可能是奇尔卡特; 他们的界面是最干净,最直接的,它得到了良好的支持和良好的记录,并且有一百万个例子。 例如,这里有一些代码使用他们的库来做一些非常接近你想要的东西: http : //www.example-code.com/csharp/rsa_signPkcs8.asp 。 然而,这不是免费的(虽然150美元并非不合理,因为我已经烧了2天试图解决这个问题,而且我每天花费超过75美元!)。

作为一种免费的替代方案,JavaScience在http://www.jensign.com/JavaScience/cryptoutils/index.html上为多种语言(包括C#/ .Net)提供了许多源代码forms的加密实用程序。 你想要做的最突出的是opensslkey( http://www.jensign.com/opensslkey/index.html ),它可以让你从.pem文件生成一个RSACryptoServiceProvider。 然后,您可以使用该提供程序对代码进行签名:

  string pemContents = new StreamReader("pkcs8privatekey.pem").ReadToEnd(); var der = opensslkey.DecodePkcs8PrivateKey(pemContents); RSACryptoServiceProvider rsa = opensslkey.DecodePrivateKeyInfo(der); signature = rsa.SignData(data, new MD5CryptoServiceProvider()); 

另一种方法是使用CNG(下一代加密)以及CodePlex的Security.Cryptography DLL

然后你可以写:

 byte[] dataToSign = Encoding.UTF8.GetBytes("Data to sign"); using (CngKey signingKey = CngKey.Import(pkcs8PrivateKey, CngKeyBlobFormat.Pkcs8PrivateBlob)) using (RSACng rsa = new RSACng(signingKey)) { rsa.SignatureHashAlgorithm = CngAlgorithm.MD5; return rsa.SignData(dataToSign); } 

感谢Simon Mourier:使用.Net 4.6,您不再需要单独的库

这个SO问题回答了代码的PKCS#8部分。 其余的.NET RSA类是一个奇怪的混乱的部分重叠类,很难理解。 肯定看来,签名支持位于RSACryptoServiceProvider和/或RSAPKCS1SignatureFormatter类中。

免责声明:我了解Java和密码学,但我对C#和.NET的了解非常有限。 我只是在Google-fu技能的影响下写这里。

假设您可以解码PKCS#8编码的RSA私钥,那么,根据我在MSDN上阅读的内容,其余代码应如下所示:

 byte[] hv = MD5.Create().ComputeHash(data); RSACryptoServiceProvider rsp = new RSACryptoServiceProvider(); RSAParameters rsp = new RSAParameters(); // here fill rsp fields by decoding pkcs8PrivateKey rsp.ImportParameters(key); RSAPKCS1SignatureFormatter rf = new RSAPKCS1SignatureFormatter(rsp); rf.SetHashAlgorithm("MD5"); byte[] signature = rf.CreateSignature(hv); 

相关类位于System.Security.Cryptography命名空间中。

至于PKCS#8密钥blob解码(即填写rsp字段),我发现这个页面描述了C#中可以执行该工作的命令行实用程序。 提供源代码并且是单个C#文件。 根据我在其中读到的内容,该代码“手动”解码PKCS#8文件; 间接地,这应该意味着原始.NET(2.0)没有用于PKCS#8密钥文件解码的工具(否则该工具的作者将不会遇到实现这种解码的麻烦)。 对于您手头的任务,您可以从源文件中清除所需的部分,跳过有关PEM和对称加密的任何内容; 你的入口点是DecodePrivateKeyInfo()函数,它显然需要一个DER编码的未加密的PKCS#8文件,就像Java的PKCS8EncodedKeySpec

您可以使用此代码。 首先,您应该从http://www.bouncycastle.org/csharp/下载“BouncyCastle.Crypto.dll”。

 ///  /// MD5withRSA Signing /// https://www.vrast.cn /// keyle_xiao 2017.1.12 ///  public class MD5withRSASigning { public Encoding encoding = Encoding.UTF8; public string SignerSymbol = "MD5withRSA"; public MD5withRSASigning() { } public MD5withRSASigning(Encoding e, string s) { encoding = e; SignerSymbol = s; } private AsymmetricKeyParameter CreateKEY(bool isPrivate, string key) { byte[] keyInfoByte = Convert.FromBase64String(key); if (isPrivate) return PrivateKeyFactory.CreateKey(keyInfoByte); else return PublicKeyFactory.CreateKey(keyInfoByte); } public string Sign(string content, string privatekey) { ISigner sig = SignerUtilities.GetSigner(SignerSymbol); sig.Init(true, CreateKEY(true, privatekey)); var bytes = encoding.GetBytes(content); sig.BlockUpdate(bytes, 0, bytes.Length); byte[] signature = sig.GenerateSignature(); /* Base 64 encode the sig so its 8-bit clean */ var signedString = Convert.ToBase64String(signature); return signedString; } public bool Verify(string content, string signData, string publickey) { ISigner signer = SignerUtilities.GetSigner(SignerSymbol); signer.Init(false, CreateKEY(false, publickey)); var expectedSig = Convert.FromBase64String(signData); /* Get the bytes to be signed from the string */ var msgBytes = encoding.GetBytes(content); /* Calculate the signature and see if it matches */ signer.BlockUpdate(msgBytes, 0, msgBytes.Length); return signer.VerifySignature(expectedSig); } }