Кастомная схема дополнения

Блочные алгоритмы шифрования в JavaScript-библиотеке CryptoJS работают с фиксированными размерами блоков данных. AES, TripleDES и другие алгоритмы принимают входные данные строго кратные размеру блока (например, 16 байт для AES). Любое отклонение от этого требования приводит к невозможности корректного шифрования.

Для устранения этой проблемы применяется дополнение (padding) — механизм, который приводит длину входного сообщения к необходимому размеру.

При шифровании данных текст разбивается на блоки фиксированной длины. Если последний блок оказывается неполным, его необходимо дополнить байтами до требуемого размера.

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

Дополнение решает две задачи:

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

В CryptoJS дополнение выполняется автоматически при вызове encrypt, если явно не указано иное.

Стандартные схемы дополнения в CryptoJS

Библиотека предоставляет несколько встроенных реализаций padding-алгоритмов, реализованных в пространстве CryptoJS.pad.

PKCS7

Наиболее распространённая схема. В конец добавляется N байт, каждый из которых равен значению N.

Пример:

Исходные данные:

"HELLO"

Размер блока: 8 байт Длина строки: 5 байт Не хватает: 3 байта

Результат:

HELLO\x03\x03\x03

PKCS7 используется по умолчанию в AES:

const encrypted = CryptoJS.AES.encrypt("Hello world", "secret key");
// padding: CryptoJS.pad.Pkcs7 применяется автоматически

Zero Padding

Дополнение нулевыми байтами. Простой, но менее безопасный метод, поскольку невозможно отличить реальные нули от добавленных.

const encrypted = CryptoJS.AES.encrypt("Hello", "key", {
    padding: CryptoJS.pad.ZeroPadding
});

Особенность:

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

ISO10126

Дополнение случайными байтами, последний байт содержит длину дополнения.

Пример:

HELLO + random + \x03

Используется реже, но повышает устойчивость к анализу структуры данных.

Архитектура padding в CryptoJS

Внутри CryptoJS padding реализован как объект с двумя методами:

  • pad(data, blockSize)
  • unpad(data)

При шифровании вызывается pad, при расшифровании — unpad.

Упрощённая структура:

CryptoJS.pad.Pkcs7 = {
    pad: function (data, blockSize) {
        // добавление байтов
    },
    unpad: function (data) {
        // удаление байтов
    }
};

Библиотека ожидает, что padding изменяет объект WordArray, используемый внутри CryptoJS для хранения бинарных данных.

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

CryptoJS позволяет полностью заменить механизм padding, что полезно в следующих случаях:

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

Кастомная схема должна реализовывать два метода: pad и unpad.

Принцип реализации кастомного padding

Основная идея — контроль добавляемых байтов.

Пример простой схемы, где добавляется фиксированный байт 0x80, а затем нули:

const CustomPadding = {
    pad: function (data, blockSize) {
        const blockSizeBytes = blockSize * 4;

        const paddingBytes = blockSizeBytes - (data.sigBytes % blockSizeBytes);

        const paddingWord = (0x80 << 24);

        data.concat(CryptoJS.lib.WordArray.create([paddingWord]));

        for (let i = 1; i < paddingBytes; i++) {
            data.concat(CryptoJS.lib.WordArray.create([0x00000000]));
        }
    },

    unpad: function (data) {
        const words = data.words;
        let i = data.sigBytes - 1;

        while (i >= 0) {
            const byte = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;

            if (byte === 0x80) {
                break;
            }

            i--;
        }

        data.sigBytes = i;
    }
};

Использование кастомного padding в шифровании

После определения схемы она передаётся через параметр padding:

const encrypted = CryptoJS.AES.encrypt("Sensitive data", "secret key", {
    padding: CustomPadding
});

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

const decrypted = CryptoJS.AES.decrypt(encrypted, "secret key", {
    padding: CustomPadding
});

Несовпадение padding на этапах шифрования и дешифрования приводит к повреждению данных.

Регистрация собственной схемы в пространстве CryptoJS

Для более удобного использования можно встроить padding в пространство CryptoJS.pad:

CryptoJS.pad.Custom = CustomPadding;

После этого использование становится аналогичным стандартным схемам:

const encrypted = CryptoJS.AES.encrypt("Data", "key", {
    padding: CryptoJS.pad.Custom
});

Пример нестандартного алгоритма дополнения

Иногда требуется добавить длину сообщения в начало блока дополнения.

Пример реализации:

const LengthPrefixPadding = {
    pad: function (data, blockSize) {
        const len = data.sigBytes;

        data.concat(CryptoJS.lib.WordArray.create([len << 24]));

        const blockSizeBytes = blockSize * 4;
        const padding = blockSizeBytes - (data.sigBytes % blockSizeBytes);

        for (let i = 0; i < padding; i++) {
            data.concat(CryptoJS.lib.WordArray.create([0x00000000]));
        }
    },

    unpad: function (data) {
        const words = data.words;

        const lengthByte = words[0] >>> 24;

        data.sigBytes = lengthByte;
    }
};

Такая схема может использоваться в протоколах, где длина сообщения является частью структуры данных.

Работа с WordArray и побитовыми операциями

CryptoJS хранит данные в формате 32-битных слов. Каждый элемент массива words содержит 4 байта.

При реализации padding важно учитывать:

  • порядок байтов (big-endian)
  • маски побитового сдвига
  • корректное обновление sigBytes

Ошибки в этих операциях приводят к невозможности расшифрования.

Совместимость и ограничения кастомных схем

Использование нестандартного padding накладывает ряд ограничений:

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

Стандартные схемы предпочтительнее при обмене данными между разными платформами.

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