Тестирование граничных случаев и ошибочных входов

При тестировании криптографических операций в SJCL критически важно исходить из того, что любая функция библиотеки работает не с «идеальными» данными, а с тем, что реально приходит из пользовательского ввода, сетевых запросов, хранилищ или сторонних API. Большая часть уязвимостей в криптосистемах на JavaScript проявляется не в алгоритмах, а в обработке некорректных или пограничных входных значений.

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

  • строки (обычно UTF-8)
  • битовые массивы (sjcl.bitArray)
  • числа (для параметров, например, итераций PBKDF2)
  • JSON-структуры (высокоуровневый API encrypt/decrypt)

Ключевая проблема тестирования заключается в том, что библиотека допускает автоматические преобразования типов. Например, строка может быть неявно преобразована в bitArray, а некорректные структуры иногда приводят не к ошибке, а к «тихому» искажению результата.

Пустые и минимальные значения

Одни из наиболее критичных случаев — это пустые и минимально допустимые значения.

Пустая строка

sjcl.encrypt("password", "");

Ожидаемое поведение зависит от контекста, но важно проверять:

  • генерируется ли корректный ciphertext
  • не происходит ли деградация IV или salt
  • возможно ли восстановление данных без ошибок

Проблема в том, что пустая строка — валидный UTF-8 ввод, и система не должна трактовать её как ошибку.

Null и undefined

sjcl.encrypt("password", null);
sjcl.encrypt("password", undefined);

SJCL не всегда явно валидирует такие значения. В зависимости от версии:

  • может произойти преобразование в строку "null" или "undefined"
  • может возникнуть ошибка сериализации
  • возможна неконсистентность при decrypt

Особое внимание требуется при работе с обёртками над SJCL, где типизация ослаблена.

Некорректные типы данных

SJCL часто используется в динамическом окружении, поэтому критично тестировать поведение при подмене типов.

Числа вместо строк

sjcl.encrypt("password", 12345);

Возможные сценарии:

  • преобразование в строку "12345"
  • исключение в процессе конвертации в bitArray
  • неожиданный результат дешифровки

Объекты вместо строк

sjcl.encrypt("password", { data: "test" });

Здесь почти всегда происходит:

  • toString()"[object Object]"
  • потеря исходной структуры
  • потенциальная утечка логики сериализации

Такие случаи критичны при интеграции с API, где данные приходят в JSON.

Граничные значения длины

Очень короткие данные

sjcl.encrypt("password", "a");

Проверяется:

  • корректность padding
  • стабильность CBC/CTR режимов
  • отсутствие утечек структуры при малом объёме

Очень длинные строки

const huge = "a".repeat(10_000_000);
sjcl.encrypt("password", huge);

Важные аспекты:

  • использование памяти (SJCL работает в JS heap без стриминга)
  • возможные блокировки event loop
  • деградация производительности PBKDF2 и AES-раундов

Особенно важно тестировать браузерные окружения, где long task может блокировать UI.

Ошибочные ключи и пароли

Пустой пароль

sjcl.encrypt("", "data");

Некоторые конфигурации допускают слабые ключи. Проверяется:

  • генерация key через KDF
  • устойчивость salt
  • отсутствие совпадений ciphertext при повторном шифровании

Unicode и нестандартные символы

sjcl.encrypt("пароль?", "данные");

Важно проверить:

  • корректную обработку UTF-16 surrogate pairs
  • отсутствие ошибок при PBKDF2
  • стабильность при дешифровке

Особую опасность представляют символы вне BMP (эмодзи, редкие иероглифы).

Нарушение структуры BitArray

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

Пустые массивы

sjcl.bitArray.bitLength([]);

Проверяется:

  • возврат 0 без исключений
  • отсутствие NaN в вычислениях

Неправильная структура массива

sjcl.bitArray.bitLength([123, "invalid", null]);

Ожидаемые проблемы:

  • некорректная интерпретация 32-битных слов
  • падение в побитовых операциях
  • потенциальная компрометация результата шифрования

Ошибки при работе с JSON API

Высокоуровневые функции sjcl.encrypt и sjcl.decrypt часто используются с JSON-обёрткой.

Некорректный JSON при decrypt

sjcl.decrypt("password", "{bad json}");

Проверяется:

  • корректность обработки parse error
  • отсутствие утечки внутренних ошибок
  • безопасное завершение функции

Отсутствие обязательных полей

sjcl.decrypt("password", JSON.stringify({}));

Возможные проблемы:

  • отсутствует iv
  • отсутствует salt
  • отсутствует ct (ciphertext)

Библиотека должна явно сигнализировать об ошибке, а не возвращать undefined или некорректный результат.

Повторное использование IV и salt

Хотя SJCL обычно генерирует IV автоматически, тестирование требует проверки сценариев ручной подстановки:

const data = sjcl.encrypt("password", "text");
const parsed = JSON.parse(data);
parsed.iv = parsed.iv;

Ключевые проверки:

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

Ошибки PBKDF2 параметров

sjcl.misc.pbkdf2("password", "salt", -1);

Граничные значения:

  • 0 итераций
  • отрицательные числа
  • слишком большие значения (например, 10^9)

Проблемы:

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

Повреждённые ciphertext

Усечение строки

const encrypted = sjcl.encrypt("password", "data");
sjcl.decrypt("password", encrypted.slice(0, -10));

Проверяется:

  • корректное выбрасывание исключения
  • отсутствие частичного декодирования
  • защита от padding oracle поведения

Модификация символов

let corrupted = encrypted.replace(/a/g, "b");
sjcl.decrypt("password", corrupted);

Ожидается:

  • полный отказ дешифровки
  • отсутствие «частичного успеха»

Работа с случайностью

SJCL зависит от генератора случайных чисел (sjcl.random).

Недостаток энтропии

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

  • поведение при cold start
  • генерацию ключей до накопления энтропии
  • fallback-режимы

Некорректные сценарии могут приводить к:

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

Исключения и нестандартное поведение

SJCL не всегда выбрасывает исключения в классическом смысле. Часто ошибки проявляются как:

  • undefined результат
  • некорректный JSON
  • silent failure при дешифровке

Поэтому тестирование должно включать:

  • явную проверку return value
  • контроль структуры результата
  • сравнение исходных и восстановленных данных

Общая стратегия тестирования граничных случаев

На практике тестирование SJCL требует сочетания:

  • property-based testing (генерация случайных входов)
  • fuzzing (искажение ciphertext и ключей)
  • unit-тестов на типовые сценарии
  • стресс-тестирования длинных строк и больших массивов

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