使用C#、BouncyCastle和导入的RSA密钥进行RSA签名和验证-内部可工作的Python示例和不可工作的C#代码示例

使用C#、BouncyCastle和导入的RSA密钥进行RSA签名和验证-内部可工作的Python示例和不可工作的C#代码示例,c#,python,rsa,bouncycastle,C#,Python,Rsa,Bouncycastle,我一直在绞尽脑汁试图得到一个简单的RSA数据签名和验证示例,该示例使用C#和BouncyCastle进行工作 RSACryptoServiceProvider.VerifyHash()在使用Python和M2Crypto的示例中始终返回false 我已经验证了工作示例和C#示例之间的散列签名是相同的,因此我被卡住了。我觉得我遗漏了一些重要的细节 接下来是工作的Python代码和非工作的C#代码 密钥是用 openssl genrsa -out testkey.pem 1024 openssl r

我一直在绞尽脑汁试图得到一个简单的RSA数据签名和验证示例,该示例使用C#和BouncyCastle进行工作

RSACryptoServiceProvider.VerifyHash()在使用Python和M2Crypto的示例中始终返回false

我已经验证了工作示例和C#示例之间的散列签名是相同的,因此我被卡住了。我觉得我遗漏了一些重要的细节

接下来是工作的Python代码和非工作的C#代码

密钥是用

openssl genrsa -out testkey.pem 1024
openssl rsa -in testkey.pem -pubout > testkey.pub
Python代码(工作):

C#代码(verifyhash()返回false):


此时,我不知道如何继续,非常感谢您的帮助。

构建私钥/公钥的方式有问题。显然,在python中,您需要这样做

我创建了使用以下代码验证(以不同格式)的新密钥:

private static void GenerateKeys(out string forPubKey, out string forPrivKey)
        {
            GenerateKeys(out forPubKey, out forPrivKey, 2048, 65537, 80);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="forPubKey"></param>
        /// <param name="forPrivKey"></param>
        /// <param name="keyStrength">1024, 2048,4096</param>
        /// <param name="exponent">Typically a fermat number 3, 5, 17, 257, 65537, 4294967297, 18446744073709551617,</param>
        /// <param name="certaninty">Should be 80 or higher depending on Key strength number (exponent)</param>
        private static void GenerateKeys(out string forPubKey, out string forPrivKey, int keyStrength, int exponent, int certaninty)
        {
            // Create key
            RsaKeyPairGenerator generator = new RsaKeyPairGenerator();

            /*
             * This value should be a Fermat number. 0x10001 (F4) is current recommended value. 3 (F1) is known to be safe also.
             * 3, 5, 17, 257, 65537, 4294967297, 18446744073709551617,
             * 
             * Practically speaking, Windows does not tolerate public exponents which do not fit in a 32-bit unsigned integer. Using e=3 or e=65537 works "everywhere". 
             */
            BigInteger exponentBigInt = new BigInteger(exponent.ToString());

            var param = new RsaKeyGenerationParameters(
                exponentBigInt, // new BigInteger("10001", 16)  publicExponent
                new SecureRandom(),  // SecureRandom.getInstance("SHA1PRNG"),//prng
                keyStrength, //strength
                certaninty);//certainty
            generator.Init(param);
            AsymmetricCipherKeyPair keyPair = generator.GenerateKeyPair();

            // Save to export format
            SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public);
            byte[] ret = info.GetEncoded();
            forPubKey = Convert.ToBase64String(ret);

            //  EncryptedPrivateKeyInfo asdf = EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
            //    DerObjectIdentifier.Ber,,,keyPair.Private);

            //// demonstration: how to serialise option 1
            //TextWriter textWriter = new StringWriter();
            //PemWriter pemWriter = new PemWriter(textWriter);
            //pemWriter.WriteObject(keyPair);
            //pemWriter.Writer.Flush();
            //string ret2 = textWriter.ToString();

            //// demonstration: how to serialise option 1
            //TextReader tr = new StringReader(ret2);
            //PemReader read = new PemReader(tr);
            //AsymmetricCipherKeyPair something = (AsymmetricCipherKeyPair)read.ReadObject();

            //// demonstration: how to serialise option 2 (don't know how to deserailize)
            //PrivateKeyInfo pKinfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);
            //byte[] privRet = pKinfo.GetEncoded();
            //string forPrivKey2Test = Convert.ToBase64String(privRet);



            PrivateKeyInfo pKinfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);
            byte[] privRet = pKinfo.GetEncoded();
            string forPrivKey2Test = Convert.ToBase64String(privRet);

            forPrivKey = forPrivKey2Test;
        }
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;


namespace RsaSignTest
{
    class Program
    {
        private const string privateKey =
            @"-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCxSHbp1ID/XHEdzVzgqYR1F/79PeMbqzuKNZChvt1gFObBhKyB
pgaHDHw3UZrO8s/hBEE/Mpe2Lh90ZAFdPIXq+HyVoznXMoJYBv0uLDApvSQbJNOd
f7T5VwmpBbkfj1NAlm39Eun9uBSokEOnB24g+bczPQPGOASrQ2Ly9afOZQIDAQAB
AoGBAIEzQIZ1OnXgVwfTLMcGg+QaUtkYizUU+9Vj6D4YrZliYjHSkS4DY2p0rOpb
7Ki5yMpCoZJ/OpWo03+tilj6zNUU6X3aHrPPSv8jcsE0sDi9zYJr/Ztk3EG23sad
bM28Bb4fV/Z0/E6FZJrmuvI2dZP/57oQSHGOhtkHFO21cW5BAkEA3l/i5Rc34YXc
WHYEsOYe0kAxS4dCmhbLWaWvsghW/TomjdxzePsO70GZZqRMdzkfA1iS1OrK+pP4
4suL2rSLrQJBAMwXFnBp4Jmek0CTSxoYf6q91eFm/IRkGLnzE1fEZ76vQOBTas8T
/mpjNQHSEywo/QB62h9A8hy7XNrfZJAMJJkCQA5TYwybKFBxDTbts3Op/4ZP+F0D
Q7klisglsmHnw6Lgoic1coLyuY2UTkucfgiYN3VBuYPZ9GWcLsZ9km7ufqkCQQCz
NVa70Qyqd+cfXfcla/u2pskHCtKTQf3AUmRavhjHBMa39CemvAy7yG9EMP4q2bcH
U9jydqnidtdbTavVHQSJAkA0zJtLzHGPtQqQaI7K6kBDXYPqloGnQxHxad0HPx2e
Vj2qv1tEsqeG6HC7aL/afXOtxcfjq4oMHbGUjDv+dGfP
-----END RSA PRIVATE KEY-----";

        private const string publicKey =
            @"-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxSHbp1ID/XHEdzVzgqYR1F/79
PeMbqzuKNZChvt1gFObBhKyBpgaHDHw3UZrO8s/hBEE/Mpe2Lh90ZAFdPIXq+HyV
oznXMoJYBv0uLDApvSQbJNOdf7T5VwmpBbkfj1NAlm39Eun9uBSokEOnB24g+bcz
PQPGOASrQ2Ly9afOZQIDAQAB
-----END PUBLIC KEY-----";

        static void Main(string[] args)
        {
            var data = "test input string";
            var sig = SignWithPrivateKey(data);
            var valid = VerifyWithPublicKey(data,sig);
        }

        private static byte[] SignWithPrivateKey(string data)
        {
            RSACryptoServiceProvider rsa;

            using (var keyreader = new StringReader(privateKey))
            {
                var pemreader = new PemReader(keyreader);
                var y = (AsymmetricCipherKeyPair) pemreader.ReadObject();
                var rsaPrivKey = (RsaPrivateCrtKeyParameters)y.Private;
                rsa = (RSACryptoServiceProvider)RSACryptoServiceProvider.Create();
                var rsaParameters = DotNetUtilities.ToRSAParameters(rsaPrivKey);
                rsa.ImportParameters(rsaParameters);

            }

            // compute sha1 hash of the data
            var sha = new SHA1CryptoServiceProvider();
            byte[] hash = sha.ComputeHash(Encoding.ASCII.GetBytes(data));

            // actually compute the signature of the SHA1 hash of the data
            var sig = rsa.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"));

            // base64 encode the signature and write to compare to the python version
            String b64signature = Convert.ToBase64String(sig);
            using (var sigwriter = new StreamWriter(@"C:\scratch\csharp_sig2.txt"))
            {
                sigwriter.Write(b64signature);
            }

            return sig;
        }

        private static bool VerifyWithPublicKey(string data,byte[] sig)
        {
            RSACryptoServiceProvider rsa;

            using (var keyreader = new StringReader(publicKey))
            {
                var pemReader = new PemReader(keyreader);
                var y = (RsaKeyParameters) pemReader.ReadObject();
                rsa = (RSACryptoServiceProvider) RSACryptoServiceProvider.Create();
                var rsaParameters = new RSAParameters();
                rsaParameters.Modulus = y.Modulus.ToByteArray();
                rsaParameters.Exponent = y.Exponent.ToByteArray();
                rsa.ImportParameters(rsaParameters);
            }

            // compute sha1 hash of the data
            var sha = new SHA1CryptoServiceProvider();
            byte[] hash = sha.ComputeHash(Encoding.ASCII.GetBytes(data));

            // This always returns false
            return rsa.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA1"),sig);
        }
    }
}
private static void GenerateKeys(out string forPubKey, out string forPrivKey)
        {
            GenerateKeys(out forPubKey, out forPrivKey, 2048, 65537, 80);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="forPubKey"></param>
        /// <param name="forPrivKey"></param>
        /// <param name="keyStrength">1024, 2048,4096</param>
        /// <param name="exponent">Typically a fermat number 3, 5, 17, 257, 65537, 4294967297, 18446744073709551617,</param>
        /// <param name="certaninty">Should be 80 or higher depending on Key strength number (exponent)</param>
        private static void GenerateKeys(out string forPubKey, out string forPrivKey, int keyStrength, int exponent, int certaninty)
        {
            // Create key
            RsaKeyPairGenerator generator = new RsaKeyPairGenerator();

            /*
             * This value should be a Fermat number. 0x10001 (F4) is current recommended value. 3 (F1) is known to be safe also.
             * 3, 5, 17, 257, 65537, 4294967297, 18446744073709551617,
             * 
             * Practically speaking, Windows does not tolerate public exponents which do not fit in a 32-bit unsigned integer. Using e=3 or e=65537 works "everywhere". 
             */
            BigInteger exponentBigInt = new BigInteger(exponent.ToString());

            var param = new RsaKeyGenerationParameters(
                exponentBigInt, // new BigInteger("10001", 16)  publicExponent
                new SecureRandom(),  // SecureRandom.getInstance("SHA1PRNG"),//prng
                keyStrength, //strength
                certaninty);//certainty
            generator.Init(param);
            AsymmetricCipherKeyPair keyPair = generator.GenerateKeyPair();

            // Save to export format
            SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public);
            byte[] ret = info.GetEncoded();
            forPubKey = Convert.ToBase64String(ret);

            //  EncryptedPrivateKeyInfo asdf = EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
            //    DerObjectIdentifier.Ber,,,keyPair.Private);

            //// demonstration: how to serialise option 1
            //TextWriter textWriter = new StringWriter();
            //PemWriter pemWriter = new PemWriter(textWriter);
            //pemWriter.WriteObject(keyPair);
            //pemWriter.Writer.Flush();
            //string ret2 = textWriter.ToString();

            //// demonstration: how to serialise option 1
            //TextReader tr = new StringReader(ret2);
            //PemReader read = new PemReader(tr);
            //AsymmetricCipherKeyPair something = (AsymmetricCipherKeyPair)read.ReadObject();

            //// demonstration: how to serialise option 2 (don't know how to deserailize)
            //PrivateKeyInfo pKinfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);
            //byte[] privRet = pKinfo.GetEncoded();
            //string forPrivKey2Test = Convert.ToBase64String(privRet);



            PrivateKeyInfo pKinfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);
            byte[] privRet = pKinfo.GetEncoded();
            string forPrivKey2Test = Convert.ToBase64String(privRet);

            forPrivKey = forPrivKey2Test;
        }
  // Private key
  RsaPrivateCrtKeyParameters kparam = ConvertToRSAPrivateKey(privateKey); 
        RSAParameters p1 = DotNetUtilities.ToRSAParameters(kparam);
        rsa = new RSACryptoServiceProvider();
        rsa.ImportParameters(p1);

 // Public key
 RsaKeyParameters kparam = ConvertToRSAPublicKey(publicKey);
        RSAParameters p1 = DotNetUtilities.ToRSAParameters(kparam);
        rsa = new RSACryptoServiceProvider();
        rsa.ImportParameters(p1);