Работа с Рутокен и ГОСТ в C#: от архитектуры PKCS#11 до готового кода подписи
Электронная подпись (КЭП) прочно вошла в корпоративный и государственный документооборот. В России стандартом де-факто стали аппаратные токены Рутокен и криптопровайдер КриптоПро CSP. Однако при разработке программного обеспечения, которое должно подписывать документы напрямую (без участия CSP), разработчики часто упираются в один и тот же вопрос: как на C# подписать данные с использованием закрытого ключа, который хранится на Рутокене?
Ответ лежит в стандарте PKCS#11 и библиотеке rtPKCS11ECP.dll. В этой статье мы разберём:
- что такое PKCS#11 и как
rtPKCS11ECP.dllобщается с токеном; - какие библиотеки для C# существуют и какую выбрать;
- как написать рабочий код для подписи данных по ГОСТ Р 34.10-2012;
- какие методы PKCS#11 используются и как ими управлять.
Статья ориентирована на практиков: после её прочтения вы сможете самостоятельно подключать Рутокен к своим .NET-приложениям.
1. Архитектура PKCS#11: как библиотека находит и общается с токеном
Прежде чем писать код, важно понять иерархию объектов PKCS#11. Это знание поможет вам правильно искать ключи и сертификаты.

Ключевые понятия PKCS#11:
- Слот (Slot) – логическое место, куда можно вставить токен. Каждому USB-порту или считывателю соответствует свой слот.
- Токен (Token) – само устройство (Рутокен), подключённое к слоту. Токен содержит объекты: ключи, сертификаты, данные.
- Сессия (Session) – канал связи между приложением и токеном. Все операции выполняются внутри открытой сессии.
- Объекты (Objects) – ключи, сертификаты, данные. Имеют класс (
CKO_PRIVATE_KEY,CKO_CERTIFICATEи т.д.) и атрибуты (CKA_ID,CKA_LABEL...). - Атрибуты (Attributes) – свойства объекта, по которым его можно искать. Например,
CKA_IDсвязывает закрытый ключ с его сертификатом. - Механизмы (Mechanisms) – алгоритмы, поддерживаемые токеном. Для ГОСТ Р 34.10-2012 это
CKM_GOSTR3410_WITH_GOSTR3411_2012_256(подпись с хешированием) и другие.
2. Где взять rtPKCS11ECP.dll
Библиотека rtPKCS11ECP.dll – это реализация PKCS#11 от компании «Актив» для токенов Рутокен. Она устанавливается вместе с драйверами Рутокен или КриптоПро CSP.
Типичные пути:
- Windows (64 бита):
C:\Windows\System32\rtPKCS11ECP.dllC:\Program Files\Crypto Pro\PKCS11\rtPKCS11ECP.dll - Windows (32 бита):
C:\Windows\SysWOW64\rtPKCS11ECP.dll - Linux:
/usr/lib/librtpkcs11ecp.soили/usr/lib64/librtpkcs11ecp.so
В коде C# мы будем загружать эту библиотеку не напрямую через DllImport, а через специализированные обёртки (см. следующий раздел).
3. Популярные C# библиотеки для работы с PKCS#11 и ГОСТ
Для C# существует несколько библиотек, которые упрощают вызов функций PKCS#11. Ниже приведена сравнительная таблица.
| Библиотека | Производитель | Лицензия | Поддержка ГОСТ Р 34.10-2012 | Уровень удобства |
|---|---|---|---|---|
| Pkcs11Interop | Сообщество | Apache 2.0 | Да (через механизмы токена) | Низкоуровневый, полный контроль |
| RutokenPkcs11Interop | АО "Актив" (Рутокен) | Проприетарная / Free | Да (полная, с готовыми примерами) | Высокий (расширяет Pkcs11Interop) |
| NCryptoki | Secure Improvements | Коммерческая | Нет данных | Высокий (абстрагирует PKCS#11) |
| Сообщество | Open Source | Нет данных | Низкий | |
| Bouncy Castle | Legion of the Bouncy Castle | MIT | Да (алгоритмы, но не PKCS#11) | Не適用 (не для PKCS#11) |
Рекомендация: Для работы с Рутокен и ГОСТ оптимально использовать Pkcs11Interop (универсально) или RutokenPkcs11Interop (если нужны специфические функции Рутокен). Обе библиотеки позволяют вызывать любые механизмы PKCS#11, включая CKM_GOSTR3410_WITH_GOSTR3411_2012_256.
Install-Package Pkcs11Interop
# или
Install-Package RutokenPkcs11Interop4. Практика: подписание данных на C# с помощью Pkcs11Interop
Ниже приведён рабочий пример кода, который:
- загружает
rtPKCS11ECP.dll; - открывает сессию с первым найденным токеном;
- аутентифицируется по PIN-коду;
- находит закрытый ключ с атрибутом
CKA_SIGN; - подписывает строку с использованием механизма
CKM_GOSTR3410_WITH_GOSTR3411_2012_256; - выводит подпись в Base64.
class Program
{
static void Main()
{
// 1. Путь к библиотеке PKCS#11
string libPath = @"C:\Windows\System32\rtPKCS11ECP.dll";
// 2. Создаём фабрику и загружаем библиотеку
var factories = new Pkcs11InteropFactories();
using (IPkcs11Library pkcs11 = factories.Pkcs11LibraryFactory.LoadPkcs11Library(factories, libPath, AppType.MultiThreaded))
{
// 3. Получаем список слотов с токенами
List<ISlot> slots = pkcs11.GetSlotList(SlotsType.WithTokenPresent);
if (slots.Count == 0)
{
Console.WriteLine("Токен не найден.");
return;
}
ISlot slot = slots[0];
Console.WriteLine($"Используем слот: {slot.SlotId}");
// 4. Открываем сессию (ReadWrite)
using (ISession session = slot.OpenSession(SessionType.ReadWrite))
{
// 5. Вход по PIN-коду
Console.Write("Введите PIN: ");
string pin = Console.ReadLine();
session.Login(CKU.CKU_USER, pin);
Console.WriteLine("Аутентификация успешна.");
// 6. Поиск закрытого ключа, поддерживающего подпись
var searchAttributes = new List<IObjectAttribute>
{
factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY),
factories.ObjectAttributeFactory.Create(CKA.CKA_SIGN, true)
};
List<IObjectHandle> privateKeys = session.FindAllObjects(searchAttributes);
if (privateKeys.Count == 0)
{
Console.WriteLine("Не найден закрытый ключ для подписи.");
return;
}
IObjectHandle privateKey = privateKeys[0];
Console.WriteLine("Ключ найден.");
// 7. Данные для подписи
byte[] dataToSign = Encoding.UTF8.GetBytes("Документ для подписи");
// 8. Механизм подписи с хешированием по ГОСТ 2012-256
IMechanism mechanism = factories.MechanismFactory.Create(CKM.CKM_GOSTR3410_WITH_GOSTR3411_2012_256);
// 9. Подписание
byte[] signature = session.Sign(mechanism, privateKey, dataToSign);
Console.WriteLine($"Подпись (Base64): {Convert.ToBase64String(signature)}");
// 10. Завершение
session.Logout();
}
}
}
}Пояснения:
Метод Sign сам вычисляет хеш по ГОСТ Р 34.11-2012, поскольку механизм CKM_GOSTR3410_WITH_GOSTR3411_2012_256 включает хеширование.
Не нужно предварительно вызывать ComputeGostHash – это делает токен или библиотека.
Если ваш токен не поддерживает этот механизм, можно использовать CKM_GOSTR3410 и передавать хеш, но это менее удобно.
5. Основные методы PKCS#11, используемые в C# (через Pkcs11Interop)
| Метод (в обёртке) | Описание |
|---|---|
pkcs11.GetSlotList(SlotsType.WithTokenPresent) | Возвращает список слотов, в которых есть токен. |
slot.OpenSession(SessionType.ReadWrite) | Открывает сессию для работы с токеном. |
session.Login(CKU.CKU_USER, pin) | Аутентификация пользователя. |
session.FindAllObjects(attributes) | Поиск объектов (ключей, сертификатов) по атрибутам. |
session.GetAttributeValue(objectHandle, attributes) | Получение значений атрибутов объекта (например, CKA_ID). |
session.Sign(mechanism, privateKey, data) | Выполнение операции подписи. |
session.Logout() | Завершение сеанса пользователя. |
session.Close() | Закрытие сессии (вызывается автоматически при Dispose). |
6. Как проверить подпись (кратко)
Проверка подписи может быть выполнена как на том же токене (метод session.Verify), так и программно с использованием открытого ключа из сертификата. Ниже пример проверки через Bouncy Castle (без токена):
bool VerifySignature(byte[] data, byte[] signature, byte[] certDer)
{
var parser = new X509CertificateParser();
var cert = parser.ReadCertificate(certDer);
var pubKey = cert.GetPublicKey() as Org.BouncyCastle.Crypto.Parameters.ECGost3410PublicKeyParameters;
if (pubKey == null) return false;
var signer = new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411_2012_256Digest());
signer.Init(false, pubKey);
signer.BlockUpdate(data, 0, data.Length);
return signer.VerifySignature(signature);
}7. Заключение
Мы разобрали:
- что такое PKCS#11 и как
rtPKCS11ECP.dllслужит мостом между C# и Рутокеном; - какие C# библиотеки существуют и почему
Pkcs11Interop– лучший выбор для ГОСТ; - как написать компактный код для подписи данных с использованием механизма
CKM_GOSTR3410_WITH_GOSTR3411_2012_256; - основные методы PKCS#11, которые понадобятся в 90% задач.
Теперь вы можете подписывать документы, отчёты и JSON-данные, работая с Рутокеном напрямую, без участия КриптоПро CSP. Это даёт больше контроля и позволяет встраивать КЭП в любые .NET-приложения.
Только полноправные пользователи могут оставлять комментарии. Аутентифицируйтесь пожалуйста, используя сервисы.