Latin1 и работа с однобайтовыми кодировками

В криптографических и низкоуровневых задачах в JavaScript часто возникает необходимость работать не только с текстом в UTF-8, но и с «сырыми» байтовыми данными. Именно здесь в CryptoJS становится важной поддержка Latin1, представляющей собой однобайтовую кодировку, где каждый символ соответствует одному байту (0–255). Это делает её удобной для представления бинарных данных без потерь и без сложной многобайтовой интерпретации.

Внутри CryptoJS основным типом для работы с данными является WordArray. Он хранит информацию не как строки JavaScript, а как массив 32-битных слов, что позволяет эффективно выполнять криптографические операции.

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

  • каждый символ = 1 байт
  • отсутствует многобайтовое преобразование
  • минимальные накладные расходы при конвертации
  • удобство для бинарных протоколов и хэшей

Latin1 в CryptoJS реализована как CryptoJS.enc.Latin1.

Основные принципы Latin1 в CryptoJS

Latin1 в CryptoJS — это не текстовая кодировка в привычном смысле, а способ интерпретации байтового массива как строки и наоборот.

Ключевая особенность:

  • строка Latin1 в Jav * aScript = последовательность байтов 0–255
  • каждый символ строки напрямую соответствует одному байту WordArray

Это делает её особенно полезной в криптографии, где важно точное побайтовое совпадение данных.

Преобразование строки в WordArray через Latin1

const wordArray = CryptoJS.enc.Latin1.parse("ABC");

Здесь происходит следующее:

  • символ A → 0x41
  • символ B → 0x42
  • символ C → 0x43

Результат — WordArray с байтовым представлением 41 42 43.

Важно: никакой UTF-8 декодировки не происходит. Байт берётся напрямую из символа.

Обратное преобразование WordArray в строку Latin1

const str = CryptoJS.enc.Latin1.stringify(wordArray);

Если WordArray содержит байты:

41 42 43

результат будет:

"ABC"

Это прямое побайтовое отображение без изменения значений.

Отличие Latin1 от UTF-8 в CryptoJS

Основная ошибка при работе с CryptoJS — путаница Latin1 и UTF-8.

UTF-8 (CryptoJS.enc.Utf8)

  • символ может занимать 1–4 байта
  • требуется декодирование
  • подходит для текста

Latin1 (CryptoJS.enc.Latin1)

  • 1 символ = 1 байт
  • нет преобразований
  • подходит для бинарных данных

Например, строка с кириллицей:

CryptoJS.enc.Utf8.parse("Привет")

и

CryptoJS.enc.Latin1.parse("Привет")

дадут совершенно разные результаты, так как Latin1 не предназначен для Unicode вне диапазона 0–255.

Работа с бинарными данными через Latin1

Latin1 часто используется как промежуточный формат при:

  • хэшировании файлов
  • обработке HMAC
  • шифровании AES
  • работе с API, возвращающими байты

Пример:

const key = CryptoJS.enc.Latin1.parse("1234567890123456");
const encrypted = CryptoJS.AES.encrypt("data", key, {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7
});

Здесь ключ интерпретируется строго как 16 байт.

Почему Latin1 важна для криптографии

Криптографические алгоритмы оперируют строго байтами, а не символами. Любое изменение интерпретации данных приводит к:

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

Latin1 гарантирует:

  • стабильное побайтовое представление
  • отсутствие преобразований Unicode
  • предсказуемость результата

Частые ошибки при использовании Latin1

Использование Latin1 для Unicode текста

Если строка содержит символы вне диапазона 0–255, данные искажаются:

CryptoJS.enc.Latin1.parse("你好")

Результат будет некорректным, так как каждый символ Unicode принудительно сжимается в один байт.

Неправильная интерпретация бинарных данных как UTF-8

Если байтовые данные интерпретировать как UTF-8, возможны ошибки декодирования и потеря информации.

Взаимодействие Latin1 с Base64

Latin1 часто используется как промежуточный слой перед кодированием Base64:

const wa = CryptoJS.enc.Latin1.parse("test");
const base64 = CryptoJS.enc.Base64.stringify(wa);

И обратно:

const wa = CryptoJS.enc.Base64.parse(base64);
const latin1 = CryptoJS.enc.Latin1.stringify(wa);

Такой подход позволяет безопасно передавать бинарные данные через текстовые каналы.

Latin1 и WordArray: внутренняя модель

WordArray хранит данные в виде:

  • массива 32-битных слов
  • длины в байтах

Latin1 выступает как адаптер между:

  • строкой JavaScript
  • бинарным представлением WordArray

Схематически:

String (Latin1)
      ↓ parse
WordArray (bytes)
      ↓ stringify
String (Latin1)

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

AES шифрование с Latin1 ключом

const key = CryptoJS.enc.Latin1.parse("secretkey1234567");

const encrypted = CryptoJS.AES.encrypt("message", key, {
    mode: CryptoJS.mode.CBC,
    iv: CryptoJS.enc.Latin1.parse("1234567890123456")
});

Здесь Latin1 обеспечивает точную длину ключа и IV.

Хэширование бинарных данных

const data = CryptoJS.enc.Latin1.parse(binaryString);
const hash = CryptoJS.SHA256(data);

Особенности хранения данных

Latin1 не выполняет:

  • нормализацию Unicode
  • трансформацию символов
  • проверку валидности текста

Она лишь отображает байты как символы диапазона 0–255.

Это делает её максимально «низкоуровневым» представлением в CryptoJS.

Когда Latin1 предпочтительнее других кодировок

Latin1 используется в случаях:

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

В отличие от UTF-8 она не добавляет слой интерпретации и не меняет структуру данных при конвертации.