RSACryptoServiceProvider против RSACng - PullRequest
       88

RSACryptoServiceProvider против RSACng

1 голос
/ 17 апреля 2020

У меня есть (неэкспортируемые) ключи, которые были созданы с использованием RSACryptoServiceProvider. Я хочу подписать данные, используя RSA-PSS (который не RSACryptoServiceProvider). Поэтому я хочу получить тот же закрытый ключ, что и экземпляр RSACng.

Я попытался сделать следующее:

// Create key with RSACryptoServiceProvider
var keyId = Guid.NewGuid().ToString();
var providerName = "Microsoft Enhanced RSA and AES Cryptographic Provider";
var key = new RSACryptoServiceProvider(2048, new CspParameters(24) {
  ProviderName = providerName,
  KeyContainerName = keyId,
  KeyNumber = (int) KeyNumber.Signature,
  Flags = CspProviderFlags.UseNonExportableKey
});

// Obtain an RSACng reference:
var cngKey = CngKey.Open(keyId, new CngProvider(providerName));
var cngRsaKey = new RSACng(cngKey);

// Sign something using cngRsaKey
[...]

К сожалению, всегда происходит сбой при выполнении CngKey.Open с WindowsCryptographicException: Keyset does not exist .

Как открыть ранее созданный ключ с помощью RSACng?

Обратите внимание, что я не могу использовать ответ, предоставленный { ссылка }, потому что я не могу использовать экспортируемые закрытые ключи. В конце ключи должны находиться на HSM (аппаратный модуль безопасности).

Есть идеи?

Ответы [ 2 ]

3 голосов
/ 20 апреля 2020

Очевидно, CngKey.Open не работает для ключей CAPI RSA в слоте Signature (поскольку он жестко кодирует значение dwLegacyKeySpec в 0). Самый простой способ - использовать слот Exchange; но если вам нужно работать с ключами слота Signature, вы можете:

[DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
private static extern int NCryptOpenStorageProvider(
    out SafeNCryptProviderHandle phProvider,
    string pszProviderName,
    int dwFlags);

[DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
private static extern int NCryptOpenKey(
    SafeNCryptProviderHandle hProvider,
    out SafeNCryptKeyHandle phKey,
    string pszKeyName,
    int dwLegacyKeySpec,
    CngKeyOpenOptions dwFlags);

private static void Test61275795()
{
    const string KeyId = "test-982375";

    CspParameters cspParams = new CspParameters(24)
    {
        ProviderName = "Microsoft Enhanced RSA and AES Cryptographic Provider",
        KeyContainerName = KeyId,
        KeyNumber = (int)KeyNumber.Signature,
        Flags = CspProviderFlags.UseNonExportableKey,
    };

    using (RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider(2048, cspParams))
    {
        // Because this is a test, delete the key on Dispose.
        rsaCsp.PersistKeyInCsp = false;

        SafeNCryptKeyHandle hKey;

        int dwError = NCryptOpenStorageProvider(out var hProv, cspParams.ProviderName, 0);

        using (hProv)
        {
            if (dwError != 0)
            {
                throw new CryptographicException(
                    $"{nameof(NCryptOpenStorageProvider)}: 0x{dwError:X8}");
            }

            dwError = NCryptOpenKey(hProv, out hKey, KeyId, cspParams.KeyNumber, 0);

            if (dwError != 0)
            {
                hKey.Dispose();
                throw new CryptographicException($"{nameof(NCryptOpenKey)}: 0x{dwError:X8}");
            }
        }

        using (hKey)
        using (CngKey cngKey = CngKey.Open(hKey, 0))
        using (RSACng rsaCng = new RSACng(cngKey))
        {
            byte[] sig = rsaCng.SignData(
                Array.Empty<byte>(),
                HashAlgorithmName.SHA256,
                RSASignaturePadding.Pss);

            Console.WriteLine(BitConverter.ToString(sig));
        }
    }
}
0 голосов
/ 19 апреля 2020

Существует процедура, называемая "CngLightup", которая позволяет получить ссылку RSACng на ключ, созданный с помощью RSACryptoServiceProvider. Он используется Microsoft, например, при реализации подписания манифеста: https://github.com/microsoft/referencesource/blob/master/inc/mansign2.cs#L1426

Для этого требуется, чтобы у вас в руках был сертификат, а не просто ссылка на ключ. Но легко создать фиктивный самозаверяющий сертификат с помощью имеющегося ключа, затем вызвать CngLightup.GetRSAPrivateKey () и вуаля. Если вы проверите GetType (), у вас в руках будет ссылка на RSACng.

...