使用RSACryptoServiceProvider从XML导入RSA公钥会将属性PublicOnly设置为false

本文关键字:属性 PublicOnly 设置 false 公钥 RSACryptoServiceProvider XML 导入 RSA 使用 | 更新日期: 2023-09-27 18:36:08

我正在创建一个工具来管理Windows上的RSA密钥对,因为没有内置的功能,而且我们广泛使用了.NET.中的RSA加密功能

该工具提供了各种功能,如列出现有RSA密钥对、创建新密钥、删除密钥、导出密钥以及从以前创建的XML导出(使用ASPNet_RegIIS.exe导出(导入密钥

除了只导入用于加密操作的公钥之外,我还有所有的功能。当最初在服务器上创建密钥对时,将使用aspnet_regiis.exe对xml进行公共和公共/私有导出。

我热衷于提供在其他机器上加密配置文件的选项,以防止私钥被分发,除非绝对必要。

每次从以前导出的XML块导入公钥时,RSACryptoServiceProviderPublicOnly属性都设置为false,表示密钥对具有公钥和私钥。我已经确认xml不包含私钥信息,因此问题不在xml文件中。

当使用CspParameters对象并将Flags指定为CspProviderFlags.UseMachineKeyStore时,似乎会出现此问题。如果在不指定任何Csp参数的情况下构造RSACryptoServiceProvider,然后从xml导入密钥,则PublicOnly属性将正确设置为false。

String xmlText = File.ReadAllText(filePath);
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
csp.FromXmlString(xmlText);
//csp.PublicOnly equals true;

然而,由于我需要为密钥容器命名,以便以后可以用于加密操作,因此在构造RSACryptoServiceProvider时,我被迫使用CspParameters对象,因为没有其他方法可以命名密钥容器。

String xmlText = File.ReadAllText(filePath);
CspParameters cspParams = new CspParameters();
cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
cspParams.KeyContainerName = keyContainerName;
RSACryptoServiceProvider csp = new RSACryptoServiceProvider(cspParams);
csp.PersistKeyInCsp = true;
csp.FromXmlString(xmlText);
//csp.PublicOnly equals false;

我已经尝试了这个代码的各种版本,但是问题仍然存在。我注意到还有类似的问题,比如RSA加密公钥没有从容器中返回?然而,我认为这个问题是不同的,从来没有令人满意的答案。

因此,问题是如何从XML导入RSA公钥并为密钥容器命名,同时确保容器中只存在公钥对?

编辑

围绕这一领域的进一步研究还表明,从xml导入完整密钥以及设置标志以允许导出密钥时存在问题。

CspProviderFlags.UseArchivableKey;

当在CSP Parameter对象上指定此标志时,会在csp.FromXmlString(xmlText)行引发类型为"Invalid flags specified"的异常;

我真的无法解释。该密钥是创建的,并且以前导出到XML,如果该密钥以前已经导出,那么应该可以导入它并允许它再次导出吗?

我对此做了很多研究,但就是看不到这两个问题的答案。

我已经尝试将csp提供程序类型从PROV_RSA_FULL更改为PROV_RS_AES,因为我相信这现在是默认的,我认为密钥最初可能是使用它而不是PROV_RSA.FULL创建的,但这没有什么区别。

使用RSACryptoServiceProvider从XML导入RSA公钥会将属性PublicOnly设置为false

导入密钥参数(从XML或RSAParameters(时,如果提供了公共参数,RSACryptoServiceProvider将与当前密钥分离;如果导入了私有参数,它只替换密钥容器中密钥的内容。

http://referencesource.microsoft.com/#mscorlib/system/security/cryptography/rsacryptoserviceprovider.cs,b027f6909a0a6d1

ImportCspBlob采用了不同的路径,但最终得出了相同的结论:如果正在导入一个仅限公共的blob,它将分离到一个临时密钥。http://referencesource.microsoft.com/#mscorlib/system/security/cryptography/utils.cs,754f1f4055bba611

底层的Windows加密API似乎不允许存储公钥(除了使用私钥存储公钥之外(。

CNG文件https://msdn.microsoft.com/en-us/library/windows/desktop/bb427412aspx表示

BCryptExportKey要创建持久化密钥对,输入密钥BLOB必须包含私钥。公钥未持久化。

有人认为他们指的是BCryptImportKey,但"公钥没有持久化"感觉很权威。

对于CAPI,我找不到任何东西能如此简单明了。

我能找到的最好的是CAPI对"密钥容器"的定义(https://msdn.microsoft.com/en-us/library/windows/desktop/ms721590(v=vs.85(.aspx#_security_key_container_gly(:

密钥容器

密钥数据库的一部分,包含属于特定用户的所有密钥对(交换和签名密钥对(。每个容器都有一个唯一的名称,在调用CryptAcquireContext函数以获取容器的句柄时使用该名称。

这个定义只引用"密钥对",这表明"公钥"可能会被存储层拒绝。考虑到RSACryptoServiceProvider的行为,这似乎很有可能。