【问题标题】:RSA signing with imported private key使用导入的私钥进行 RSA 签名
【发布时间】:2016-05-26 16:42:40
【问题描述】:

我购买了 SSL 证书 b/c arvixe 不支持自签名证书。我在 .pem 文件中有一个私钥,我想用它来对银行交易参数进行 RSA 签名。到目前为止,我还没有找到可以做到的方法。

certificate.PrivateKey 引发 Keyset not found 异常。使用充气城堡导入私钥 (.pem) 文件工作正常,直到我需要转换为 RSACryptoServiceProvider。此时,DotNetUtilities.ToRSA 会引发 File Not Found 异常。一定有更好的方法来做到这一点!!!

这是我代码中的相关 sn-p:

            public string SignRsa(string stringToSign)
        {
            var encoder = new ASCIIEncoding();
            var binData = encoder.GetBytes(stringToSign);
            byte[] binSignature;

            if (Request.Url.OriginalString.IndexOf("localhost", StringComparison.Ordinal) < 0)
            {
                var store = new X509Store(StoreLocation.LocalMachine);
                store.Open(OpenFlags.ReadOnly);
                var certificates = store.Certificates;
                var signed = string.Empty;
                X509Certificate2 ipCert = certificates.Find(X509FindType.FindBySubjectName, "www.ingyenpiac.com", false).OfType<X509Certificate2>().First();
                RSACryptoServiceProvider rsaCsp;
                if (ipCert != null)
                {
                    AsymmetricCipherKeyPair keyPair;
                    using (var reader = System.IO.File.OpenText(Server.MapPath("~/App_Data/private_key.pem"))) // file containing RSA PKCS1 private key
                        keyPair = (AsymmetricCipherKeyPair)new PemReader(reader).ReadObject();
                    PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);
                    byte[] serializedPrivateBytes = privateKeyInfo.ToAsn1Object().GetDerEncoded();
                    string serializedPrivate = Convert.ToBase64String(serializedPrivateBytes);
                    SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public);
                    byte[] serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded();
                    string serializedPublic = Convert.ToBase64String(serializedPublicBytes);
                    RsaPrivateCrtKeyParameters privateKey = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(serializedPrivate));
                    RsaKeyParameters publicKey = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(serializedPublic));
                    var kpp = keyPair.Private as RsaPrivateCrtKeyParameters;
                    var ppk = DotNetUtilities.ToRSA(kpp); //   <==== File not found exception!!!! WTF???
                    RSACryptoServiceProvider tempRcsp = (RSACryptoServiceProvider)ppk;
                    RSACryptoServiceProvider rcsp = new RSACryptoServiceProvider(new CspParameters(1, "Microsoft Strong Cryptographic Provider", new Guid().ToString(), new CryptoKeySecurity(), null));
                    rcsp.ImportCspBlob(tempRcsp.ExportCspBlob(true));
                    ipCert.PrivateKey = rcsp;
                    if (ipCert.Verify())
                    {
                        rsaCsp = (RSACryptoServiceProvider)ipCert.PrivateKey;
                    }
                    else
                        throw new ApplicationException("Certificate failed to verify.");
                }
                else
                    throw new ApplicationException("SignRsa: No certifciate found");
                using (var sha = new SHA1CryptoServiceProvider())
                {
                    binSignature = rsaCsp.SignData(binData, sha);
                }
                if (rsaCsp.VerifyData(binData, new SHA1CryptoServiceProvider(), binSignature))
                    signed = BitConverter.ToString(binSignature).Replace("-", string.Empty);
                store.Close();
                return signed;
            }
return null;
}

我当然希望有人可以帮助我!

【问题讨论】:

    标签: c#-4.0 cryptography rsa bouncycastle x509certificate2


    【解决方案1】:

    使用 .NET 4.6,此代码可以稍微简化:

    public string SignRsa(string stringToSign)
    {
        var signed = string.Empty;
    
        using (var ipCert = new X509Certificate2(Server.MapPath("~/App_Data/pfxFile.pfx"), "password"))
        using (var RSA = ipCert.GetRSAPrivateKey())
        {
            // Note, if the cert was not RSA, or had no private key, RSA
            // will be null.  But you didn't check it, so I won't.
            var binData = System.Text.Encoding.ASCII.GetBytes(stringToSign);
            byte[] binSignature = RSA.SignData(binData, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
    
            // Not sure why you want to re-verify the signature, but OK:
            if (RSA.VerifyData(binData, binSignature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1))
                signed = BitConverter.ToString(binSignature).Replace("-", string.Empty);
    
            return signed;
        }
    }
    

    【讨论】:

      【解决方案2】:

      哇!我真的把事情复杂化了。不需要充气城堡,也不需要扭曲。答案很简单,如下图:

          public string SignRsa(string stringToSign)
          {
              ASCIIEncoding encoder;
              var signed = string.Empty;
              var ipCert = new X509Certificate2(Server.MapPath("~/App_Data/pfxFile.pfx"), "password");
              var RSA = (RSACryptoServiceProvider)ipCert.PrivateKey;
              encoder = new ASCIIEncoding();
              var binData = encoder.GetBytes(stringToSign);
              byte[] binSignature;
              using (var sha1 = new SHA1CryptoServiceProvider())
                  binSignature = RSA.SignData(binData, sha1);
              if (RSA.VerifyData(binData, new SHA1CryptoServiceProvider(), binSignature))
                  signed = BitConverter.ToString(binSignature).Replace("-", string.Empty);
              return signed;
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-01-13
        • 2012-07-15
        • 2023-04-02
        • 2011-03-11
        • 1970-01-01
        • 2012-07-13
        • 2013-06-06
        • 2023-04-11
        相关资源
        最近更新 更多