简体   繁体   English

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

[英]Encrypt data with X509 certificate's private key in UWP

I'm displaying to the user every available certificates in his personal store, fetched with the following method : 我正在向用户显示其个人商店中的所有可用证书,并通过以下方法获取:

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

When the user select one of those certificates, a sample file is loaded and given to the following method : 当用户选择这些证书之一时,将加载示例文件并提供给以下方法:

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

This method is supposed to encrypt the data with the RSA private key using the SHA256 algorithm, but it keeps falling into the catch statement. 该方法应该使用SHA256算法使用RSA私钥对数据进行加密,但是它一直属于catch语句。

The error that I get depends on the certificate that I use : 我得到的错误取决于我使用的证书:

  • When I use a certificate registered in the user's personal store : 当我使用在用户的个人商店中注册的证书时:

Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Internal.Cryptography.CryptoThrowHelper + WindowsCryptographicException:

Invalid parameter 无效的参数

at System.Security.Cryptography.RSACng.EncryptOrDecrypt(SafeNCryptKeyHandle key, Byte[] input, AsymmetricPaddingMode paddingMode, Void* paddingInfo, EncryptOrDecryptAction encryptOrDecrypt) 在System.Security.Cryptography.RSACng.EncryptOrDecrypt(SafeNCryptKeyHandle密钥,Byte []输入,AsymmetricPaddingMode paddingMode,Void * paddingInfo,EncryptOrDecryptAction cryptoOrDecrypt)

at System.Security.Cryptography.RSACng.EncryptOrDecrypt(Byte[] data, RSAEncryptionPadding padding, EncryptOrDecryptAction encryptOrDecrypt) 在System.Security.Cryptography.RSACng.EncryptOrDecrypt(Byte []数据,RSAEncryptionPadding填充,EncryptOrDecryptAction加密或解密)

at System.Security.Cryptography.RSACng.Encrypt(Byte[] data, RSAEncryptionPadding padding) 在System.Security.Cryptography.RSACng.Encrypt(Byte [] data,RSAEncryptionPadding padding)

at My method 我的方式

  • When I use a certificate from a USB key : 当我使用USB密钥中的证书时:

Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: 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) 在Security.Cryptography.RSACng.EncryptOrDecrypt(SafeNCryptKeyHandle密钥,Byte []输入,AsymmetricPaddingMode paddingMode,Void * paddingInfo,EncryptOrDecryptAction cryptoOrDecrypt)

at System.Security.Cryptography.RSACng.EncryptOrDecrypt(Byte[] data, RSAEncryptionPadding padding, EncryptOrDecryptAction encryptOrDecrypt) 在System.Security.Cryptography.RSACng.EncryptOrDecrypt(Byte []数据,RSAEncryptionPadding填充,EncryptOrDecryptAction加密或解密)

at System.Security.Cryptography.RSACng.Encrypt(Byte[] data, RSAEncryptionPadding padding) 在System.Security.Cryptography.RSACng.Encrypt(Byte [] data,RSAEncryptionPadding padding)

at My method 我的方式

I've also tried the private key's SignData method, resulting in the same exceptions : 我还尝试了私钥的SignData方法,导致了相同的异常:

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

Am I missing something ? 我想念什么吗?

Please note that, as I'm working in an UWP application, I can only access some of the System.Security namespace . 请注意,当我在UWP应用程序中工作时,我只能访问一些System.Security名称空间

I found a solution to my issues, it was due to these two mistakes : 我找到了解决问题的方法,这是由于以下两个错误:

First, the encryption method to use here isn't Encrypt but SignData , since I want to electronically sign the data. 首先,这里使用的加密方法不是Encrypt而是SignData ,因为我想对数据进行电子签名。

Second, in order to make a valid signature, the certificate needs to contain the Non-Repudation extension. 其次,为了进行有效签名,证书需要包含“ 不可否认”扩展名。 To check that, I've added this method : 为了确认这一点,我添加了以下方法:

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

I now fetch the certificates using the following : 我现在使用以下方法获取证书:

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

One thing that I still don't understand is why the SignData method doesn't throw any exception and did sign the data when the certificate is fetched from a pfx file and not from the store. 我仍然不明白的一件事是,当从pfx文件而不是从存储中获取证书时,为什么SignData方法不会引发任何异常并对数据进行签名。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM