使用C#,BouncyCastle和导入的RSA密钥进行RSA签名和validation – 内部使用Python示例和非工作C#代码示例

我一直在试着用C#和BouncyCastle工作来解决RSA数据签名和validation的一个小例子。

RSACryptoServiceProvider.VerifyHash()总是在一个适用于Python和M2Crypto的示例中返回false。

我已经validation了工作示例和C#示例之间的哈希签名是相同的,它就在那里我被卡住了。 我觉得我错过了一些重要的细节。

工作的Python代码和非工作的C#代码如下。

关键是生成的

openssl genrsa -out testkey.pem 1024 openssl rsa -in testkey.pem -pubout > testkey.pub 

Python代码(工作):

  private = """-----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-----""" public = """-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxSHbp1ID/XHEdzVzgqYR1F/79 PeMbqzuKNZChvt1gFObBhKyBpgaHDHw3UZrO8s/hBEE/Mpe2Lh90ZAFdPIXq+HyV oznXMoJYBv0uLDApvSQbJNOdf7T5VwmpBbkfj1NAlm39Eun9uBSokEOnB24g+bcz PQPGOASrQ2Ly9afOZQIDAQAB -----END PUBLIC KEY-----""" message = "test input string" import base64 # Use EVP api to sign message from M2Crypto import EVP key = EVP.load_key_string(private) key.reset_context(md='sha1') key.sign_init() key.sign_update(message) signature = key.sign_final() encoded = base64.b64encode(signature) print encoded with open("python_sig2.txt","w") as f: f.write(encoded) # Use EVP api to verify signature from M2Crypto import BIO, RSA, EVP bio = BIO.MemoryBuffer(public) rsa = RSA.load_pub_key_bio(bio) pubkey = EVP.PKey() pubkey.assign_rsa(rsa) pubkey.reset_context(md="sha1") pubkey.verify_init() pubkey.verify_update(message) decoded = base64.b64decode(encoded) print pubkey.verify_final(decoded) == 1 

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

 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); } } } 

在这一点上,我不知道如何继续,任何帮助将不胜感激。

你如何重新构建私钥/公钥是有问题的。 显然在python中你需要注意这一点。

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

 private static void GenerateKeys(out string forPubKey, out string forPrivKey) { GenerateKeys(out forPubKey, out forPrivKey, 2048, 65537, 80); } ///  /// ///  ///  ///  /// 1024, 2048,4096 /// Typically a fermat number 3, 5, 17, 257, 65537, 4294967297, 18446744073709551617, /// Should be 80 or higher depending on Key strength number (exponent) 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; } 

然后将它们转回RSA对象,如下所示:

  // 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);