Кодек base64: стандартный и URL-safe вариант

Кодирование base64 в SJCL реализовано как отдельный модуль кодеков, работающий поверх внутреннего представления данных библиотеки — bitArray. Это принципиально важно: SJCL не оперирует байтами или строками напрямую, а использует побитовый массив фиксированной структуры, что позволяет унифицировать криптографические операции и устранить неоднозначности, связанные с кодировками JavaScript-строк.

Стандарт base64 предназначен для преобразования бинарных данных в текстовый формат, удобный для передачи по текстовым протоколам. Он использует алфавит из 64 символов:

A–Z, a–z, 0–9, +, /

Каждые 3 байта (24 бита) преобразуются в 4 символа по 6 бит.

SJCL работает не с байтами, а с массивом 32-битных слов, где каждый элемент содержит 32 бита данных. Поэтому перед кодированием происходит интерпретация bitArray как последовательности бит без привязки к байтовой границе.


Стандартный base64 в SJCL

Реализация стандартного base64 находится в sjcl.codec.base64. Основные методы:

  • sjcl.codec.base64.fromBits(arrBit) — кодирование
  • sjcl.codec.base64.toBits(str) — декодирование

Кодирование в base64

var sjcl = require('sjcl');

var bits = sjcl.hash.sha256.hash("hello");
var encoded = sjcl.codec.base64.fromBits(bits);

На выходе получается строка base64, пригодная для хранения или передачи.

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

  • нормализация входного bitArray
  • группировка бит по 6
  • сопоставление индексов алфавита base64
  • добавление padding =, если длина не кратна 24 битам

Декодирование base64

var decodedBits = sjcl.codec.base64.toBits(encoded);

Алгоритм обратный:

  • удаление символов padding =
  • преобразование символов в 6-битные значения
  • сборка обратно в 32-битные слова bitArray

Особенности стандартного base64 в SJCL

1. Padding (=)

SJCL сохраняет классическое поведение RFC 4648:

  • если входные данные не кратны 24 битам — добавляются =
  • 1 или 2 символа padding выравнивают длину

Это важно при совместимости с внешними API, особенно при взаимодействии с серверными языками (Java, Python, Go).


2. Алфавит

Используется классический набор:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

Это означает, что результат может содержать символы + и /, которые не всегда безопасны для URL или файловых имен.


3. Работа с bitArray

SJCL требует строгого соблюдения формата входа:

  • каждый элемент массива — 32-битное слово
  • последние биты могут быть не выровнены по байтам
  • библиотека хранит длину массива в отдельном поле

URL-safe base64 в SJCL

Для сценариев, где base64 должен использоваться в URL, cookie, токенах или идентификаторах, применяется модифицированный вариант — base64url.

В SJCL он реализован как:

  • sjcl.codec.base64url.fromBits
  • sjcl.codec.base64url.toBits

Отличия base64url от стандартного base64

Основные изменения касаются алфавита:

Стандарт base64 base64url
+ -
/ _
= padding обычно убирается

Кодирование в base64url

var bits = sjcl.hash.sha256.hash("hello");
var urlSafe = sjcl.codec.base64url.fromBits(bits);

Результат:

  • не содержит + и /
  • безопасен для URL без дополнительного escaping
  • padding может отсутствовать

Декодирование base64url

var restoredBits = sjcl.codec.base64url.toBits(urlSafe);

Алгоритм декодирования включает:

  • обратную замену - → + и _ → /
  • восстановление padding при необходимости
  • затем стандартный base64 decode pipeline

Удаление padding в base64url

SJCL придерживается практики, при которой = обычно удаляется:

encoded = encoded.replace(/=/g, "");

Это уменьшает размер строки и делает её удобной для использования в URL-параметрах:

https://example.com/?token=QmFzZTY0X1Rva2Vu

Сравнение поведения base64 и base64url в SJCL

Стандартный base64:

  • используется для совместимости
  • включает +, /, =
  • подходит для email, MIME, бинарных протоколов

base64url:

  • используется для web-токенов (JWT-подобные схемы)
  • безопасен для URL без encodeURIComponent
  • исключает неоднозначные символы

Внутренние детали реализации SJCL

SJCL не хранит отдельные реализации алгоритмов кодирования — вместо этого оба кодека построены на общей базе функций:

  • преобразование bitArray → массив 6-битных индексов
  • lookup таблица алфавита
  • побитовые операции с mask и shift

Ключевая идея — минимизация зависимостей от строковой кодировки JavaScript.


Обработка крайних случаев

1. Пустой массив

sjcl.codec.base64.fromBits([])

Результат: пустая строка


2. Невыровненные биты

SJCL корректно обрабатывает случаи, когда длина бит не кратна 8, автоматически обрезая лишние биты при кодировании.


3. Ошибки декодирования

При некорректных символах:

  • toBits может выбросить исключение
  • либо вернуть частично восстановленные данные (зависит от версии SJCL)

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

base64 и base64url в SJCL чаще всего применяются в связке с:

  • хешами (SHA-256, SHA-512)
  • HMAC
  • шифрованием AES
  • генерацией токенов

Пример HMAC + base64url:

var key = sjcl.codec.utf8String.toBits("secret");
var data = sjcl.codec.utf8String.toBits("message");

var mac = sjcl.misc.hmac(key, sjcl.hash.sha256);
var result = mac.encrypt(data);

var token = sjcl.codec.base64url.fromBits(result);

Совместимость с внешними системами

При интеграции SJCL с backend важно учитывать:

  • JavaScript base64url часто несовместим с RFC строго без padding
  • некоторые серверы требуют восстановление = до длины кратной 4
  • Python base64.urlsafe_b64decode может требовать нормализации строки

Типичный pipeline согласования:

SJCL base64url → HTTP → backend decode → restore padding → decode

Типичные ошибки при работе с base64 в SJCL

1. Попытка кодировать строку напрямую

Неверно:

sjcl.codec.base64.fromBits("text");

Правильно:

var bits = sjcl.codec.utf8String.toBits("text");
sjcl.codec.base64.fromBits(bits);

2. Игнорирование UTF-8 преобразования

SJCL не предполагает автоматическую работу со строками JavaScript, поэтому:

  • строки должны быть явно конвертированы в bitArray
  • иначе результат будет некорректным при non-ASCII символах

3. Смешивание base64 и base64url

Результаты этих кодеков не взаимозаменяемы без преобразования алфавита и padding.


Влияние на безопасность

Сам по себе base64 не является механизмом защиты данных:

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

В контексте SJCL он используется как транспортный слой поверх криптографических операций.


Оптимизационные особенности

SJCL минимизирует overhead:

  • работа через массивы чисел быстрее строковых операций
  • отсутствие промежуточных преобразований в байтовые буферы
  • предвычисленные таблицы алфавитов ускоряют encode/decode

Закономерности выбора кодека

Внутри реальных приложений на SJCL выбор обычно следующий:

  • base64 → совместимость с legacy API, email, бинарные протоколы
  • base64url → web-токены, URL, браузерные приложения, OAuth-подобные схемы

Разделение на два кодека позволяет избежать постоянного ручного escaping и нормализации строк.