我想导入使用CngKey.Export(CngKeyBlobFormat.EccPrivateBlob)导出的密钥,为密钥命名,并将其保留在密钥存储区中。这应该是这么简单,但我没有找到任何办法。
我可以使用CngKey.Create创建一个命名密钥,并将其保存到密钥存储区,以便稍后通过CngKey.Open使用它。如果我使用正确的选项创建它,我可以使用CngKey.Export将密钥导出为EccPrivateBlob并将其存储在文件中。稍后,我可以从文件中读取这些字节,并使用如下调用重新导入密钥:
CngKey key = CngKey.Import(keyBytes,
CngKeyBlobFormat.EccPrivateBlob);
这很成功,但它产生了一个未命名的临时密钥。如何为Create提供密钥的名称,因此导入的密钥将存储在密钥库中? 我正在寻找一种方法来存档ECDsa签名密钥,然后将其还原到其他用户或PC。我不想留下私人blob并且每次都导入它 - 我希望管理员只导入一次并将其安全地锁定在密钥库中。
答案 0 :(得分:1)
所以最后我能够解决这个问题。主要问题是,Microsoft的人员编写代码的方式是导入不会将密钥导入密钥库,而是需要使用导出的字节再次重新创建密钥。
要导出,导入和测试方法的完整代码如下:
[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
这里有一些要点:
测试:
$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"
答案 1 :(得分:0)
As you rightly said, the import does not supply a keyName and therefor it creates an ephemeral key. What you need to do is call CngKey.Create and supply a CngProperty in the CreationParameters containing the private blob:
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);
}
You can get the private blob like this:
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);
}