如何使用.pfx证书加密,解密和签名?

时间:2016-06-18 08:24:43

标签: c# encryption x509certificate x509certificate2 pfx

我的计算机上有一个.pfx证书文件。我想用其公钥加密消息,然后用私有解密。

此外,我想用其私钥签署另一条消息,然后检查签名。我需要从该消息中获取有关该消息已签署的证书的信息。

我怎样才能使用System.Security.Cryptography?

2 个答案:

答案 0 :(得分:8)

您可以在.NET中打开PFX,如下所示:

var path = <YOUR PFX FILE PATH>;
var password = <YOUR PASSWORD>;

var collection = new X509Certificate2Collection();

collection.Import(path, password, X509KeyStorageFlags.PersistKeySet);

然后,枚举X509Certificate2Collection。获得证书后(假设有一个证书),然后:

var certificate = collection[0];

要加密数据,您可以使用:

var publicKey = certificate.PublicKey.Key as RSACryptoServiceProvider;

var encryptedData = publicKey.Encrypt(<yourdata>, false);

此处,我没有使用OAEP进行加密,但您可以通过将fOAEP设置为true作为第二个参数来使用它。

要解密数据,您可以使用:

var privateKey = certificate.PrivateKey as RSACryptoServiceProvider;

var data = privateKey.Decrypt(encryptedData, false);

PFX中的证书可能没有相应的私钥,因此您可以在访问PrivateKey属性之前使用以下属性检查私钥是否存在

if (!certificate.HasPrivateKey)
    throw new Exception("The certificate does not have a private key");

如果您使用OAEP进行了加密,则必须将fOAEP设置为true进行解密。

要签署数据,您可以使用:

var signature = privateKey.SignData(<yourdata>, "SHA1");

要验证签名,您可以使用:

var isValid = publicKey.VerifyData(<yourdata>, "SHA1", signature);

在这里,我使用了SHA1,这被认为不是很强大。您可以使用其他更强大的散列算法,如SHA256

最后,如果您的消息是一个小字符串,那么之前的过程就可以了。但是,如果您要加密大数据,那么我建议您使用对称加密,然后使用公钥加密对称密钥。 (有关完整示例,请参阅X509Certificate2 Class。)

答案 1 :(得分:0)

从.NET 4.6开始,对* CryptoServiceProvider类型的依赖性已经降低:

private static byte[] SignArbitrarily(byte[] data, X509Certificate2 cert)
{
    Debug.Assert(data != null);
    Debug.Assert(cert != null);
    Debug.Assert(cert.HasPrivateKey);

    // .NET 4.6(.0):
    using (RSA rsa = cert.GetRSAPrivateKey())
    {
        if (rsa != null)
        {
            // You need to explicitly pick a hash/digest algorithm and padding for RSA,
            // these are just some example choices.
            return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
        }
    }

    // .NET 4.6.1:
    using (ECDsa ecdsa = cert.GetECDsaPrivateKey())
    {
        if (ecdsa != null)
        {
            // ECDSA signatures need to explicitly choose a hash algorithm, but there
            // are no padding choices (unlike RSA).
            return ecdsa.SignData(data, HashAlgorithmName.SHA256);
        }
    }

    // .NET 4.6.2 (currently in preview):
    using (DSA dsa = cert.GetDSAPrivateKey())
    {
        if (dsa != null)
        {
            // FIPS 186-1 (legacy) DSA does not have an option for the hash algorithm,
            //   SHA-1 was the only option.
            // FIPS 186-3 (current) DSA allows any of SHA-1, SHA-2-224, SHA-2-256,
            //   SHA-2-384, and SHA-2-512 (.NET does not support SHA-2-224).
            //   KeySize < 1024 is FIPS-186-1 mode, > 1024 is 186-3, and == 1024 can
            //   be either (depending on the hardware/software provider).
            // So, SHA-1 is being used in this example as the "most flexible",
            //   but may not currently be considered "secure".
            return dsa.SignData(data, HashAlgorithmName.SHA1);
        }
    }

    throw new InvalidOperationException("No algorithm handler");
}

// Uses the same choices as SignArbitrarily.
private static bool VerifyArbitrarily(byte[] data, byte[] signature, X509Certificate2 cert)
{
    Debug.Assert(data != null);
    Debug.Assert(signature != null);
    Debug.Assert(cert != null);

    using (RSA rsa = cert.GetRSAPublicKey())
    {
        if (rsa != null)
        {
            return rsa.VerifyData(data, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
        }
    }

    using (ECDsa ecdsa = cert.GetECDsaPublicKey())
    {
        if (ecdsa != null)
        {
            return ecdsa.VerifyData(data, signature, HashAlgorithmName.SHA256);
        }
    }

    using (DSA dsa = cert.GetDSAPublicKey())
    {
        if (dsa != null)
        {
            return dsa.VerifyData(data, signature, HashAlgorithmName.SHA1);
        }
    }

    throw new InvalidOperationException("No algorithm handler");
}

对于非对称加密/解密,RSA是唯一的算法,并且需要填充模式。新RSAEncryptionPadding.OaepSHA1与RSACryptoServiceProvider中的fOAEP: true相同。 .NET支持较新的OAEP,但并非所有底层提供者都支持。

rsaPublic.Encrypt(data, RSAEncryptionPadding.OaepSHA1);
rsaPrivate.Decrypt(encryptedData, RSAEncryptionPadding.OaepSHA1);