C#BouncyCastle – 使用公钥/私钥进行RSA加密

我需要在C#中加密数据,以便将其传递给Java。 Java代码属于第三方但我得到了相关的源代码,因此我决定,当Java使用Bouncy Castle库时,我将使用C#端口。

解密工作正常。 但是,只有当我使用私钥加密而不使用公钥时,解密才有效。 使用公钥时,解密会因unknown block type失败。

显然, RsaEncryptWithPrivate的加密在加密时使用公钥,所以我不明白为什么这两种加密方法在function上不相同:

 using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Encodings; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.OpenSsl; public class EncryptionClass { public string RsaEncryptWithPublic(string clearText , string publicKey) { var bytesToEncrypt = Encoding.UTF8.GetBytes(clearText); var encryptEngine = new Pkcs1Encoding(new RsaEngine()); using (var txtreader = new StringReader(publicKey)) { var keyParameter = (AsymmetricKeyParameter)new PemReader(txtreader).ReadObject(); encryptEngine.Init(true, keyParameter); } var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(bytesToEncrypt, 0, bytesToEncrypt.Length)); return encrypted; } public string RsaEncryptWithPrivate(string clearText , string privateKey) { var bytesToEncrypt = Encoding.UTF8.GetBytes(clearText); var encryptEngine = new Pkcs1Encoding(new RsaEngine()); using (var txtreader = new StringReader(privateKey)) { var keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject(); encryptEngine.Init(true, keyPair.Public); } var encrypted= Convert.ToBase64String(encryptEngine.ProcessBlock(bytesToEncrypt, 0, bytesToEncrypt.Length)); return encrypted; } // Decryption: public string RsaDecrypt(string base64Input , string privateKey) { var bytesToDecrypt = Convert.FromBase64String(base64Input); //get a stream from the string AsymmetricCipherKeyPair keyPair; var decryptEngine = new Pkcs1Encoding(new RsaEngine()); using ( var txtreader = new StringReader(privateKey) ) { keyPair = (AsymmetricCipherKeyPair) new PemReader(txtreader).ReadObject(); decryptEngine.Init(false, keyPair.Private); } var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length)); return decrypted; } } // In my test project [Test()] public void EncryptTest() { // Set up var input = "Perceived determine departure explained no forfeited"; var enc = new EncryptionClass(); var publicKey = "-----BEGIN PUBLIC KEY----- // SNIPPED // -----END PUBLIC KEY-----"; var privateKey = "-----BEGIN PRIVATE KEY----- // SNIPPED // -----END PRIVATE KEY-----"; // Encrypt it var encryptedWithPublic = enc.RsaEncryptWithPublic(input, publicKey); var encryptedWithPrivate = enc.RsaEncryptWithPrivate(input, privateKey); // Decrypt var outputWithPublic = payUEnc.RsaDecrypt(encryptedWithPrivate, privateKey); // Throws error: "unknown block type" var outputWithPrivate = payUEnc.RsaDecrypt(encryptedWithPrivate, _privateKey); // returns the correct decrypted text, "Perceived determine departure explained no forfeited" // Assertion Assert.AreEqual(outputWithPrivate, input); // This is true } 

顺便提一下,Java解密表现出同样的问题 – 当仅使用公钥加密时,它会失败。

我对密码学很RsaEncryptWithPublic ,所以我确信我在RsaEncryptWithPublic方法中做了一些非常简单的错误。

编辑:

我还添加了一个unit testing,certificate公钥等于从私钥中提取的公钥:

  [Test()] public void EncryptCompareTest() { AsymmetricKeyParameter keyParameterFromPub; AsymmetricKeyParameter keyParameterFromPriv; AsymmetricCipherKeyPair keyPair; using (var txtreader = new StringReader(_publicKey)) { keyParameterFromPub = (AsymmetricKeyParameter)new PemReader(txtreader).ReadObject(); } using (var txtreader = new StringReader(_privateKey)) { keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject(); keyParameterFromPriv = keyPair.Public; } Assert.AreEqual(keyParameterFromPub, keyParameterFromPriv); // returns true; } 

OP的代码中存在一些错误。 我做了一些改变。 这是我运行的。

 public class TFRSAEncryption { public string RsaEncryptWithPublic(string clearText, string publicKey) { var bytesToEncrypt = Encoding.UTF8.GetBytes(clearText); var encryptEngine = new Pkcs1Encoding(new RsaEngine()); using (var txtreader = new StringReader(publicKey)) { var keyParameter = (AsymmetricKeyParameter)new PemReader(txtreader).ReadObject(); encryptEngine.Init(true, keyParameter); } var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(bytesToEncrypt, 0, bytesToEncrypt.Length)); return encrypted; } public string RsaEncryptWithPrivate(string clearText, string privateKey) { var bytesToEncrypt = Encoding.UTF8.GetBytes(clearText); var encryptEngine = new Pkcs1Encoding(new RsaEngine()); using (var txtreader = new StringReader(privateKey)) { var keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject(); encryptEngine.Init(true, keyPair.Private); } var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(bytesToEncrypt, 0, bytesToEncrypt.Length)); return encrypted; } // Decryption: public string RsaDecryptWithPrivate(string base64Input, string privateKey) { var bytesToDecrypt = Convert.FromBase64String(base64Input); AsymmetricCipherKeyPair keyPair; var decryptEngine = new Pkcs1Encoding(new RsaEngine()); using (var txtreader = new StringReader(privateKey)) { keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject(); decryptEngine.Init(false, keyPair.Private); } var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length)); return decrypted; } public string RsaDecryptWithPublic(string base64Input, string publicKey) { var bytesToDecrypt = Convert.FromBase64String(base64Input); var decryptEngine = new Pkcs1Encoding(new RsaEngine()); using (var txtreader = new StringReader(publicKey)) { var keyParameter = (AsymmetricKeyParameter)new PemReader(txtreader).ReadObject(); decryptEngine.Init(false, keyParameter); } var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length)); return decrypted; } } class Program { static void Main(string[] args) { // Set up var input = "Perceived determine departure explained no forfeited"; var enc = new TFRSAEncryption(); var publicKey = "-----BEGIN PUBLIC KEY----- // Base64 string omitted // -----END PUBLIC KEY-----"; var privateKey = "-----BEGIN PRIVATE KEY----- // Base64 string omitted// -----END PRIVATE KEY-----"; // Encrypt it var encryptedWithPublic = enc.RsaEncryptWithPublic(input, publicKey); var encryptedWithPrivate = enc.RsaEncryptWithPrivate(input, privateKey); // Decrypt var output1 = enc.RsaDecryptWithPrivate(encryptedWithPublic, privateKey); var output2 = enc.RsaDecryptWithPublic(encryptedWithPrivate, publicKey); Console.WriteLine(output1 == output2 && output2 == input); Console.Read(); } } 

我使用了一个不正确的公钥..并且certificate私钥和公钥匹配的测试是使用正确的公钥。

上面的代码完美无缺,只要你正确的键!

我尝试了@Mario解决方案但是遇到了一些exception。 第一个是

-----END PUBLIC KEY not found

我可以通过正确格式化两个键来解决这个问题

 publicKey = $"-----BEGIN PUBLIC KEY-----\n{publicKey}\n-----END PUBLIC KEY-----\n"; 

第二个错误是在尝试解密文本时。 Unable to cast object of type 'Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters' to type 'Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair'.
我通过强制转换为适当的类型来解决。

 var keyPair = (RsaPrivateCrtKeyParameters)new PemReader(txtreader).ReadObject();