我的计算机上有一个.pfx证书文件。我想用其公钥加密消息,然后用私有解密。
此外,我想用其私钥签署另一条消息,然后检查签名。我需要从该消息中获取有关该消息已签署的证书的信息。
我怎样才能使用System.Security.Cryptography?
答案 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);