PKCS#5: шифрование закрытых ключей паролем

Общая роль PKCS#5 в криптографической экосистеме

PKCS#5 описывает стандарт, определяющий методы защиты криптографических ключей с использованием паролей. Основная задача этого стандарта — безопасное преобразование пароля пользователя в криптографический ключ, который затем используется для шифрования приватных данных, включая закрытые ключи RSA и EC.

В контексте JavaScript-библиотеки Jsrsasign PKCS#5 используется для:

  • шифрования приватных ключей в формате PEM
  • расшифровки защищённых ключей
  • генерации ключей шифрования из паролей
  • поддержки совместимости с OpenSSL и другими криптосистемами

Версии PKCS#5: PBKDF1 и PBKDF2

PKCS#5 имеет две основные редакции алгоритмов вывода ключей из пароля.

PKCS#5 v1 (PBKDF1)

Более старая схема, основанная на однократном хешировании:

  • Использует MD5 или SHA-1
  • Ограничена длиной выходного ключа
  • Считается устаревшей

Формально процесс выглядит как итеративное хеширование:

  • DK = HASH^c(password + salt)

Где:

  • DK — derived key
  • c — количество итераций
  • salt — случайная добавка

PKCS#5 v2 (PBKDF2)

Современный стандарт, используемый в Jsrsasign по умолчанию.

DK = (P, S, c, dkLen)

Где:

  • P — пароль
  • S — salt
  • c — число итераций
  • dkLen — длина ключа

Особенности PBKDF2:

  • поддержка HMAC-SHA1, SHA256 и других
  • высокая устойчивость к brute-force атакам
  • регулируемая сложность через итерации
  • используется в OpenSSL, PKCS#12, JWT-системах

Формат защищённых приватных ключей

В PKCS#5 защищённый приватный ключ обычно хранится в PEM-формате:

-----BEGIN ENCRYPTED PRIVATE KEY-----
...
-----END ENCRYPTED PRIVATE KEY-----

Внутри содержится:

  • алгоритм шифрования (AES, DES-EDE3 и др.)
  • параметры PBKDF2 (salt, iteration count)
  • зашифрованный приватный ключ

Jsrsasign умеет автоматически определять эти параметры при парсинге.


Шифрование приватного ключа в Jsrsasign

В библиотеке Jsrsasign основной инструмент работы с ключами — KEYUTIL.

Пример генерации RSA ключа и его шифрования паролем

const { KEYUTIL, KJUR } = require("jsrsasign");

// генерация RSA ключа
const kp = KEYUTIL.generateKeypair("RSA", 2048);

// приватный ключ
const prv = kp.prvKeyObj;

// шифрование приватного ключа паролем
const encryptedPEM = KEYUTIL.getPEM(prv, "PKCS5PRV", "myStrongPassword");

console.log(encryptedPEM);

Здесь:

  • PKCS5PRV указывает использование PKCS#5 шифрования
  • пароль применяется через PBKDF2 автоматически
  • результат — зашифрованный PEM

Дешифрование приватного ключа

Для восстановления ключа используется тот же пароль:

const { KEYUTIL } = require("jsrsasign");

const pem = `-----BEGIN ENCRYPTED PRIVATE KEY-----...`;

const prvKeyObj = KEYUTIL.getKey(pem, "myStrongPassword");

console.log(prvKeyObj);

Если пароль неверный, Jsrsasign выбрасывает исключение.


Внутренний механизм PKCS#5 в Jsrsasign

При шифровании происходит несколько этапов:

1. Генерация salt

Случайная последовательность байтов:

  • увеличивает стойкость к радужным таблицам
  • хранится внутри PEM

2. Вывод ключа PBKDF2

Пароль + salt → криптографический ключ фиксированной длины.

3. Шифрование приватного ключа

Чаще всего используется:

  • AES-128-CBC
  • AES-256-CBC
  • 3DES (устаревший вариант)

4. Формирование структуры PKCS#8 EncryptedPrivateKeyInfo

Включает:

  • алгоритм шифрования
  • параметры PBKDF2
  • зашифрованный блок ключа

Поддерживаемые алгоритмы в Jsrsasign

Jsrsasign поддерживает набор алгоритмов, совместимых с PKCS#5:

  • PBKDF2-HMAC-SHA1
  • PBKDF2-HMAC-SHA256
  • AES-CBC
  • 3DES-EDE-CBC

Контроль параметров PBKDF2

При необходимости параметры можно задавать вручную через низкоуровневые API:

const { KJUR } = require("jsrsasign");

const derivedKey = KJUR.crypto.PBKDF2.deriveKeyFromPassword(
  "password",
  "randomSalt",
  10000,
  32,
  "SHA-256"
);

Параметры:

  • 10000 — количество итераций
  • 32 — длина ключа в байтах
  • SHA-256 — HMAC функция

Совместимость с OpenSSL

Jsrsasign создаёт PKCS#5-совместимые структуры, которые можно использовать в OpenSSL:

openssl rsa -in key.pem -out decrypted.pem

И наоборот — ключи OpenSSL могут быть прочитаны в Jsrsasign.


Типичные ошибки при работе с PKCS#5

Неверный пароль

Частая причина ошибок:

  • неправильная кодировка строки
  • лишние пробелы
  • несовпадение алгоритма

Несовместимый формат

Некоторые ключи используют:

  • PKCS#1 вместо PKCS#8
  • устаревшие DES-алгоритмы

Jsrsasign может требовать явного указания формата.

Слабые параметры PBKDF2

  • маленькое число итераций снижает безопасность
  • рекомендуется минимум 10000+

Практическая схема использования в приложениях

PKCS#5 в Jsrsasign обычно применяется в следующих сценариях:

  • хранение приватных ключей в браузере
  • защищённый экспорт ключей
  • клиентское шифрование перед отправкой на сервер
  • локальные криптографические приложения

Формирование безопасного ключевого контейнера

Типичная структура:

  1. Генерация RSA/EC ключа
  2. Выбор сильного пароля
  3. PBKDF2 с высокой итерацией
  4. AES-256-CBC шифрование
  5. Сохранение PEM

Работа с несколькими алгоритмами шифрования

Jsrsasign позволяет гибко выбирать алгоритм:

KEYUTIL.getPEM(prvKey, "PKCS5PRV", password, "AES256");

Возможные значения:

  • “AES128”
  • “AES192”
  • “AES256”
  • “DES3”

Внутренние структуры PKCS#5/PKCS#8

EncryptedPrivateKeyInfo включает:

  • encryptionAlgorithm
  • salt
  • iterationCount
  • encryptedData

Эта структура стандартизирована ASN.1, что обеспечивает межплатформенную совместимость.


Повышение криптографической стойкости

Рекомендации при использовании PKCS#5 в Jsrsasign:

  • использовать PBKDF2 с SHA-256 или выше
  • увеличивать число итераций при современных CPU
  • избегать DES и MD5
  • применять AES-256-CBC

Типовой цикл работы с защищённым ключом

  1. Генерация ключа
  2. Шифрование PKCS#5
  3. Сохранение PEM
  4. Загрузка PEM
  5. Дешифрование через пароль
  6. Использование приватного ключа

Особенности реализации Jsrsasign

  • полностью JavaScript-реализация без нативных зависимостей
  • совместимость с ASN.1 структурами OpenSSL
  • поддержка как PKCS#5 v1, так и v2
  • интеграция с RSA/EC ключами через KEYUTIL