【问题标题】:How do I import a CNG Key to the key store?如何将 CNG 密钥导入密钥库?
【发布时间】:2016-03-23 13:48:57
【问题描述】:

我想导入一个使用 CngKey.Export(CngKeyBlobFormat.EccPrivateBlob) 导出的密钥,为该密钥命名,并将其保存在密钥存储中。这应该很简单,但我还没有找到任何方法来做到这一点。

我可以使用 CngKey.Create 创建一个命名密钥,并将其持久化到密钥存储中,以便我以后可以通过 CngKey.Open 使用它。如果我使用正确的选项创建它,我可以使用 CngKey.Export 将密钥导出为 EccPrivateBlob 并将其存储在文件中。稍后,我可以从文件中读回这些字节,并使用如下调用重新导入密钥:

CngKey key = CngKey.Import(keyBytes,
       CngKeyBlobFormat.EccPrivateBlob);

这是成功的,但它会生成一个未命名的临时密钥。如何像使用 Create 一样为密钥提供名称,以便将导入的密钥存储在密钥库中?
我正在寻找一种方法来存档 ECDsa 签名密钥,然后将其还原给不同的用户或 PC。我不想让私有 blob 闲置并每次都导入它——我希望管理员只导入它一次并将其安全地锁定在密钥库中。

【问题讨论】:

  • 嗨,babackman,我也在寻找解决方案。你找到了吗?
  • 这个问题有什么解决办法吗?我正在寻找这个并且 CngKey.import() 创建一个未命名的密钥对象。我的密钥也作为 MachineKey 导出,但 import 创建了一个非 machinekey 对象。我的代码如下: $importedKeyBlob = [System.IO.File]::readAllBytes($privateFileName); [System.Security.Cryptography.CngKey] $importedkey = [System.Security.Cryptography.CngKey]::Import($importedKeyBlob, [System.Security.Cryptography.CngKeyBlobFormat]::Pkcs8PrivateBlob, [System.Security.Cryptography.CngProvider] ::MicrosoftSoftwareKeyStorageProvider)

标签: c# cryptography cng


【解决方案1】:

正如您所说的那样,导入不提供 keyName,因此它创建了一个临时密钥。您需要做的是调用 CngKey.Create 并在包含私有 blob 的 CreationParameters 中提供 CngProperty:

var myKSP = CngProvider.MicrosoftSoftwareKeyStorageProvider;
var blobType = CngKeyBlobFormat.GenericPrivateBlob;
var keyData = Convert.FromBase64String(privateKey);
const bool MachineKey = false;

if (!CngKey.Exists(keyName, myKSP))
{
    var keyParams = new CngKeyCreationParameters
    {
        ExportPolicy = CngExportPolicies.AllowPlaintextExport,
        KeyCreationOptions = (MachineKey) ? CngKeyCreationOptions.MachineKey : CngKeyCreationOptions.None,
        Provider = myKSP
    };
    keyParams.Parameters.Add(new CngProperty(blobType.Format, keyData, CngPropertyOptions.None));

    var key = CngKey.Create(CngAlgorithm.Rsa, keyName, keyParams);
}

您可以像这样获取私有 blob:

var myKSP = CngProvider.MicrosoftSoftwareKeyStorageProvider;
if (CngKey.Exists(keyName, myKSP))
{
    var key = CngKey.Open(keyName);
    var blobType = CngKeyBlobFormat.GenericPrivateBlob;
    var bytes = key.Export(blobType);

    return Convert.ToBase64String(bytes);
}

【讨论】:

  • 如果您想导入临时密钥但需要将导出策略设置为 AllowPlainTextExport,这也是可行的方法。
【解决方案2】:

所以最后我能够解决这个问题。主要问题是微软人员编写代码的方式是 Import 不会将密钥导入密钥存储区,而是您需要使用导出的字节再次重新创建密钥。

导出、导入和测试方法的完整代码如下:

创建 Cng 关键参数并设置其属性

[System.Security.Cryptography.CngKeyCreationParameters] $cngKeyParameter =  [System.Security.Cryptography.CngKeyCreationParameters]::new()
$cngKeyParameter.KeyUsage = [System.Security.Cryptography.CngKeyUsages]::AllUsages
$cngKeyParameter.ExportPolicy = [System.Security.Cryptography.CngExportPolicies]::AllowPlaintextExport

$cngKeyParameter.Provider = [System.Security.Cryptography.CngProvider]::MicrosoftSoftwareKeyStorageProvider
$cngKeyParameter.UIPolicy = [System.Security.Cryptography.CngUIPolicy]::new([System.Security.Cryptography.CngUIProtectionLevels]::None)
$cngKeyParameter.KeyCreationOptions = [System.Security.Cryptography.CngKeyCreationOptions]::MachineKey
    
#Create Cng Property for Length, set its value and add it to Cng Key Parameter
[System.Security.Cryptography.CngProperty] $cngProperty = [System.Security.Cryptography.CngProperty]::new($cngPropertyName, [System.BitConverter]::GetBytes(2048), [System.Security.Cryptography.CngPropertyOptions]::None)
$cngKeyParameter.Parameters.Add($cngProperty)

#Create Cng Key for given $keyName using Rsa Algorithm
[System.Security.Cryptography.CngKey] $key = [System.Security.Cryptography.CngKey]::Create([System.Security.Cryptography.CngAlgorithm]::Rsa, "MyRsaKey", $cngKeyParameter)
    
Write-Output "CNG Key : $globalkeyName - Created"

将密钥导出到文件

 [System.IO.File]::WriteAllBytes("c:\\user\myusername\\keyexport", $key.Export([System.Security.Cryptography.CngKeyBlobFormat]::GenericPrivateBlob));

进口

    $importedKeyBlob = [System.IO.File]::readAllBytes("c:\\user\myusername\\keyexport");
   # [System.Security.Cryptography.CngKey] $importedkey = [System.Security.Cryptography.CngKey]::Import($importedKeyBlob, [System.Security.Cryptography.CngKeyBlobFormat]::GenericPrivateBlob, [System.Security.Cryptography.CngProvider]::MicrosoftSoftwareKeyStorageProvider)

       #Create Cng Key Parameter and set its properties
[System.Security.Cryptography.CngKeyCreationParameters] $cngKeyParameter =  [System.Security.Cryptography.CngKeyCreationParameters]::new()
$cngKeyParameter.KeyUsage = [System.Security.Cryptography.CngKeyUsages]::AllUsages
$cngKeyParameter.ExportPolicy = [System.Security.Cryptography.CngExportPolicies]::AllowPlaintextExport

$cngKeyParameter.Provider = [System.Security.Cryptography.CngProvider]::MicrosoftSoftwareKeyStorageProvider
$cngKeyParameter.UIPolicy = [System.Security.Cryptography.CngUIPolicy]::new([System.Security.Cryptography.CngUIProtectionLevels]::None)
$cngKeyParameter.KeyCreationOptions = [System.Security.Cryptography.CngKeyCreationOptions]::MachineKey
    
#Create Cng Property for Length, set its value and add it to Cng Key Parameter
[System.Security.Cryptography.CngProperty] $cngProperty = [System.Security.Cryptography.CngProperty]::new($cngPropertyName, [System.BitConverter]::GetBytes(2048), [System.Security.Cryptography.CngPropertyOptions]::None)
$cngKeyParameter.Parameters.Add($cngProperty)

#Create Cng Property for blob, set its value and add it to Cng Key Parameter
[System.Security.Cryptography.CngProperty] $keyBlobProperty = [System.Security.Cryptography.CngProperty]::new([System.Security.Cryptography.CngKeyBlobFormat]::GenericPrivateBlob,$importedKeyBlob , [System.Security.Cryptography.CngPropertyOptions]::None)
$cngKeyParameter.Parameters.Add($keyBlobProperty)

$cngKeyParameter

#Create Cng Key for given $keyName using Rsa Algorithm
[System.Security.Cryptography.CngKey] $key = [System.Security.Cryptography.CngKey]::Create([System.Security.Cryptography.CngAlgorithm]::Rsa, "MyRsaKey", $cngKeyParameter)

$key 

这里有一些要点:

  1. [System.Security.Cryptography.CngKeyBlobFormat]::Pkcs8PrivateBlob 仍然无法正常工作。我看到 MS 人员在 GitHub 上谈论他们在这种消息格式中存在问题。
  2. 导出和导入的 CngKeyBlob 格式应该相同,否则代码将无法正常工作并出现未知错误
  3. 您应该使用管理员权限运行 powershell ISE

测试:

  • 创建密钥“MyRsaKey”
  • 通过线程下方给出的测试 powershell 测试密钥是否存在于密钥库中
  • 导出密钥
  • 使用以下 powershell 脚本删除密钥
  • 再次测试密钥是否在密钥库中
  • 再次导入并测试

测试密钥是否存在于密钥库中

$isKeyExists = [System.Security.Cryptography.CngKey]::Exists("MyRsaKey", [System.Security.Cryptography.CngProvider]::MicrosoftSoftwareKeyStorageProvider, [System.Security.Cryptography.CngKeyCreationOptions]::MachineKey)
Write-Output "CNG Key Exists :: $isKeyExists"

从密钥库中删除密钥并测试是否成功删除密钥

[System.Security.Cryptography.CngKey] $key = [System.Security.Cryptography.CngKey]::Open($globalkeyName, [System.Security.Cryptography.CngProvider]::MicrosoftSoftwareKeyStorageProvider, [System.Security.Cryptography.CngKeyCreationOptions]::MachineKey)
    $key.Delete()

    $isKeyExists = [System.Security.Cryptography.CngKey]::Exists($globalkeyName, [System.Security.Cryptography.CngProvider]::MicrosoftSoftwareKeyStorageProvider, [System.Security.Cryptography.CngKeyCreationOptions]::MachineKey)
Write-Output "CNG Key Exists :: $isKeyExists"

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-02
  • 1970-01-01
  • 2013-08-06
  • 2013-01-02
  • 2016-03-08
  • 2011-01-29
相关资源
最近更新 更多