Открыть сервис

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 включает несколько этапов:

  1. Открытие поставщика ключей — вызов NCryptOpenStorageProvider.
  2. Создание ключа — вызов NCryptCreatePersistedKey с указанием имени и флагов.
  3. Настройка параметров ключа (опционально) — вызов NCryptSetProperty для задания размера ключа, длины хэша и других атрибутов.
  4. Сохранение ключа — вызов NCryptFinalizeKey. Только после этого ключ фактически записывается в хранилище и становится доступным для криптографических операций.
  5. Использование ключа — вызов функций NCryptEncrypt, NCryptDecrypt, NCryptSignHash, NCryptVerifySignature и других.
  6. Закрытие дескрипторов — вызов 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 →