Шифрование данных открытым ключом

Асимметричное шифрование (шифрование с открытым ключом) основано на использовании пары ключей: публичного (public key) и приватного (private key). Публичный ключ используется для шифрования данных, а приватный — для их расшифровки. Такая модель решает проблему безопасной передачи ключей, характерную для симметричных алгоритмов.

Основные свойства:

  • Публичный ключ может свободно распространяться
  • Приватный ключ должен храниться в секрете
  • Данные, зашифрованные публичным ключом, могут быть расшифрованы только соответствующим приватным ключом
  • Обратная операция (подпись) использует приватный ключ для создания подписи, а публичный — для проверки

Наиболее распространённый алгоритм — RSA, который поддерживается библиотекой Jsrsasign.


Библиотека Jsrsasign и её возможности

Jsrsasign — это JavaScript-библиотека, реализующая криптографические операции:

  • RSA, ECDSA
  • Генерация и обработка ключей
  • Шифрование и дешифрование
  • Цифровые подписи
  • Работа с X.509 сертификатами

Для шифрования с открытым ключом в Jsrsasign используется класс RSAKey.


Форматы ключей

Jsrsasign поддерживает различные форматы представления ключей:

  • PEM (Base64 + заголовки)
  • DER (бинарный формат)
  • PKCS#1 и PKCS#8

Пример публичного ключа в PEM:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqh...
-----END PUBLIC KEY-----

Приватный ключ:

-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBg...
-----END PRIVATE KEY-----

Импорт публичного ключа

Для работы с ключом его необходимо загрузить в объект RSAKey.

const rsa = new KJUR.crypto.RSAKey();
rsa.readCertPEM(pubKeyPEM);

Альтернативный способ:

rsa.readPKCS8PubKeyHex(pubKeyHex);

Шифрование данных

Шифрование производится с использованием публичного ключа.

const plaintext = "Секретное сообщение";
const encryptedHex = rsa.encrypt(plaintext);

Результат возвращается в шестнадцатеричном формате (hex). Для удобства передачи его часто кодируют в Base64:

const encryptedBase64 = hextob64(encryptedHex);

Особенности RSA-шифрования

RSA не предназначен для шифрования больших объёмов данных напрямую. Ограничения:

  • Размер данных должен быть меньше длины ключа (с учётом padding)
  • Обычно используется для шифрования симметричных ключей (гибридное шифрование)

Пример ограничения:

  • RSA 2048 бит → максимум ~245 байт (при использовании PKCS#1 v1.5)

Padding (заполнение)

Padding — это механизм добавления случайных данных перед шифрованием для повышения безопасности.

Jsrsasign поддерживает:

  • PKCS#1 v1.5 (по умолчанию)
  • OAEP (более безопасный вариант)

Пример использования OAEP:

const encrypted = rsa.encryptOAEP("данные", "sha256");

Параметры:

  • строка данных
  • алгоритм хеширования (sha1, sha256 и др.)

Расшифрование данных

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

const rsa = new KJUR.crypto.RSAKey();
rsa.readPKCS8PrvKeyHex(prvKeyHex);

const decrypted = rsa.decrypt(encryptedHex);

Если использовался Base64:

const encryptedHex = b64tohex(encryptedBase64);
const decrypted = rsa.decrypt(encryptedHex);

Генерация ключевой пары

Jsrsasign позволяет генерировать ключи:

const keypair = KEYUTIL.generateKeypair("RSA", 2048);

const pubKeyObj = keypair.pubKeyObj;
const prvKeyObj = keypair.prvKeyObj;

Экспорт в PEM:

const pubPEM = KEYUTIL.getPEM(pubKeyObj);
const prvPEM = KEYUTIL.getPEM(prvKeyObj, "PKCS8PRV");

Гибридное шифрование

Практическое применение RSA — защита симметричных ключей:

  1. Генерируется случайный AES-ключ
  2. Данные шифруются AES
  3. AES-ключ шифруется RSA

Это позволяет:

  • Обрабатывать большие объёмы данных
  • Сохранять производительность
  • Использовать преимущества асимметричной криптографии

Работа с UTF-8 и кодировками

Перед шифрованием важно учитывать кодировку:

const utf8Hex = utf8tohex("Пример текста");
const encrypted = rsa.encrypt(utf8Hex);

После расшифровки:

const decryptedUtf8 = hextoutf8(decryptedHex);

Ошибки и ограничения

Типичные проблемы:

1. Переполнение блока

  • Ошибка при попытке зашифровать слишком длинную строку

2. Несовпадение padding

  • Нельзя расшифровать OAEP-данные с использованием PKCS#1

3. Неверный формат ключа

  • PEM должен быть корректно отформатирован

4. Проблемы с кодировкой

  • Особенно при работе с Unicode

Безопасность

Ключевые рекомендации:

  • Использовать RSA не менее 2048 бит
  • Предпочитать OAEP вместо PKCS#1 v1.5
  • Не шифровать большие данные напрямую
  • Хранить приватные ключи в защищённой среде
  • Использовать проверенные источники ключей

Пример полного цикла

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

// Экспорт
const pubPEM = KEYUTIL.getPEM(kp.pubKeyObj);
const prvPEM = KEYUTIL.getPEM(kp.prvKeyObj, "PKCS8PRV");

// Импорт
const rsaPub = new KJUR.crypto.RSAKey();
rsaPub.readCertPEM(pubPEM);

const rsaPrv = new KJUR.crypto.RSAKey();
rsaPrv.readPKCS8PrvKeyHex(KEYUTIL.getHexFromPEM(prvPEM));

// Шифрование
const encrypted = rsaPub.encrypt("hello");

// Расшифрование
const decrypted = rsaPrv.decrypt(encrypted);

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

  • Передача конфиденциальных данных через API
  • Шифрование токенов авторизации
  • Защита конфигурационных файлов
  • Обмен ключами в протоколах безопасности
  • Реализация защищённых каналов связи

Производительность

RSA значительно медленнее симметричных алгоритмов:

  • Генерация ключей — ресурсоёмкая операция
  • Шифрование — относительно быстро
  • Расшифрование — медленнее шифрования

Рекомендуется:

  • Минимизировать количество операций RSA
  • Использовать кэширование ключей
  • Применять гибридные схемы

Сравнение с Web Crypto API

Jsrsasign:

  • Работает везде (включая старые браузеры)
  • Не требует HTTPS
  • Прост в использовании

Web Crypto API:

  • Быстрее (нативная реализация)
  • Более безопасен (ограничения среды)
  • Асинхронный интерфейс

Выбор зависит от требований проекта и среды выполнения.


Итоговая структура процесса

  1. Получение публичного ключа
  2. Шифрование данных
  3. Передача зашифрованной информации
  4. Расшифрование приватным ключом
  5. Обработка результата

Такая схема обеспечивает конфиденциальность и защищённость передачи данных в распределённых системах.