c# - 解密包含私钥的受密码保护的 PEM

标签 c# encryption bouncycastle private-key pem

我有以下使用 Bouncy CaSTLe for C# 创建加密私钥的方法:

public string GetPrivateKey(AsymmetricCipherKeyPair keyPair, string password)
{
    var generator = new Pkcs8Generator(keyPair.Private, Pkcs8Generator.PbeSha1_3DES);
    generator.IterationCount = 4;
    generator.Password = password.ToCharArray();
    var pem = generator.Generate();

    TextWriter textWriter = new StringWriter();
    PemWriter pemWriter = new PemWriter(textWriter);
    pemWriter.WriteObject(pem);
    pemWriter.Writer.Flush();
    string privateKey = textWriter.ToString();
    return privateKey;
}

看起来像这样:

-----BEGIN ENCRYPTED PRIVATE KEY-----
...
-----END ENCRYPTED PRIVATE KEY-----

我不知道的是如何在我的 Decrypt 方法中使用用于加密私钥的密码。现在,在不知道如何使用他的密码“解密”我的私钥的情况下,我得到以下异常:

Org.BouncyCastle.OpenSsl.PemException : problem creating ENCRYPTED private key: System.NullReferenceException: Object reference not set to an instance of an object. at Org.BouncyCastle.OpenSsl.PemReader.ReadPrivateKey(PemObject pemObject)

解密方法的代码如下:

public string Decrypt(string base64Input, string privateKey, string password)
{
    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))
    {
        var obj = new PemReader(txtreader).ReadObject();
        keyPair = (AsymmetricCipherKeyPair) obj;

        decryptEngine.Init(false, keyPair.Private);
    }

    var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length));
    return decrypted;
}

最佳答案

在我看来,您需要解密私钥才能使用它。当前未使用您的密码参数。不幸的是,要找出如何做到这一点似乎并不那么容易。


与许多其他 Java API 一样,Bouncy CaSTLe 使用密码处理程序来检索密码。这样做的原因是允许程序仅在需要时才询问用户密码。这允许程序在内存中保留密码的时间最短。

因此要允许解密,请使用以下构造函数:

PemReader(TextReader reader, IPasswordFinder pFinder);

带有 IPasswordFinder 的实现(用于 C# 的 Bouncy CaSTLe 主要是 Java 端口,否则可能会使用委托(delegate))。


为方便起见,代码。此代码还重建了整个 key 对,而不仅仅是私钥。

导入语句:

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using System.IO;

解码器:

private static AsymmetricCipherKeyPair DecodePrivateKey(string encryptedPrivateKey, string password)
{
    TextReader textReader = new StringReader(encryptedPrivateKey);
    PemReader pemReader = new PemReader(textReader, new PasswordFinder(password));
    object privateKeyObject = pemReader.ReadObject();
    RsaPrivateCrtKeyParameters rsaPrivatekey = (RsaPrivateCrtKeyParameters)privateKeyObject;
    RsaKeyParameters rsaPublicKey = new RsaKeyParameters(false, rsaPrivatekey.Modulus, rsaPrivatekey.PublicExponent);
    AsymmetricCipherKeyPair kp = new AsymmetricCipherKeyPair(rsaPublicKey, rsaPrivatekey);
    return kp;
}

需要的辅助类:

private class PasswordFinder : IPasswordFinder
{
    private string password;

    public PasswordFinder(string password)
    {
        this.password = password;
    }


    public char[] GetPassword()
    {
        return password.ToCharArray();
    }
}

请注意,通常您应该只使用 char[] 而不是 string 作为密码,因为 char[] 可以在使用后清除,而string 不能。

现在有了私钥解密应该很容易了。

关于c# - 解密包含私钥的受密码保护的 PEM,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44767290/

相关文章:

java - 仅当 *bcprov*.jar 打包到生成的 JAR 中时,BouncyCaSTLe SecurityException 才会抛出

cryptography - 使用 BouncyCaSTLe 库的 Argon2 示例

c# - 在主线程中设置线程本地值并在另一个线程中获取

c# - fluent nhibernate - 具有属性的多对多映射

ios - 加解密iOS/Node.js安全问询

encryption - 用于加密 Realm 数据库的 native 应用程序的 key 生成/存储

java - 如何将证书信息与已签名的数据关联?

c# - 如何使用Oracle和.Net客户端实现密码更改功能?

c# - 默认情况下是否可以让 Visual Studio 折叠摘要部分

c# - 使用 bouncycaSTLe 在 C# 中使用 cryptodome 解密在 python 中加密的 RSA 数据给出错误 block 不正确