NCryptCreatePersistedKey
NCryptCreatePersistedKey — это функция из набора криптографических API (Cryptography API: Next Generation, CNG) в операционной системе Windows, предназначенная для создания постоянного (persisted) ключа в указанном хранилище ключей (Key Storage Provider, KSP). Данная функция позволяет создавать как симметричные, так и асимметричные ключи, которые сохраняются в защищённом хранилище и могут быть впоследствии использованы для шифрования, расшифрования, подписи или проверки подписи.
История и контекст
Функция NCryptCreatePersistedKey была введена в Windows Vista и Windows Server 2008 вместе с платформой CNG, которая пришла на смену устаревшей CryptoAPI (CAPI). CNG представляет собой модульную, расширяемую архитектуру, поддерживающую современные алгоритмы шифрования (например, AES, SHA-2, ECDSA) и аппаратные модули безопасности (HSM). Функция входит в состав библиотеки ncrypt.dll и является частью интерфейса, ориентированного на работу с постоянными ключами, в отличие от временных (эпизодических) ключей, создаваемых, например, функцией NCryptGenerateKey.
Синтаксис и параметры
Функция объявлена в заголовочном файле ncrypt.h и имеет следующий прототип на языке C:
``c SECURITY_STATUS NCryptCreatePersistedKey( NCRYPT_PROV_HANDLE hProvider, NCRYPT_KEY_HANDLE *phKey, LPCWSTR pszAlgId, LPCWSTR pszKeyName, DWORD dwLegacyKeySpec, DWORD dwFlags ); ``
Параметры
- hProvider — дескриптор поставщика ключей (KSP), полученный с помощью функции
NCryptOpenStorageProvider. Обычно это встроенный Microsoft Software Key Storage Provider или сторонний KSP. - phKey — указатель на переменную, которая после успешного вызова получает дескриптор созданного ключа.
- pszAlgId — строка, идентифицирующая алгоритм ключа. Возможные значения:
NCRYPT_RSA_ALGORITHM,NCRYPT_DSA_ALGORITHM,NCRYPT_DH_ALGORITHM,NCRYPT_ECDSA_P256_ALGORITHM,NCRYPT_ECDH_P256_ALGORITHM,NCRYPT_AES_ALGORITHMи другие. Для симметричных алгоритмов требуется указание размера ключа через флаги. - pszKeyName — строка, задающая имя ключа в хранилище. Если ключ с таким именем уже существует, функция может вернуть ошибку
NTE_EXISTS(если не указан флагNCRYPT_OVERWRITE_KEY_FLAG). Если имя равноNULL, создаётся эпизодический (непостоянный) ключ, который не сохраняется. - dwLegacyKeySpec — зарезервированный параметр для обратной совместимости с CryptoAPI. Должен быть равен 0 для новых приложений.
- dwFlags — набор флагов, влияющих на поведение функции. Основные флаги:
NCRYPT_OVERWRITE_KEY_FLAG— разрешает перезапись существующего ключа с тем же именем.NCRYPT_MACHINE_KEY_FLAG— создаёт ключ в машинном хранилище (доступен всем пользователям системы), а не в пользовательском.NCRYPT_EXPORTABLE_KEY— делает ключ экспортируемым (может быть извлечён из хранилища).NCRYPT_PROTECTED_KEY_FLAG— создаёт ключ, защищённый аппаратным модулем (например, TPM).
Возвращаемое значение
Функция возвращает код состояния типа SECURITY_STATUS. В случае успеха возвращается ERROR_SUCCESS (0). Возможные ошибки:
NTE_BAD_FLAGS— недопустимая комбинация флагов.NTE_EXISTS— ключ с указанным именем уже существует и не указан флаг перезаписи.NTE_INVALID_HANDLE— неверный дескриптор поставщика.NTE_NO_MEMORY— недостаточно памяти.NTE_NOT_SUPPORTED— алгоритм не поддерживается поставщиком.
Порядок работы с постоянным ключом
Создание и использование постоянного ключа через CNG включает несколько этапов:
- Открытие поставщика ключей — вызов
NCryptOpenStorageProvider. - Создание ключа — вызов
NCryptCreatePersistedKeyс указанием имени и флагов. - Настройка параметров ключа (опционально) — вызов
NCryptSetPropertyдля задания размера ключа, длины хэша и других атрибутов. - Сохранение ключа — вызов
NCryptFinalizeKey. Только после этого ключ фактически записывается в хранилище и становится доступным для криптографических операций. - Использование ключа — вызов функций
NCryptEncrypt,NCryptDecrypt,NCryptSignHash,NCryptVerifySignatureи других. - Закрытие дескрипторов — вызов
NCryptFreeObjectдля ключа и поставщика.
Пример использования
Ниже приведён упрощённый пример создания постоянного RSA-ключа длиной 2048 бит в пользовательском хранилище:
```c
include <windows.h>
include <ncrypt.h>
include <stdio.h>
pragma comment(lib, "ncrypt.lib")
void CreatePersistedRSAKey() { NCRYPT_PROV_HANDLE hProvider = NULL; NCRYPT_KEY_HANDLE hKey = NULL; SECURITY_STATUS secStatus;
// Открытие поставщика Microsoft Software Key Storage Provider secStatus = NCryptOpenStorageProvider(&hProvider, MS_KEY_STORAGE_PROVIDER, 0); if (secStatus != ERROR_SUCCESS) { printf("NCryptOpenStorageProvider failed: 0x%x\n", secStatus); return; }
// Создание постоянного RSA-ключа с именем "MyRSAKey" secStatus = NCryptCreatePersistedKey(hProvider, &hKey, NCRYPT_RSA_ALGORITHM, L"MyRSAKey", 0, NCRYPT_EXPORTABLE_KEY); if (secStatus != ERROR_SUCCESS) { printf("NCryptCreatePersistedKey failed: 0x%x\n", secStatus); NCryptFreeObject(hProvider); return; }
// Установка размера ключа (2048 бит) DWORD keyLength = 2048; secStatus = NCryptSetProperty(hKey, NCRYPT_LENGTH_PROPERTY, (PBYTE)&keyLength, sizeof(keyLength), 0); if (secStatus != ERROR_SUCCESS) { printf("NCryptSetProperty failed: 0x%x\n", secStatus); NCryptFreeObject(hKey); NCryptFreeObject(hProvider); return; }
// Финализация ключа (сохранение в хранилище) secStatus = NCryptFinalizeKey(hKey, 0); if (secStatus != ERROR_SUCCESS) { printf("NCryptFinalizeKey failed: 0x%x\n", secStatus); } else { printf("RSA key created successfully.\n"); }
// Очистка ресурсов NCryptFreeObject(hKey); NCryptFreeObject(hProvider); } ```
Особенности и ограничения
- Функция NCryptCreatePersistedKey не создаёт ключ мгновенно — он сохраняется только после вызова
NCryptFinalizeKey. До этого момента ключ находится в оперативной памяти и может быть настроен. - Имя ключа (
pszKeyName) должно быть уникальным в пределах хранилища и поставщика. Для машинных ключей (флагNCRYPT_MACHINE_KEY_FLAG) требуется административные привилегии. - Некоторые поставщики (например, аппаратные HSM) могут накладывать дополнительные ограничения на создаваемые ключи, такие как минимальная длина или запрет на экспорт.
- В Windows 10 и более поздних версиях поддерживается создание ключей с использованием Trusted Platform Module (TPM) через поставщика
Microsoft Platform Crypto Provider.
Применение
Функция используется в широком спектре приложений, требующих долговременного хранения криптографических ключей:
- Защита данных — шифрование файлов, баз данных, конфигураций с использованием постоянных ключей.
- Цифровые подписи — создание и проверка подписей для документов, программного обеспечения, электронных писем.
- Аутентификация — хранение ключей для протоколов TLS/SSL, VPN, Kerberos.
- Аппаратные модули безопасности — интеграция с TPM и смарт-картами для создания ключей, недоступных для извлечения.
Связанные функции
NCryptOpenStorageProvider— открытие поставщика ключей.NCryptFinalizeKey— сохранение ключа в хранилище.NCryptDeleteKey— удаление постоянного ключа.NCryptGetProperty/NCryptSetProperty— чтение и запись свойств ключа.NCryptEnumKeys— перечисление ключей в хранилище.
Критика и альтернативы
Основной недостаток функции — её привязка к платформе Windows. Для кроссплатформенных приложений используются библиотеки OpenSSL, libsodium или Bouncy Castle. Кроме того, сложность управления ключами через CNG (необходимость ручной финализации) может приводить к ошибкам, если разработчик не завершает создание ключа. В некоторых сценариях предпочтительнее использовать временные ключи (создаваемые через NCryptGenerateKey), которые не требуют управления хранилищем.
Источники
- Microsoft Docs: «NCryptCreatePersistedKey function» (ncrypt.h)
- Microsoft Docs: «Cryptography API: Next Generation»
- MSDN: «Key Storage Provider (KSP)»
- Windows SDK: заголовочный файл ncrypt.h
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →