在 UWP 中使用 X509 证书的私钥加密数据
Encrypt data with X509 certificate's private key in UWP
我正在向用户显示其个人商店中的所有可用证书,这些证书是通过以下方法获取的:
public List<X509Certificate2> GetPersonalCertificates()
{
var certificates = new List<X509Certificate2>();
using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
store.Open(OpenFlags.MaxAllowed);
foreach (var certificate in store.Certificates)
{
if (certificate != null && certificate.HasPrivateKey)
{
certificates.Add(certificate);
}
}
}
return certificates;
}
当用户 select 其中一个证书时,将加载示例文件并提供给以下方法:
public byte[] EncryptFile(X509Certificate2 certificate, byte[] fileToEncrypt)
{
if (certificate == null || hashToSign == null) return null;
byte[] encryptedFile = null;
try
{
using (var privateKey = certificate.GetRSAPrivateKey())
{
encryptedFile = privateKey.Encrypt(hashToSign, System.Security.Cryptography.RSAEncryptionPadding.OaepSHA256);
}
}
catch (Exception e)
{
// Error management
}
return encryptedFile;
}
该方法本应使用SHA256算法用RSA私钥加密数据,却老是落入catch语句
我得到的错误取决于我使用的证书:
- 当我使用在用户个人存储中注册的证书时:
Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException:
Invalid parameter
at System.Security.Cryptography.RSACng.EncryptOrDecrypt(SafeNCryptKeyHandle
key, Byte[] input, AsymmetricPaddingMode paddingMode, Void*
paddingInfo, EncryptOrDecryptAction encryptOrDecrypt)
at System.Security.Cryptography.RSACng.EncryptOrDecrypt(Byte[] data,
RSAEncryptionPadding padding, EncryptOrDecryptAction encryptOrDecrypt)
at System.Security.Cryptography.RSACng.Encrypt(Byte[] data,
RSAEncryptionPadding padding)
at My method
- 当我使用来自 USB 密钥的证书时:
Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException:
The requested operation is not supported
at Security.Cryptography.RSACng.EncryptOrDecrypt(SafeNCryptKeyHandle
key, Byte[] input, AsymmetricPaddingMode paddingMode, Void*
paddingInfo, EncryptOrDecryptAction encryptOrDecrypt)
at System.Security.Cryptography.RSACng.EncryptOrDecrypt(Byte[] data, RSAEncryptionPadding padding, EncryptOrDecryptAction
encryptOrDecrypt)
at System.Security.Cryptography.RSACng.Encrypt(Byte[] data, RSAEncryptionPadding padding)
at My method
我也尝试了私钥的 SignData 方法,导致相同的异常:
encryptedFile = privateKey.SignData(hashToSign, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
我是不是漏掉了什么?
请注意,由于我在 UWP 应用程序中工作,因此我只能访问 some of the System.Security namespace。
我找到了解决问题的方法,这是由于这两个错误造成的:
首先,这里使用的加密方法不是 Encrypt,而是 SignData,因为我想对数据进行电子签名。
其次,为了进行有效签名,证书需要包含 Non-Repudation 扩展。为了检查这一点,我添加了这个方法:
private bool _canUsingCertificateForSignData(X509ExtensionCollection extensions)
{
if (extensions != null)
{
foreach (var ext in extensions)
{
if (ext.GetType().Equals(typeof(X509KeyUsageExtension)))
{
if (((X509KeyUsageExtension)ext).KeyUsages.HasFlag(X509KeyUsageFlags.NonRepudiation))
{
return true;
}
}
}
}
return false;
}
我现在使用以下方法获取证书:
public List<X509Certificate2> GetPersonalCertificates()
{
var certificates = new List<X509Certificate2>();
using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
store.Open(OpenFlags.MaxAllowed);
foreach (var certificate in store.Certificates)
{
if (certificate != null && certificate.HasPrivateKey && _canUsingCertificateForSignData(certificate.Extensions))
{
certificates.Add(certificate);
}
}
}
return certificates;
}
我仍然不明白的一件事是为什么 SignData 方法没有抛出任何异常并且在从 pfx 文件而不是来自商店。
我正在向用户显示其个人商店中的所有可用证书,这些证书是通过以下方法获取的:
public List<X509Certificate2> GetPersonalCertificates()
{
var certificates = new List<X509Certificate2>();
using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
store.Open(OpenFlags.MaxAllowed);
foreach (var certificate in store.Certificates)
{
if (certificate != null && certificate.HasPrivateKey)
{
certificates.Add(certificate);
}
}
}
return certificates;
}
当用户 select 其中一个证书时,将加载示例文件并提供给以下方法:
public byte[] EncryptFile(X509Certificate2 certificate, byte[] fileToEncrypt)
{
if (certificate == null || hashToSign == null) return null;
byte[] encryptedFile = null;
try
{
using (var privateKey = certificate.GetRSAPrivateKey())
{
encryptedFile = privateKey.Encrypt(hashToSign, System.Security.Cryptography.RSAEncryptionPadding.OaepSHA256);
}
}
catch (Exception e)
{
// Error management
}
return encryptedFile;
}
该方法本应使用SHA256算法用RSA私钥加密数据,却老是落入catch语句
我得到的错误取决于我使用的证书:
- 当我使用在用户个人存储中注册的证书时:
Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException:
Invalid parameter
at System.Security.Cryptography.RSACng.EncryptOrDecrypt(SafeNCryptKeyHandle key, Byte[] input, AsymmetricPaddingMode paddingMode, Void* paddingInfo, EncryptOrDecryptAction encryptOrDecrypt)
at System.Security.Cryptography.RSACng.EncryptOrDecrypt(Byte[] data, RSAEncryptionPadding padding, EncryptOrDecryptAction encryptOrDecrypt)
at System.Security.Cryptography.RSACng.Encrypt(Byte[] data, RSAEncryptionPadding padding)
at My method
- 当我使用来自 USB 密钥的证书时:
Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException:
The requested operation is not supported
at Security.Cryptography.RSACng.EncryptOrDecrypt(SafeNCryptKeyHandle key, Byte[] input, AsymmetricPaddingMode paddingMode, Void* paddingInfo, EncryptOrDecryptAction encryptOrDecrypt)
at System.Security.Cryptography.RSACng.EncryptOrDecrypt(Byte[] data, RSAEncryptionPadding padding, EncryptOrDecryptAction encryptOrDecrypt)
at System.Security.Cryptography.RSACng.Encrypt(Byte[] data, RSAEncryptionPadding padding)
at My method
我也尝试了私钥的 SignData 方法,导致相同的异常:
encryptedFile = privateKey.SignData(hashToSign, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
我是不是漏掉了什么?
请注意,由于我在 UWP 应用程序中工作,因此我只能访问 some of the System.Security namespace。
我找到了解决问题的方法,这是由于这两个错误造成的:
首先,这里使用的加密方法不是 Encrypt,而是 SignData,因为我想对数据进行电子签名。
其次,为了进行有效签名,证书需要包含 Non-Repudation 扩展。为了检查这一点,我添加了这个方法:
private bool _canUsingCertificateForSignData(X509ExtensionCollection extensions)
{
if (extensions != null)
{
foreach (var ext in extensions)
{
if (ext.GetType().Equals(typeof(X509KeyUsageExtension)))
{
if (((X509KeyUsageExtension)ext).KeyUsages.HasFlag(X509KeyUsageFlags.NonRepudiation))
{
return true;
}
}
}
}
return false;
}
我现在使用以下方法获取证书:
public List<X509Certificate2> GetPersonalCertificates()
{
var certificates = new List<X509Certificate2>();
using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
store.Open(OpenFlags.MaxAllowed);
foreach (var certificate in store.Certificates)
{
if (certificate != null && certificate.HasPrivateKey && _canUsingCertificateForSignData(certificate.Extensions))
{
certificates.Add(certificate);
}
}
}
return certificates;
}
我仍然不明白的一件事是为什么 SignData 方法没有抛出任何异常并且在从 pfx 文件而不是来自商店。