使用UWP中的X509证书私钥加密数据

时间:2017-06-15 14:30:21

标签: c# encryption uwp x509certificate2

我正在向用户显示他个人商店中的每个可用证书,使用以下方法获取:

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;
}

当用户选择其中一个证书时,会加载一个示例文件并将其提供给以下方法:

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:

     

参数无效

     

在System.Security.Cryptography.RSACng.EncryptOrDecrypt(SafeNCryptKeyHandle)   key,Byte [] input,AsymmetricPaddingMode paddingMode,Void *   paddingInfo,EncryptOrDecryptAction encryptOrDecrypt)

     

在System.Security.Cryptography.RSACng.EncryptOrDecrypt(Byte []数据中,   RSAEncryptionPadding padding,EncryptOrDecryptAction encryptOrDecrypt)

     

在System.Security.Cryptography.RSACng.Encrypt(Byte []数据中,   RSAEncryptionPadding padding)

     

我的方法

  • 当我使用USB密钥证书时:
  

Internal.Cryptography.CryptoThrowHelper + WindowsCryptographicException:

     

不支持请求的操作

     

at Security.Cryptography.RSACng.EncryptOrDecrypt(SafeNCryptKeyHandle)   key,Byte [] input,AsymmetricPaddingMode paddingMode,Void *   paddingInfo,EncryptOrDecryptAction encryptOrDecrypt)

     

在System.Security.Cryptography.RSACng.EncryptOrDecrypt(Byte []数据,RSAEncryptionPadding padding,EncryptOrDecryptAction   encryptOrDecrypt)

     

在System.Security.Cryptography.RSACng.Encrypt(Byte []数据,RSAEncryptionPadding padding)

     

我的方法

我也尝试过私钥的 SignData 方法,导致相同的例外情况:

encryptedFile = privateKey.SignData(hashToSign, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

我错过了什么吗?

请注意,由于我正在使用UWP应用程序,因此我只能访问some of the System.Security namespace

1 个答案:

答案 0 :(得分:0)

我找到了解决问题的方法,原因是这两个错误:

首先,此处使用的加密方法不是加密,而是 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获取证书时对数据进行了签名文件,而非商店。