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


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

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

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

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 方法。

编辑:

我还添加了一个单元测试,证明公钥等于从私钥中提取的公钥:

    [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;

    } 

15
2018-01-22 10:21


起源


我使用了一个不正确的公钥..并且证明私钥和公钥匹配的测试是使用正确的公钥。只要你把钥匙弄好,a \ bove代码就可以完美地工作! - scudsucker


答案:


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

13
2018-05-20 12:55



谢谢!我感谢您的帮助 - Hugo Medina
你有没有错误'GetInstance中的非法对象:Org.BouncyCastle.Asn1.DerSequence'这段代码?我正在尝试测试BouncyCastle以查看它是如何工作的,当我运行上面的代码时,我收到此错误消息。 - Ruslan
@Ruslan我认为这可能是由版本更改引起的。您可以尝试接近我的发布时间的版本并追溯以查看API更改的内容。 - Morio


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

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


2
2018-01-28 09:56