Я использовал метод расширения, найденный в этом ссылка в течение многих лет, чтобы получить доступ к сертификату на смарт-карте и предоставить ПИН-код программно, не открывая пользователю маску ПИН-кода запроса. Сейчас с новыми версиями ядра .net уже не работает, поэтому пытаюсь исправить.

Я знаю, что сейчас с новыми версиями фреймворка лучше использовать

RSA rsa = certificate.GetRSAPrivateKey();

Однако таким образом у меня нет доступа к CspKeyContainerInfo (KeyContainerName, ProviderName, ProviderType), необходимому для вызова собственных методов, предоставляющих PIN-код

Есть ли способ получить доступ к той же информации с помощью объекта RSA?

Или есть лучший/более новый способ предоставления PIN-кода смарт-карты программой?

3
Lorenzo 27 Апр 2020 в 18:48
Режим шифрования по умолчанию меняется с последней версией Net. Многие люди сталкиваются с этой проблемой. Microsoft облажалась и изменила настройки по умолчанию, поэтому код больше не совместим с предыдущими версиями. Теория Microsoft заключается в переходе на новейшие технологии. Необходимо найти режим шифрования сертификата. а затем используйте правильные параметры для RSA, чтобы быть совместимым со старым сертификатом. Недавно видел, когда RSA использовался через Ethernet, что скрипач пробовал каждую настройку режима RSA, а затем отображал, какой из них работает. Отличный инструмент. Все еще пытаюсь выяснить с новыми версиями Сети, какие параметры шифрования изменились.
 – 
jdweng
27 Апр 2020 в 19:21

1 ответ

Код, который у вас есть, работает только тогда, когда закрытый ключ предоставляется Windows CAPI. Если закрытый ключ предоставляется Windows CNG, вам нужно сделать его в форме CNG.

private static RSA GetRSAPrivateKeyWithPin(this X509Certificate2 cert, string pin)
{
    RSA rsa = cert.GetRSAPrivateKey();

    if (rsa is RSACryptoServiceProvider rsaCsp)
    {
        // Current code
        SetPin(rsaCsp);
        return rsa;
    }

    if (rsa is RSACng rsaCng)
    {
        // Set the PIN, an explicit null terminator is required to this Unicode/UCS-2 string.

        byte[] propertyBytes;

        if (pin[pin.Length - 1] == '\0')
        {
            propertyBytes = Encoding.Unicode.GetBytes(pin);
        }
        else
        {
            propertyBytes = new byte[Encoding.Unicode.GetByteCount(pin) + 2];
            Encoding.Unicode.GetBytes(pin, 0, pin.Length, propertyBytes, 0);
        }

        const string NCRYPT_PIN_PROPERTY = "SmartCardPin";

        CngProperty pinProperty = new CngProperty(
            NCRYPT_PIN_PROPERTY,
            propertyBytes,
            CngPropertyOptions.None);

        rsaCng.Key.SetProperty(pinProperty);
        return rsa;
    }

    // If you're on macOS or Linux neither of the above will hit. There's
    // also no standard model for setting a PIN on either of those OS families.
    rsa.Dispose();
    throw new NotSupportedException($"Don't know how to set the PIN for {rsa.GetType().FullName}");
}

PIN-код RSACng, скопированный с https://stackoverflow.com/a/42630670/6535399; потому что этот вопрос кажется более открытым, и ответ здесь более общий.

4
bartonjs 27 Апр 2020 в 20:10
Большое спасибо Джереми, это работает как шарм. Извините, я не нашел другого ответа.
 – 
Lorenzo
28 Апр 2020 в 11:35