在 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

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 文件而不是来自商店。