Перекодирование между форматами

В криптографических операциях JavaScript-библиотеки Jsrsasign данные редко существуют в одном универсальном виде. Одна и та же сущность — ключ, сертификат, подпись — может быть представлена в нескольких форматах, каждый из которых решает свою задачу: хранение, передача, совместимость с OpenSSL, работа в браузере или на сервере.

На практике используются три базовых уровня представления:

  • бинарный (DER)
  • текстовый контейнер (PEM)
  • промежуточные строковые формы (HEX, Base64)

Понимание перекодирования между ними является ключом к работе с библиотекой.


DER как исходная бинарная форма

DER (Distinguished Encoding Rules) представляет собой строгую бинарную сериализацию ASN.1-структур. Именно в этом виде хранятся X.509 сертификаты, приватные ключи и подписи внутри большинства криптографических систем.

В Jsrsasign DER почти никогда не используется напрямую как объект JavaScript. Вместо этого он представлен как:

  • HEX-строка (чаще всего)
  • ArrayBuffer / Uint8Array (в браузерных сценариях)

Типичный пример DER в HEX-форме:

308203223082020aa003020102020900...

Работа с DER требует понимания, что это не текст, а строго структурированный бинарный поток, где каждый байт имеет смысл.


HEX-представление как промежуточный слой

HEX (шестнадцатеричная строка) является основным рабочим форматом в Jsrsasign.

Почти все низкоуровневые функции библиотеки оперируют именно HEX:

  • ASN.1 парсинг
  • разбор сертификатов
  • извлечение ключей
  • криптографические вычисления

Преобразование строки в HEX

В Jsrsasign используется:

KJUR.crypto.Util.strtohex("test")

Результат — HEX-представление строки.

Обратное преобразование

KJUR.crypto.Util.hextoutf8("74657374")

HEX является связующим звеном между человекочитаемыми форматами и бинарной криптографией.


Base64 как транспортный формат

Base64 используется для безопасной передачи бинарных данных через текстовые каналы: JSON, HTTP, email.

В Jsrsasign Base64 почти всегда связан с PEM-форматами.

Кодирование HEX → Base64

KJUR.crypto.Util.hextob64("74657374")

Декодирование Base64 → HEX

KJUR.crypto.Util.b64tohex("dGVzdA==")

Base64 не содержит структурной информации — он лишь упаковывает байты в ASCII.


PEM как контейнер криптографических объектов

PEM (Privacy Enhanced Mail) — это текстовый формат, который содержит Base64-данные, обрамлённые заголовками:

-----BEGIN CERTIFICATE-----
MIIC...
-----END CERTIFICATE-----

В Jsrsasign PEM является стандартным способом обмена:

  • сертификатами
  • приватными ключами
  • публичными ключами

Извлечение HEX из PEM

var pem = "-----BEGIN CERTIFICATE-----\nMIIC...\n-----END CERTIFICATE-----";
var hex = KJUR.asn1.x509.X509.pemToHex(pem);

Преобразование HEX → PEM

var pem = KJUR.asn1.ASN1Util.getPEMStringFromHex(hex, "CERTIFICATE");

PEM всегда содержит метаинформацию о типе объекта, что делает его более удобным для инфраструктурных задач.


Работа с сертификатами: цепочка перекодирования

Типичный процесс обработки сертификата в Jsrsasign включает несколько стадий:

PEM → Base64 → HEX → ASN.1 структура

Пример извлечения данных:

var x = new X509();
x.readCertPEM(pem);

Внутри происходит:

  • удаление заголовков PEM
  • декодирование Base64
  • получение DER (HEX)
  • парсинг ASN.1 структуры

ASN.1 как структурный слой

ASN.1 является фундаментом большинства криптографических структур.

Jsrsasign предоставляет:

  • ASN1HEX — работа с ASN.1 через HEX
  • ASN1Object — представление дерева

Извлечение элемента из DER

var seq = ASN1HEX.getVbyList(hex, 0, ["2", "3"]);

Здесь происходит навигация по ASN.1 дереву без полного парсинга в объекты.


Перекодирование ключей

Приватные и публичные ключи в Jsrsasign чаще всего представлены в PKCS#1 или PKCS#8 формате.

PEM → ключевой объект

var key = KEYUTIL.getKey(pem);

Внутри выполняется:

  • распаковка PEM
  • преобразование Base64 → HEX
  • ASN.1 разбор
  • формирование JavaScript-объекта ключа

Обратное преобразование ключа в PEM

var pem = KEYUTIL.getPEM(key);

Конвертация строковых данных

Помимо криптографических структур, Jsrsasign активно работает с обычными строками.

UTF-8 → HEX

KJUR.crypto.Util.utf8tohex("Пример")

HEX → UTF-8

KJUR.crypto.Util.hextoutf8(hex)

Это используется при:

  • формировании подписываемых сообщений
  • обработке хэшей
  • подготовке данных для RSA/ECDSA

Перекодирование хэшей

Хэш-функции возвращают бинарный результат, который необходимо преобразовывать.

SHA-256 → HEX

KJUR.crypto.Util.sha256("data")

Результат уже является HEX-строкой.

HEX → Base64

KJUR.crypto.Util.hextob64(hashHex)

Такой подход используется при формировании JWT и цифровых подписей.


JWT и перекодирование форматов

JWT (JSON Web Token) является одним из наиболее частых сценариев использования Jsrsasign.

Структура:

Base64Url(Header).Base64Url(Payload).Base64Url(Signature)

Отличие Base64Url

Base64Url — модификация Base64:

  • + заменяется на -
  • / заменяется на _
  • отсутствует padding =

Jsrsasign выполняет преобразования:

KJUR.crypto.Util.b64tohex
KJUR.crypto.Util.stob64u

Base64Url ↔︎ HEX ↔︎ JSON цепочка

При работе с JWT происходит несколько перекодировок:

JSON → UTF-8 → Base64Url → подпись → HEX

Пример:

var sHeader = JSON.stringify({alg: "RS256", typ: "JWT"});
var sPayload = JSON.stringify({sub: "123"});

Далее:

  • JSON → UTF-8
  • UTF-8 → Base64Url
  • подпись создаётся из HEX-данных

Криптографическая подпись и форматы

Процесс подписи в Jsrsasign включает обязательное преобразование:

  1. исходные данные (строка/JSON)
  2. HEX представление
  3. хэширование
  4. подпись (RSA/ECDSA)
  5. преобразование результата в Base64/Base64Url

Пример:

var sig = new KJUR.crypto.Signature({"alg": "SHA256withRSA"});
sig.init(privateKey);
sig.updateString(data);
var signatureHex = sig.sign();

Здесь результат — HEX, который часто дополнительно перекодируется:

KJUR.crypto.Util.hextob64(signatureHex)

Обратимость преобразований и ограничения

Не все преобразования являются полностью обратимыми без контекста:

  • HEX ↔︎ Base64 — обратимы полностью
  • PEM → HEX — обратимо, но зависит от типа объекта
  • ASN.1 → объект — может терять низкоуровневую структуру
  • JSON → криптографическая подпись — необратимо без ключа

Поэтому при проектировании криптографических систем важно учитывать уровень абстракции, на котором происходит перекодирование.


Типовые цепочки преобразований в Jsrsasign

Сертификат

PEM → Base64 → DER(HEX) → ASN.1 структура → поля сертификата

Подпись

String → UTF-8 → HEX → Hash → HEX → Base64 → JWT

Ключ

PEM → Base64 → DER → ASN.1 → Key Object → PEM/JSON

Ошибки при перекодировании

На практике наиболее частые проблемы связаны с:

  • двойным Base64-декодированием
  • попыткой интерпретации HEX как UTF-8
  • потерей заголовков PEM
  • неправильным выбором Base64 vs Base64Url
  • некорректной обработкой padding

Jsrsasign требует строгого соблюдения формата на каждом этапе, так как автоматической нормализации данных нет.


Внутренние утилиты Jsrsasign

Основные функции, используемые для перекодирования:

  • KJUR.crypto.Util.hextob64
  • KJUR.crypto.Util.b64tohex
  • KJUR.crypto.Util.utf8tohex
  • KJUR.crypto.Util.hextoutf8
  • ASN1HEX (работа с ASN.1 в HEX)
  • KEYUTIL (конвертация ключей)
  • X509 (разбор сертификатов)

Эти инструменты образуют базовый слой трансформации данных внутри библиотеки.


Практическая модель представлений данных

Любая криптографическая сущность в Jsrsasign может быть представлена как:

  • человекочитаемый текст (UTF-8)
  • транспортный формат (Base64 / PEM)
  • машинный формат (HEX / DER)
  • структурированный формат (ASN.1 / Object)

Переход между ними не является побочным процессом — это основа всей архитектуры библиотеки.